diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index a85d139bb90..83ee81f9ff5 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -71,7 +71,7 @@ "react-custom-scrollbars": "4.2.1", "react-dom": "17.0.1", "react-highlight-words": "0.16.0", - "react-hook-form": "5.1.3", + "react-hook-form": "7.2.3", "react-popper": "2.2.4", "react-storybook-addon-props-combinations": "1.1.0", "react-table": "7.0.0", diff --git a/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx b/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx index 0b4a473c597..9fd1a782294 100644 --- a/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx +++ b/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx @@ -17,7 +17,7 @@ export default { }; export const simple = () => { - const defaultValues = { + const defaultValues: any = { people: [{ firstName: 'Janis', lastName: 'Joplin' }], }; return ( @@ -30,8 +30,16 @@ export const simple = () => {
{fields.map((field, index) => ( - - + + ))}
diff --git a/packages/grafana-ui/src/components/Forms/Form.mdx b/packages/grafana-ui/src/components/Forms/Form.mdx index fdfcb66dec3..417eb7c4105 100644 --- a/packages/grafana-ui/src/components/Forms/Form.mdx +++ b/packages/grafana-ui/src/components/Forms/Form.mdx @@ -1,4 +1,4 @@ -import { Meta, Story, Preview, Props } from "@storybook/addon-docs/blocks"; +import { Meta, Props } from "@storybook/addon-docs/blocks"; import { Form } from "./Form"; @@ -29,8 +29,8 @@ const defaultUser: Partial = { >{({register, errors}) => { return ( - - + + ) @@ -43,18 +43,17 @@ const defaultUser: Partial = { #### `register` -`register` allows to register form elements(inputs, selects, radios, etc) in the form. In order to do that you need to pass `register` as a `ref` property to the form input. For example: +`register` allows registering form elements (inputs, selects, radios, etc) in the form. In order to do that you need to invoke the function itself and spread the props into the input. For example: ```jsx - + ``` -Register accepts an object which describes validation rules for a given input: +The first argument for `register` is the field name. It also accepts an object, which describes validation rules for a given input: ```jsx { // custom validation rule } @@ -70,7 +69,7 @@ See [Validation](#validation) for examples on validation and validation rules. ```jsx - + ``` @@ -89,22 +88,20 @@ import { Form, Field, InputControl } from '@grafana/ui'; } {/* Pass control exposed from Form render prop */} control={control} name="radio" - options={...} /> onChange(value.value)}/>} control={control} name="select" - onSelected={onSelectChange} - {/* Pass the name of the onChange handler */} - onChangeName='onSelected' /> +``` +Note that `field` also contains `ref` prop, which is passed down to the rendered component by default. In case if that component doesn't support this prop, it will need to be removed before spreading the `field`. + +```jsx + + + )} @@ -197,9 +192,8 @@ Validation can be performed either synchronously or asynchronously. What's impor <> )} @@ -217,8 +211,7 @@ One important thing to note is that if you want to provide different error messa { return v !== 'John' && 'Name must be John' @@ -258,8 +251,7 @@ validateAsync = (newValue: string) => { { return await validateAsync(v); @@ -271,6 +263,26 @@ validateAsync = (newValue: string) => { ``` +### Upgrading to v8 +Version 8 of Grafana-UI is using version 7 of `react-hook-form` (previously version 5 was used), which introduced a few breaking changes to the `Form` API. The detailed list of changes can be found in the library's migration guides: +- [Migration guide v5 to v6](https://react-hook-form.com/migrate-v5-to-v6/) +- [Migration guide v6 to v7](https://react-hook-form.com/migrate-v6-to-v7/) + +In a nutshell, the two most important changes are: +- register method is no longer passed as a `ref`, but instead its result is spread onto the input component: +```jsx +- ++ +``` +- `InputControl`'s `as` prop has been replaced with `render`, which has `field` and `fieldState` objects as arguments. `onChange`, `onBlur`, `value`, `name`, and `ref` are parts of `field`. +```jsx +- } /> ++ } +// or ++ } /> +``` + + ### Props diff --git a/packages/grafana-ui/src/components/Forms/Form.story.tsx b/packages/grafana-ui/src/components/Forms/Form.story.tsx index ddd12686352..42455b78057 100644 --- a/packages/grafana-ui/src/components/Forms/Form.story.tsx +++ b/packages/grafana-ui/src/components/Forms/Form.story.tsx @@ -1,8 +1,4 @@ import React from 'react'; - -import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; -import { withStoryContainer } from '../../utils/storybook/withStoryContainer'; -import mdx from './Form.mdx'; import { ValidateResult } from 'react-hook-form'; import { Story } from '@storybook/react'; import { @@ -18,9 +14,12 @@ import { TextArea, RadioButtonGroup, } from '@grafana/ui'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { withStoryContainer } from '../../utils/storybook/withStoryContainer'; +import mdx from './Form.mdx'; export default { - title: 'Forms/Example forms', + title: 'Forms/Form', decorators: [withStoryContainer, withCenteredStory], parameters: { docs: { @@ -48,20 +47,20 @@ const selectOptions = [ ]; interface FormDTO { - name: string; - email: string; - username: string; - checkbox: boolean; + name?: string; + email?: string; + username?: string; + checkbox?: boolean; switch: boolean; radio: string; select: string; - text: string; + text?: string; nested: { path: string; }; } -const renderForm = (defaultValues?: Partial) => ( +const renderForm = (defaultValues?: FormDTO) => (
{ @@ -74,34 +73,38 @@ const renderForm = (defaultValues?: Partial) => ( Edit user - + - + - + - + -