From 5a2af3e5f22c8f5e31a4db1ed5aa9d0f7d9d2736 Mon Sep 17 00:00:00 2001 From: Erik Rasmussen Date: Mon, 4 Dec 2017 10:53:11 +0100 Subject: [PATCH] Mutators!! --- .flowconfig | 1 + README.md | 153 +++++++++++--------- package-lock.json | 324 +++++++++++++++++------------------------- package.json | 22 +-- src/Field.test.js | 19 ++- src/FormSpy.test.js | 2 + src/ReactFinalForm.js | 5 + src/index.js.flow | 2 + 8 files changed, 249 insertions(+), 279 deletions(-) diff --git a/.flowconfig b/.flowconfig index 61e4e1f6..70aeb747 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,4 +1,5 @@ [ignore] +dist [include] diff --git a/README.md b/README.md index 92e96eef..9e0cba73 100644 --- a/README.md +++ b/README.md @@ -97,76 +97,81 @@ const MyForm = () => ## Table of Contents + + -- [Examples](#examples) - - [Simple Example](#simple-example) - - [Synchronous Record-Level Validation](#synchronous-record-level-validation) - - [Synchronous Field-Level Validation](#synchronous-field-level-validation) - - [Asynchronous Field-Level Validation](#asynchronous-field-level-validation) - - [Hybrid Synchronous/Asynchronous Record-Level Validation](#hybrid-synchronousasynchronous-record-level-validation) - - [Submission Errors](#submission-errors) - - [Third Party Components](#third-party-components) - - [💥 Performance Optimization Through Subscriptions 💥](#-performance-optimization-through-subscriptions-) -- [Rendering](#rendering) -- [API](#api) - - [`Field : React.ComponentType`](#field--reactcomponenttypefieldprops) - - [`Form : React.ComponentType`](#form--reactcomponenttypeformprops) - - [`FormSpy : React.ComponentType`](#formspy--reactcomponenttypeformspyprops) - - [`version: string`](#version-string) -- [Types](#types) - - [`FieldProps`](#fieldprops) - - [`allowNull?: boolean`](#allownull-boolean) - - [`children?: ((props: FieldRenderProps) => React.Node) | React.Node`](#children-props-fieldrenderprops--reactnode--reactnode) - - [`component?: React.ComponentType`](#component-reactcomponenttypefieldrenderprops) - - [`name: string`](#name-string) - - [`render?: (props: FieldRenderProps) => React.Node`](#render-props-fieldrenderprops--reactnode) - - [`subscription?: FieldSubscription`](#subscription-fieldsubscription) - - [`validate?: (value: ?any, allValues: Object) => ?any`](#validate-value-any-allvalues-object--any) - - [`value?: any`](#value-any) - - [`FieldRenderProps`](#fieldrenderprops) - - [`input.name: string`](#inputname-string) - - [`input.onBlur: (?SyntheticFocusEvent<*>) => void`](#inputonblur-syntheticfocusevent--void) - - [`input.onChange: (SyntheticInputEvent<*> | any) => void`](#inputonchange-syntheticinputevent--any--void) - - [`input.onFocus: (?SyntheticFocusEvent<*>) => void`](#inputonfocus-syntheticfocusevent--void) - - [`input.value: any`](#inputvalue-any) - - [`meta.active?: boolean`](#metaactive-boolean) - - [`meta.dirty?: boolean`](#metadirty-boolean) - - [`meta.error?: any`](#metaerror-any) - - [`meta.initial?: any`](#metainitial-any) - - [`meta.invalid?: boolean`](#metainvalid-boolean) - - [`meta.pristine?: boolean`](#metapristine-boolean) - - [`meta.submitError?: any`](#metasubmiterror-any) - - [`meta.submitFailed?: boolean`](#metasubmitfailed-boolean) - - [`meta.submitSucceeded?: boolean`](#metasubmitsucceeded-boolean) - - [`meta.touched?: boolean`](#metatouched-boolean) - - [`meta.valid?: boolean`](#metavalid-boolean) - - [`meta.visited?: boolean`](#metavisited-boolean) - - [`FormProps`](#formprops) - - [`children?: ((props: FormRenderProps) => React.Node) | React.Node`](#children-props-formrenderprops--reactnode--reactnode) - - [`component?: React.ComponentType`](#component-reactcomponenttypeformrenderprops) - - [`debug?: DebugFunction`](#debug-debugfunction) - - [`initialValues?: Object`](#initialvalues-object) - - [`onSubmit: (values: Object, callback: ?(errors: ?Object) => void) => ?Object | Promise | void`](#onsubmit-values-object-callback-errors-object--void--object--promiseobject--void) - - [`render?: (props: FormRenderProps) => React.Node`](#render-props-formrenderprops--reactnode) - - [`subscription?: FormSubscription`](#subscription-formsubscription) - - [`validate?: (values: Object) => Object | Promise`](#validate-values-object--object--promiseobject) - - [`validateOnBlur?: boolean`](#validateonblur-boolean) - - [`FormRenderProps`](#formrenderprops) - - [`batch: (fn: () => void) => void)`](#batch-fn---void--void) - - [`blur: (name: string) => void`](#blur-name-string--void) - - [`change: (name: string, value: any) => void`](#change-name-string-value-any--void) - - [`focus: (name: string) => void`](#focus-name-string--void) - - [`handleSubmit: (SyntheticEvent) => void`](#handlesubmit-syntheticeventhtmlformelement--void) - - [`initialize: (values: Object) => void`](#initialize-values-object--void) - - [`reset: () => void`](#reset---void) - - [`FormSpyProps`](#formspyprops) - - [`children?: ((props: FormSpyRenderProps) => React.Node) | React.Node`](#children-props-formspyrenderprops--reactnode--reactnode) - - [`component?: React.ComponentType`](#component-reactcomponenttypeformspyrenderprops) - - [`render?: (props: FormSpyRenderProps) => React.Node`](#render-props-formspyrenderprops--reactnode) - - [`subscription?: FormSubscription`](#subscription-formsubscription-1) - - [`FormSpyRenderProps`](#formspyrenderprops) +* [Examples](#examples) + * [Simple Example](#simple-example) + * [Synchronous Record-Level Validation](#synchronous-record-level-validation) + * [Synchronous Field-Level Validation](#synchronous-field-level-validation) + * [Asynchronous Field-Level Validation](#asynchronous-field-level-validation) + * [Hybrid Synchronous/Asynchronous Record-Level Validation](#hybrid-synchronousasynchronous-record-level-validation) + * [Submission Errors](#submission-errors) + * [Third Party Components](#third-party-components) + * [💥 Performance Optimization Through Subscriptions 💥](#-performance-optimization-through-subscriptions-) +* [Rendering](#rendering) +* [API](#api) + * [`Field : React.ComponentType`](#field--reactcomponenttypefieldprops) + * [`Form : React.ComponentType`](#form--reactcomponenttypeformprops) + * [`FormSpy : React.ComponentType`](#formspy--reactcomponenttypeformspyprops) + * [`version: string`](#version-string) +* [Types](#types) + * [`FieldProps`](#fieldprops) + * [`allowNull?: boolean`](#allownull-boolean) + * [`children?: ((props: FieldRenderProps) => React.Node) | React.Node`](#children-props-fieldrenderprops--reactnode--reactnode) + * [`component?: React.ComponentType`](#component-reactcomponenttypefieldrenderprops) + * [`name: string`](#name-string) + * [`render?: (props: FieldRenderProps) => React.Node`](#render-props-fieldrenderprops--reactnode) + * [`subscription?: FieldSubscription`](#subscription-fieldsubscription) + * [`validate?: (value: ?any, allValues: Object) => ?any`](#validate-value-any-allvalues-object--any) + * [`value?: any`](#value-any) + * [`FieldRenderProps`](#fieldrenderprops) + * [`input.name: string`](#inputname-string) + * [`input.onBlur: (?SyntheticFocusEvent<*>) => void`](#inputonblur-syntheticfocusevent--void) + * [`input.onChange: (SyntheticInputEvent<*> | any) => void`](#inputonchange-syntheticinputevent--any--void) + * [`input.onFocus: (?SyntheticFocusEvent<*>) => void`](#inputonfocus-syntheticfocusevent--void) + * [`input.value: any`](#inputvalue-any) + * [`meta.active?: boolean`](#metaactive-boolean) + * [`meta.data: Object`](#metadata-object) + * [`meta.dirty?: boolean`](#metadirty-boolean) + * [`meta.error?: any`](#metaerror-any) + * [`meta.initial?: any`](#metainitial-any) + * [`meta.invalid?: boolean`](#metainvalid-boolean) + * [`meta.pristine?: boolean`](#metapristine-boolean) + * [`meta.submitError?: any`](#metasubmiterror-any) + * [`meta.submitFailed?: boolean`](#metasubmitfailed-boolean) + * [`meta.submitSucceeded?: boolean`](#metasubmitsucceeded-boolean) + * [`meta.touched?: boolean`](#metatouched-boolean) + * [`meta.valid?: boolean`](#metavalid-boolean) + * [`meta.visited?: boolean`](#metavisited-boolean) + * [`FormProps`](#formprops) + * [`children?: ((props: FormRenderProps) => React.Node) | React.Node`](#children-props-formrenderprops--reactnode--reactnode) + * [`component?: React.ComponentType`](#component-reactcomponenttypeformrenderprops) + * [`debug?: DebugFunction`](#debug-debugfunction) + * [`initialValues?: Object`](#initialvalues-object) + * [`mutators?: { [string]: Mutator }`](#mutators--string-mutator-) + * [`onSubmit: (values: Object, callback: ?(errors: ?Object) => void) => ?Object | Promise | void`](#onsubmit-values-object-callback-errors-object--void--object--promiseobject--void) + * [`render?: (props: FormRenderProps) => React.Node`](#render-props-formrenderprops--reactnode) + * [`subscription?: FormSubscription`](#subscription-formsubscription) + * [`validate?: (values: Object) => Object | Promise`](#validate-values-object--object--promiseobject) + * [`validateOnBlur?: boolean`](#validateonblur-boolean) + * [`FormRenderProps`](#formrenderprops) + * [`batch: (fn: () => void) => void)`](#batch-fn---void--void) + * [`blur: (name: string) => void`](#blur-name-string--void) + * [`change: (name: string, value: any) => void`](#change-name-string-value-any--void) + * [`focus: (name: string) => void`](#focus-name-string--void) + * [`handleSubmit: (SyntheticEvent) => void`](#handlesubmit-syntheticeventhtmlformelement--void) + * [`initialize: (values: Object) => void`](#initialize-values-object--void) + * [`mutators?: { [string]: Function }`](#mutators--string-function-) + * [`reset: () => void`](#reset---void) + * [`FormSpyProps`](#formspyprops) + * [`children?: ((props: FormSpyRenderProps) => React.Node) | React.Node`](#children-props-formspyrenderprops--reactnode--reactnode) + * [`component?: React.ComponentType`](#component-reactcomponenttypeformspyrenderprops) + * [`render?: (props: FormSpyRenderProps) => React.Node`](#render-props-formspyrenderprops--reactnode) + * [`formSubscription?: FormSubscription`](#formsubscription-formsubscription) + * [`FormSpyRenderProps`](#formspyrenderprops) @@ -349,6 +354,10 @@ The current value of the field. [See the 🏁 Final Form docs on `active`](https://github.com/erikras/final-form#active-boolean). +#### `meta.data: Object` + +[See the 🏁 Final Form docs on `data`](https://github.com/erikras/final-form#data-object). + #### `meta.dirty?: boolean` [See the 🏁 Final Form docs on `dirty`](https://github.com/erikras/final-form#dirty-boolean). @@ -417,6 +426,10 @@ well as any non-API props passed into the `
` component. [See the 🏁 Final Form docs on `initialValues`](https://github.com/erikras/final-form#initialvalues-object). +#### `mutators?: { [string]: Mutator }` + +[See the 🏁 Final Form docs on `mutators`](https://github.com/erikras/final-form#mutators--string-function-). + #### `onSubmit: (values: Object, callback: ?(errors: ?Object) => void) => ?Object | Promise | void` [See the 🏁 Final Form docs on `onSubmit`](https://github.com/erikras/final-form#onsubmit-values-object-callback-errors-object--void--object--promiseobject--void). @@ -482,6 +495,10 @@ onSubmit={handleSubmit}/>`. A function that initializes the form values. [See the 🏁 Final Form docs on `initialize`](https://github.com/erikras/final-form#initialize-values-object--void). +#### `mutators?: { [string]: Function }` + +[See the 🏁 Final Form docs on `mutators`](https://github.com/erikras/final-form#mutators--string-function-). + #### `reset: () => void` A function that resets the form values to their last initialized values. @@ -508,7 +525,7 @@ as well as any non-API props passed into the `` component. A render function that is given [`FormSpyRenderProps`](#formspyrenderprops), as well as any non-API props passed into the `` component. -#### `subscription?: FormSubscription` +#### `formSubscription?: FormSubscription` A [`FormSubscription`](https://github.com/erikras/final-form#formsubscription--string-boolean-) diff --git a/package-lock.json b/package-lock.json index d53152c4..da77dbf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "react-final-form", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz", "integrity": - "sha512-EVq4T1a2GviKiQ75OfxNrGPPhJyXzg9jjORuuwhloZbFdrhT4FHa73sv9OFWBwX7rl2b6bxBVmfxrBQYWYz9tA==", + "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", "dev": true, "requires": { "chalk": "2.3.0", @@ -18,55 +18,56 @@ } }, "@babel/helper-function-name": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.31.tgz", "integrity": - "sha512-ysfIt7p72xm5fjSJsv7fMVN/j+EwIdqu8/MJjt6TqB4wM2r6rFRi0ujBTWDkLGQkRB/P5uDV8qcFCHAHnNzmsg==", + "sha512-c+DAyp8LMm2nzSs2uXEuxp4LYGSUYEyHtU3fU57avFChjsnTmmpWmXj2dv0yUxHTEydgVAv5fIzA+4KJwoqWDA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0-beta.32", - "@babel/template": "7.0.0-beta.32", - "@babel/types": "7.0.0-beta.32" + "@babel/helper-get-function-arity": "7.0.0-beta.31", + "@babel/template": "7.0.0-beta.31", + "@babel/traverse": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.31.tgz", "integrity": - "sha512-bm7lIlizycJQY5SJ3HXWJV4XjSrOt1onzrDcOxUo9FEnKRZDEr/zfi5ar2s5tvvZvve/jGHwZKVKekRw2cjPCQ==", + "sha512-m7rVVX/dMLbbB9NCzKYRrrFb0qZxgpmQ4Wv6y7zEsB6skoJHRuXVeb/hAFze79vXBbuD63ci7AVHXzAdZSk9KQ==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.32" + "@babel/types": "7.0.0-beta.31" } }, "@babel/template": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.31.tgz", "integrity": - "sha512-DB9sLgX2mfE29vjAkxHlzLyWr31EO9HaYoAM/UsPSsL70Eudl0i25URwIfQT6S6ckeVFnFP1t6PhERVeV4EAHA==", + "sha512-97IRmLvoDhIDSQkqklVt3UCxJsv0LUEVb/0DzXWtc8Lgiyxj567qZkmTG9aR21CmcJVVIvq2Y/moZj4oEpl5AA==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.32", - "@babel/types": "7.0.0-beta.32", - "babylon": "7.0.0-beta.32", + "@babel/code-frame": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31", + "babylon": "7.0.0-beta.31", "lodash": "4.17.4" } }, "@babel/traverse": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.31.tgz", "integrity": - "sha512-dGe2CLduCIZ/iDkbmnqspQguRy5ARvI+zC8TiwFnsJ2YYO2TWK7x2aEwrbkSmi0iPlBP+Syiag7Idc1qNQq74g==", + "sha512-3N+VJW+KlezEjFBG7WSYeMyC5kIqVLPb/PGSzCDPFcJrnArluD1GIl7Y3xC7cjKiTq2/JohaLWHVPjJWHlo9Gg==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.32", - "@babel/helper-function-name": "7.0.0-beta.32", - "@babel/types": "7.0.0-beta.32", - "babylon": "7.0.0-beta.32", + "@babel/code-frame": "7.0.0-beta.31", + "@babel/helper-function-name": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31", + "babylon": "7.0.0-beta.31", "debug": "3.1.0", "globals": "10.4.0", "invariant": "2.2.2", @@ -74,11 +75,11 @@ } }, "@babel/types": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.31.tgz", "integrity": - "sha512-w8+wzVcYCMb9OfaBfay2Vg5hyj7UfBX6qQtA+kB0qsW1h1NH/7xHMwvTZNqkuFBwjz5wxGS2QmaIcC3HH+UoxA==", + "sha512-exAHB+NeFGxkfQ5dSUD03xl3zYGneeSk2Mw2ldTt/nTvYxuDiuSp3DlxgUBgzbdTFG4fbwPk0WtKWOoTXCmNGg==", "dev": true, "requires": { "esutils": "2.0.2", @@ -142,9 +143,9 @@ } }, "ajv": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.0.tgz", - "integrity": "sha1-6yhAdG6dxIvV4GOjbj/UAMXqtak=", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz", + "integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=", "dev": true, "requires": { "co": "4.6.0", @@ -518,17 +519,17 @@ } }, "babel-eslint": { - "version": "8.0.2", + "version": "8.0.3", "resolved": - "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.0.2.tgz", + "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.0.3.tgz", "integrity": - "sha512-yyl5U088oE+419+BNLJDKVWkUokuPLQeQt9ZTy9uM9kAzbtQgyYL3JkG425B8jxXA7MwTxnDAtRLMKJNH36qjA==", + "sha512-7D4iUpylEiKJPGbeSAlNddGcmA41PadgZ6UAb6JVyh003h3d0EbZusYFBR/+nBgqtaVJM2J2zUVa3N0hrpMH6g==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.32", - "@babel/traverse": "7.0.0-beta.32", - "@babel/types": "7.0.0-beta.32", - "babylon": "7.0.0-beta.32" + "@babel/code-frame": "7.0.0-beta.31", + "@babel/traverse": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31", + "babylon": "7.0.0-beta.31" } }, "babel-generator": { @@ -1514,11 +1515,11 @@ } }, "babylon": { - "version": "7.0.0-beta.32", + "version": "7.0.0-beta.31", "resolved": - "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.32.tgz", + "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz", "integrity": - "sha512-PvAmyP2IJEBVAuE5yVzrTSWCCN9VMa1eGns8w3w6FYD/ivHSUmS7n+F40Fmjn+0nCQSUFR96wP0CqQ4jxTnF4Q==", + "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==", "dev": true }, "bail": { @@ -1614,7 +1615,7 @@ "sha512-3n3nPdbUqn3nWmsy4PeSQthz2ja1ndpoXta+dwFFNhveGjMg6FXpWYe12vsTpNoXJbzx3j7GZXdtoVIdvh3JbA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000772", + "caniuse-lite": "1.0.30000778", "electron-to-chromium": "1.3.27" } }, @@ -1645,7 +1646,7 @@ "axios": "0.16.2", "bytes": "3.0.0", "ci-env": "1.5.2", - "commander": "2.12.1", + "commander": "2.12.2", "github-build": "1.2.0", "glob": "7.1.2", "gzip-size": "4.1.0", @@ -1759,10 +1760,10 @@ } }, "caniuse-lite": { - "version": "1.0.30000772", + "version": "1.0.30000778", "resolved": - "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000772.tgz", - "integrity": "sha1-eBKWIsq/7Xrx/zi2SraApqCGVCA=", + "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000778.tgz", + "integrity": "sha1-8efLixOx9nREAikddfC81MMWA2k=", "dev": true }, "caseless": { @@ -1993,10 +1994,10 @@ } }, "commander": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.1.tgz", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", "integrity": - "sha512-PCNLExLlI5HiPdaJs4pMXwOTHkSCpNQ1QJH9ykZLKtKEyKu3p9HgmH5l97vM8c0IUz6d54l+xEu2GG9yuYrFzA==", + "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", "dev": true }, "common-tags": { @@ -2648,13 +2649,13 @@ } }, "eslint": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.12.0.tgz", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.12.1.tgz", "integrity": - "sha512-Ohv4NU0FffkEe4so8DBrdfRUbGUtM4XnBTDll2pY7OdW3VkjBOZPerx3Bmuhg6S6D6r8+cli0EezN0xawUfYwg==", + "sha512-28hOYej+NZ/R5H1yMvyKa1+bPlu+fnsIAQffK6hxXgvmXnImos2bA5XfCn5dYv2k2mrKj+/U/Z4L5ICWxC7TQw==", "dev": true, "requires": { - "ajv": "5.5.0", + "ajv": "5.5.1", "babel-code-frame": "6.26.0", "chalk": "2.3.0", "concat-stream": "1.6.0", @@ -3227,11 +3228,11 @@ } }, "final-form": { - "version": "1.0.0", + "version": "1.2.0", "resolved": - "https://registry.npmjs.org/final-form/-/final-form-1.0.0.tgz", + "https://registry.npmjs.org/final-form/-/final-form-1.2.0.tgz", "integrity": - "sha512-0sv+41vyZgVhrlf56US0CsDdsk2kWH/3bMIf5S2JDqxdjGlpZStYB0CZO8ihN4nCovq2ub1c9wVQpK9jgQhqwQ==", + "sha512-GLe+dpWh/RNFIbqNakKc7HVMZeOu53R0dBqvPAlnYo02777H2IwYy9AFWhUwQ6yuF/xsmRSEtYhyYWvHDPZYqw==", "dev": true }, "find-parent-dir": { @@ -3270,10 +3271,10 @@ "dev": true }, "flow-bin": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.59.0.tgz", + "version": "0.60.1", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.60.1.tgz", "integrity": - "sha512-yJDRffvby5mCTkbwOdXwiGDjeea8Z+BPVuP53/tHqHIZC+KtQD790zopVf7mHk65v+wRn+TZ7tkRSNA9oDmyLg==", + "sha512-n31idUasUQVqOYl8Tvig7kfmdcAdRC+J1Gt88J435DZm0saNfwqeYOMoZrehRD6JgaAGQ0PaJfoxWuL9lKZXpA==", "dev": true }, "flow-remove-types": { @@ -4491,7 +4492,7 @@ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "ajv": "5.5.0", + "ajv": "5.5.1", "har-schema": "2.0.0" } }, @@ -4923,14 +4924,14 @@ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { - "version": "1.0.0", + "version": "1.0.1", "resolved": - "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", - "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { "path-is-inside": "1.0.2" @@ -5740,17 +5741,18 @@ } }, "lint-staged": { - "version": "5.0.0", + "version": "6.0.0", "resolved": - "https://registry.npmjs.org/lint-staged/-/lint-staged-5.0.0.tgz", + "https://registry.npmjs.org/lint-staged/-/lint-staged-6.0.0.tgz", "integrity": - "sha512-nKwjLlYOd6Eqog3cg3aDulrRfLkR3GPasqTI7+3ZKucLATqay86wOaEM0gtYVmTS0/ihHSARnOWduAqNJZAbeQ==", + "sha512-ZUftK94S4vedpQG1LlA2tc2AuQXXBwc+1lB+j8SEfG5+p2dqu3Ug8iYQ8jdap+uLkhDw4OaJXqE+CZ/L+vfv+Q==", "dev": true, "requires": { "app-root-path": "2.0.1", "chalk": "2.3.0", - "commander": "2.12.1", + "commander": "2.12.2", "cosmiconfig": "3.1.0", + "debug": "3.1.0", "dedent": "0.7.0", "execa": "0.8.0", "find-parent-dir": "0.3.0", @@ -5827,7 +5829,7 @@ "log-update": "1.0.2", "ora": "0.2.3", "p-map": "1.2.0", - "rxjs": "5.5.2", + "rxjs": "5.5.3", "stream-to-observable": "0.2.0", "strip-ansi": "3.0.1" }, @@ -6606,7 +6608,7 @@ "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", "dev": true, "requires": { - "commander": "2.12.1", + "commander": "2.12.2", "npm-path": "2.0.3", "which": "1.3.0" } @@ -7276,23 +7278,24 @@ "dev": true }, "prettier-eslint": { - "version": "8.2.2", + "version": "8.2.3", "resolved": - "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-8.2.2.tgz", + "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-8.2.3.tgz", "integrity": - "sha512-zeR/ZfoENuKupTd+l49aUSCKGAheIPIpZFErK2xJhPfqubg2iJy2velL72AnGkgXsXiyLwAthxoXHoL2HASctw==", + "sha512-cQNfrjLLVGo6YTHp+2Ne05cupqnOkYHWYvo/Y6oczJXBWcaUgr7GUQ2LlBFEOxmwxJlKGI+cQLh6r3EcPScBRw==", "dev": true, "requires": { + "babel-core": "6.26.0", "common-tags": "1.5.1", "dlv": "1.1.0", - "eslint": "4.12.0", + "eslint": "4.12.1", "indent-string": "3.2.0", "lodash.merge": "4.6.0", "loglevel-colored-level-prefix": "1.0.0", "prettier": "1.8.2", - "pretty-format": "20.0.3", + "pretty-format": "21.2.1", "require-relative": "0.8.7", - "typescript": "2.6.1", + "typescript": "2.6.2", "typescript-eslint-parser": "8.0.1" }, "dependencies": { @@ -7302,35 +7305,24 @@ "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", "dev": true - }, - "pretty-format": { - "version": "20.0.3", - "resolved": - "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", - "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1", - "ansi-styles": "3.2.0" - } } } }, "prettier-eslint-cli": { - "version": "4.4.0", + "version": "4.4.2", "resolved": - "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-4.4.0.tgz", + "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-4.4.2.tgz", "integrity": - "sha512-q7kAFt+JpUQJALs110mpaT0+NEMZ4tt1SgOmeNL1D+13rABH0nIMw8fy3NnaTMSmRH9Wfuct6jHSDyqdb9PpVQ==", + "sha512-gYHzialGyhPFHdI/PCwVNxJr9nX+IpysKU2g3064Cydz+4w1kQvm7YAWEx11QnrjSkn95NBtk9SsYjTmBWNqcA==", "dev": true, "requires": { "arrify": "1.0.1", "babel-runtime": "6.26.0", "boolify": "1.0.1", "camelcase-keys": "4.2.0", - "chalk": "2.1.0", + "chalk": "2.3.0", "common-tags": "1.5.1", - "eslint": "4.12.0", + "eslint": "4.12.1", "find-up": "2.1.0", "get-stdin": "5.0.1", "glob": "7.1.2", @@ -7339,9 +7331,9 @@ "lodash.memoize": "4.1.2", "loglevel-colored-level-prefix": "1.0.0", "messageformat": "1.1.0", - "prettier-eslint": "8.2.2", - "rxjs": "5.5.2", - "yargs": "8.0.2" + "prettier-eslint": "8.2.3", + "rxjs": "5.5.3", + "yargs": "10.0.3" }, "dependencies": { "camelcase": { @@ -7363,18 +7355,6 @@ "quick-lru": "1.1.0" } }, - "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": - "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -7424,84 +7404,41 @@ "number-is-nan": "1.0.1" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": - "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, "map-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", "dev": true }, - "path-type": { - "version": "2.0.0", - "resolved": - "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "2.3.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": - "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": - "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": - "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz", + "integrity": + "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", "dev": true, "requires": { - "camelcase": "4.1.0", "cliui": "3.2.0", "decamelize": "1.2.0", + "find-up": "2.1.0", "get-caller-file": "1.0.2", "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", "require-directory": "2.1.1", "require-main-filename": "1.0.1", "set-blocking": "2.0.0", "string-width": "2.1.1", "which-module": "2.0.0", "y18n": "3.2.1", - "yargs-parser": "7.0.0" + "yargs-parser": "8.0.0" + } + }, + "yargs-parser": { + "version": "8.0.0", + "resolved": + "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.0.0.tgz", + "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=", + "dev": true, + "requires": { + "camelcase": "4.1.0" } } } @@ -7689,10 +7626,10 @@ } }, "react": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.1.1.tgz", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.2.0.tgz", "integrity": - "sha512-FQfiFfk2z2Fk87OngNJHT05KyC9DOVn8LPeB7ZX+9u5+yU1JK6o5ozRlU3PeOMr0IFkWNvgn9jU8/IhRxR1F0g==", + "sha512-ZmIomM7EE1DvPEnSFAHZn9Vs9zJl5A9H7el0EGTE6ZbW9FKe/14IYAlPbC8iH25YarEQxZL+E8VW7Mi7kfQrDQ==", "dev": true, "requires": { "fbjs": "0.8.16", @@ -7702,10 +7639,10 @@ } }, "react-dom": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.1.1.tgz", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.2.0.tgz", "integrity": - "sha512-q06jiwST8SEPAMIEkAsu7BgynEZtqF87VrTc70XsW7nxVhWEu2Y4MF5UfxxHQO/mNtQHQWP0YcFxmwm9oMrMaQ==", + "sha512-zpGAdwHVn9K0091d+hr+R0qrjoJ84cIBFL2uU60KvWBPfZ7LPSrfqviTxGHWN0sjPZb2hxWzMexwrvJdKePvjg==", "dev": true, "requires": { "fbjs": "0.8.16", @@ -8083,10 +8020,10 @@ } }, "rollup": { - "version": "0.51.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.51.8.tgz", + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.52.0.tgz", "integrity": - "sha512-e7FwWxqb4vhdonmwRH06nqC9wR6h1kZojK2D+lN1xjiB8FDtAKgy7o+r8fCXVzQZ1ZCdcVlls3mTq5g6u38Jew==", + "sha512-IQ+t5uoeMSHpDyeJj4uFVWj+ocS8sUbFPNKCssyCac3GVgLs62nFH6UdU0nGLRIxjasPaN7wGHEioVXbxXRaYQ==", "dev": true }, "rollup-plugin-babel": { @@ -8209,7 +8146,7 @@ "integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=", "dev": true, "requires": { - "uglify-js": "3.2.0" + "uglify-js": "3.2.1" }, "dependencies": { "source-map": { @@ -8221,14 +8158,14 @@ "dev": true }, "uglify-js": { - "version": "3.2.0", + "version": "3.2.1", "resolved": - "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.0.tgz", + "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.1.tgz", "integrity": - "sha512-L98DlTshoPGnZGF8pr3MoE+CCo6n9joktHNHMPkckeBV8xTVc4CWtC0kGGhQsIvnX2Ug4nXFTAeE7SpTrPX2tg==", + "sha512-BhZTJPmOKPSUcjnx2nlfaOQKHLyjjT4HFyzFWF1BUErx9knJNpdW94ql5o8qVxeNL+8IAWjEjnPvASH2yZnkMg==", "dev": true, "requires": { - "commander": "2.12.1", + "commander": "2.12.2", "source-map": "0.6.1" } } @@ -8261,20 +8198,21 @@ "dev": true }, "rxjs": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.3.tgz", "integrity": - "sha512-oRYoIKWBU3Ic37fLA5VJu31VqQO4bWubRntcHSJ+cwaDQBwdnZ9x4zmhJfm/nFQ2E82/I4loSioHnACamrKGgA==", + "sha512-VWockSz7xmDveeZ7wv8RvdipGGZ1NmL/m4jnpvN9BH4x1fW/TPoD23yXh+qDkbWSlajXVVfLIbGmyxa94Ls84w==", "dev": true, "requires": { - "symbol-observable": "1.0.4" + "symbol-observable": "1.1.0" }, "dependencies": { "symbol-observable": { - "version": "1.0.4", + "version": "1.1.0", "resolved": - "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", - "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=", + "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz", + "integrity": + "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw==", "dev": true } } @@ -8702,7 +8640,7 @@ "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { - "ajv": "5.5.0", + "ajv": "5.5.1", "ajv-keywords": "2.1.1", "chalk": "2.3.0", "lodash": "4.17.4", @@ -8901,10 +8839,10 @@ "dev": true }, "typescript": { - "version": "2.6.1", + "version": "2.6.2", "resolved": - "https://registry.npmjs.org/typescript/-/typescript-2.6.1.tgz", - "integrity": "sha1-7znN6ierrAtQAkLWcmq5DgyEZjE=", + "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", "dev": true }, "typescript-eslint-parser": { diff --git a/package.json b/package.json index be9633ec..9d72d904 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-final-form", - "version": "1.0.0", + "version": "1.1.0", "description": "🏁 High performance subscription-based form state management for React", "main": "dist/react-final-form.cjs.js", @@ -24,7 +24,7 @@ }, "homepage": "https://github.com/erikras/react-final-form#readme", "devDependencies": { - "babel-eslint": "^8.0.2", + "babel-eslint": "^8.0.3", "babel-jest": "^21.2.0", "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-flow-strip-types": "^6.22.0", @@ -33,28 +33,28 @@ "babel-preset-stage-2": "^6.24.1", "bundlesize": "^0.15.3", "doctoc": "^1.3.0", - "eslint": "^4.10.0", + "eslint": "^4.12.1", "eslint-config-react-app": "^2.0.1", "eslint-plugin-babel": "^4.1.2", "eslint-plugin-flowtype": "^2.37.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-react": "^7.4.0", - "final-form": "^1.0.0", + "final-form": "^1.2.0", "flow": "^0.2.3", - "flow-bin": "^0.59.0", + "flow-bin": "^0.60.1", "husky": "^0.14.3", "jest": "^21.2.1", - "lint-staged": "^5.0.0", + "lint-staged": "^6.0.0", "nps": "^5.7.1", "nps-utils": "^1.5.0", "prettier": "^1.8.2", - "prettier-eslint-cli": "^4.4.0", + "prettier-eslint-cli": "^4.4.2", "prop-types": "^15.6.0", "raf": "^3.4.0", - "react": "^16.1.0", - "react-dom": "^16.1.0", - "rollup": "^0.51.3", + "react": "^16.2.0", + "react-dom": "^16.2.0", + "rollup": "^0.52.0", "rollup-plugin-babel": "^3.0.2", "rollup-plugin-commonjs": "^8.2.6", "rollup-plugin-flow": "^1.1.1", @@ -63,7 +63,7 @@ "rollup-plugin-uglify": "^2.0.1" }, "peerDependencies": { - "final-form": "^1.0.0", + "final-form": "^1.2.0", "prop-types": "^15.6.0", "react": "^15.0.0-0 || ^16.0.0-0" }, diff --git a/src/Field.test.js b/src/Field.test.js index 764d317e..25c11927 100644 --- a/src/Field.test.js +++ b/src/Field.test.js @@ -211,7 +211,12 @@ describe('Field', () => { }) it('should optionally allow null', () => { - const renderInput = jest.fn(({ input }) => ) + const renderInput = jest.fn(({ input }) => ( + + )) const render = jest.fn(() => ( @@ -279,22 +284,22 @@ describe('Field', () => { onChange('hi') // valid now - expect(input).toHaveBeenCalledTimes(3) - expect(input.mock.calls[2][0].meta.error).toBeUndefined() + expect(input).toHaveBeenCalledTimes(2) + expect(input.mock.calls[1][0].meta.error).toBeUndefined() // toggle rules const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button') TestUtils.Simulate.click(button) // props changed, but still valid. doesn't update until next time validation is run - expect(input).toHaveBeenCalledTimes(4) - expect(input.mock.calls[3][0].meta.error).toBeUndefined() + expect(input).toHaveBeenCalledTimes(3) + expect(input.mock.calls[2][0].meta.error).toBeUndefined() onChange('his') // invalid now - expect(input).toHaveBeenCalledTimes(6) - expect(input.mock.calls[5][0].meta.error).toBe('Must be uppercase') + expect(input).toHaveBeenCalledTimes(4) + expect(input.mock.calls[3][0].meta.error).toBe('Must be uppercase') }) it('should render checkboxes with checked prop', () => { diff --git a/src/FormSpy.test.js b/src/FormSpy.test.js index 95ecec2e..31f2c941 100644 --- a/src/FormSpy.test.js +++ b/src/FormSpy.test.js @@ -28,6 +28,7 @@ describe('FormSpy', () => { expect(render).toHaveBeenCalledTimes(1) expect(render).toHaveBeenCalledWith({ dirty: false, + errors: {}, invalid: false, pristine: true, submitFailed: false, @@ -46,6 +47,7 @@ describe('FormSpy', () => { expect(render).toHaveBeenCalledTimes(2) expect(render).toHaveBeenCalledWith({ dirty: true, + errors: {}, invalid: false, pristine: false, submitFailed: false, diff --git a/src/ReactFinalForm.js b/src/ReactFinalForm.js index f87df768..be560259 100644 --- a/src/ReactFinalForm.js +++ b/src/ReactFinalForm.js @@ -44,6 +44,7 @@ export default class ReactFinalForm extends React.PureComponent { component, debug, initialValues, + mutators, onSubmit, render, validate, @@ -56,6 +57,7 @@ export default class ReactFinalForm extends React.PureComponent { const config: Config = { debug, initialValues, + mutators, onSubmit, validate } @@ -84,6 +86,7 @@ export default class ReactFinalForm extends React.PureComponent { } notify = (state: FormState) => this.setState({ state }) + handleSubmit = (event: SyntheticEvent) => { event.preventDefault() this.form.submit() @@ -98,6 +101,7 @@ export default class ReactFinalForm extends React.PureComponent { const { debug, initialValues, + mutators, onSubmit, subscription, validate, @@ -107,6 +111,7 @@ export default class ReactFinalForm extends React.PureComponent { { ...props, ...this.state.state, + mutators: this.form && this.form.mutators, batch: this.form && this.form.batch, blur: this.form && this.form.blur, change: this.form && this.form.change, diff --git a/src/index.js.flow b/src/index.js.flow index 8ba503e9..dbf43a9d 100644 --- a/src/index.js.flow +++ b/src/index.js.flow @@ -2,6 +2,8 @@ import * as React from 'react' import type { FieldProps, FormProps, FormSpyProps } from './types' +export type { ReactContext } from './types' + declare export var Field: React.ComponentType declare export var Form: React.ComponentType declare export var FormSpy: React.ComponentType