-
Notifications
You must be signed in to change notification settings - Fork 8.6k
[Docs] ES UI form library #78654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
[Docs] ES UI form library #78654
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
c116f2d
Setup dev docs website
sebelga 41ec445
Add docs
sebelga e3100f8
Update src/plugins/es_ui_shared/docs/docs/form_lib/core/about.md
sebelga 76edfc2
Apply suggestions from code review
sebelga 5ac1e87
Update core/about.md
sebelga 48e71f2
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 2ebd95d
Apply suggestions from code review
sebelga 13d58f0
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 22ae174
Apply suggestions from code review
sebelga 00690d6
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 433bedf
Apply suggestions from code review
sebelga 837a18f
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 6eb1431
Update core/form_component.md
sebelga b49fdd3
Apply suggestions from code review
sebelga 567d71d
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 6a59a2e
Update core/form_hook.md
sebelga f63c2e7
Apply suggestions from code review
sebelga 4267d00
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 390f798
Update core/use_field.md
sebelga 453996f
Apply suggestions from code review
sebelga 287b5b5
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 17d345b
Update core/use_form_hook.md
sebelga 231c331
Apply suggestions from code review
sebelga 9846787
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 27c31ac
Apply suggestions from code review
sebelga e3dcf1b
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 869267e
Update examples/dynamic_fields.md
sebelga 43ff400
Merge branch 'master' into docs/es-ui-shared-2
sebelga a387dd8
Change field composition example to a "car configurator" form
sebelga 8e679e3
Remove unnecessary block in fields_composition example
sebelga 627fb7d
Split example on how to listen to form changes in root or child compo…
sebelga 42a53e9
Update comments as suggested in CR
sebelga 29e59de
Simplify de/serializer example + add description
sebelga ccaeb55
Simplify "Style fields" examples
sebelga 229947d
Apply suggestions from code review
sebelga 4f56f94
Update validation examples from CR suggestions
sebelga 856640c
Merge branch 'docs/es-ui-shared-2' of github.com:sebelga/kibana into …
sebelga 66a8e0b
Update src/plugins/es_ui_shared/docs/docs/form_lib/examples/react_to_…
sebelga 422479b
Update src/plugins/es_ui_shared/docs/docs/form_lib/examples/react_to_…
sebelga File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| /* | ||
| * Licensed to Elasticsearch B.V. under one or more contributor | ||
| * license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright | ||
| * ownership. Elasticsearch B.V. licenses this file to you under | ||
| * the Apache License, Version 2.0 (the "License"); you may | ||
| * not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| module.exports = { | ||
| presets: [require.resolve('@docusaurus/core/lib/babel/preset')], | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| --- | ||
| id: about | ||
| title: Core | ||
| sidebar_label: Getting started | ||
| --- | ||
|
|
||
| The core exposes the main building blocks (hooks and components) needed to build your form. | ||
|
|
||
| It is important to note that the core **is not** responsible for rendering UI. Its responsibility is to return form and fields **state and handlers** that you can connect to React components. The core of the form lib is agnostic of any UI rendering the form. | ||
|
|
||
| In Kibana we work with [the EUI component library](https://elastic.github.io/eui) and have created [field components](../helpers/components.md) that wrap EUI components. With these components, connection with the form lib is already done for you. | ||
|
|
||
| ## Getting started | ||
|
|
||
| The three required components to build a form are: | ||
|
|
||
| - `useForm()` hook to declare a new form | ||
| - `<Form />` component that will wrap your form and create a context for it | ||
| - `<UseField />` component to declare a field | ||
|
|
||
| Let's see them in action before going into details | ||
|
|
||
| ```js | ||
| import { useForm, Form, UseField } from 'src/plugins/es_ui_shared/public'; | ||
|
|
||
| export const UserForm = () => { | ||
| const { form } = useForm(); // 1 | ||
|
|
||
| return ( | ||
| <Form form={form}> // 2 | ||
| <UseField path="name" /> // 3 | ||
| <UseField path="lastName" /> | ||
|
|
||
| <button onClick={form.submit}>Submit</button> | ||
| </Form> | ||
| ); | ||
| }; | ||
| ``` | ||
|
|
||
| 1. We use the `useForm` hook to declare a new form. | ||
| 2. We then wrap our form with the `<Form />` component, providing the `form` that we have just created. | ||
| 3. Finally, we declared two fields with the `<UseField />` component, providing a unique `path` for each one of them. | ||
|
|
||
| If you were to run this code in the browser and click on the "Submit" button nothing would happen as we haven't defined any handler to execute when submitting the form. Let's do that now along with providing a `UserFormData` interface to the form, which we will get back in our `onSubmit` handler. | ||
|
|
||
| ```js | ||
| import { useForm, Form, UseField, FormConfig } from 'src/plugins/es_ui_shared/public'; | ||
|
|
||
| interface UserFormData { | ||
| name: string; | ||
| lastName: string; | ||
| } | ||
|
|
||
| export const UserForm = () => { | ||
| const onFormSubmit: FormConfig<UserFormData>['onSubmit'] = async (data, isValid) => { | ||
| console.log("Is form valid:", isValid); | ||
| if (!isValid) { | ||
| // Maybe show a callout? | ||
| return; | ||
| } | ||
|
|
||
| console.log("Form data:", data); | ||
| }; | ||
|
|
||
| const { form } = useForm({ onSubmit: onFormSubmit }); | ||
|
|
||
| return ( | ||
| <Form form={form}> | ||
| ... | ||
| <button onClick={form.submit}>Submit</button> | ||
| </Form> | ||
| ); | ||
| }; | ||
| ``` | ||
|
|
||
| Great! We have our first working form. No state to worry about, just a simple declarative way to build our fields. | ||
|
|
||
| Those of you who are attentive might have noticed that the above form _does_ render the fields in the UI although we said earlier that the core of the form lib is not responsible for any UI rendering. This is because the `<UseField />` has a fallback mechanism to render an `<input type="text" />` and hook to the field `value` and `onChange`. Unless you have styled your `input` elements and don't require other field types like `checkbox` or `select`, you will probably want to customize how the the `<UseField />` renders. We will see that in a future section. | ||
93 changes: 93 additions & 0 deletions
93
src/plugins/es_ui_shared/docs/docs/form_lib/core/default_value.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| --- | ||
| id: default_value | ||
| title: defaultValue | ||
| sidebar_label: defaultValue | ||
| --- | ||
|
|
||
| There are multiple places where you can define the default value of a field. Note that by "default value" we are saying "the initial value" of a field. Once the field is initiated it has its own internal state and can't be controlled. | ||
|
|
||
| ## Order of precedence | ||
|
|
||
| 1. As a prop on the `<UseField path="name" defaultValue="John" />` component | ||
| 2. In the **form** `defaultValue` config passed to `useForm({ defaultValue: { ... } })` | ||
| 3. In the **field** `defaultValue` config parameter (either passed as prop to `<UseField />` prop or declared inside a form schema) | ||
| 4. If no default value is found above, it defaults to `""` (empty string) | ||
|
|
||
| ### As a prop on `<UseField />` | ||
|
|
||
| This takes over any other `defaultValue` defined elsewhere. What you provide as prop is what you will have as default value for the field. Remember that the `<UseField />` **is not** a controlled component, so changing the `defaultValue` prop to another value does not have any effect. | ||
|
|
||
| ```js | ||
| // Here we manually set the default value | ||
| <UseField path="user.firstName" defaultValue="John" /> | ||
| ``` | ||
|
|
||
| ### In the form `defaultValue` config passed to `useForm()` | ||
|
|
||
| The above solution works well for very small forms, but with larger form it is not very convenient to manually add the default value of each field. | ||
|
|
||
| ```js | ||
| // Let's imagine some data coming from the server | ||
| const fetchedData = { | ||
| user: { | ||
| firstName: 'John', | ||
| lastName: 'Snow', | ||
| } | ||
| } | ||
|
|
||
| // We need to manually write each connection, which is not convenient | ||
| <UseField path="user.firstName" defaultValue={fetchedData.user.firstName} /> | ||
| <UseField path="user.lastName" defaultValue={fetchedData.user.lastName} /> | ||
| ``` | ||
|
|
||
| It is much easier to provide the `defaultValue` object (probably some data that we have fetched from the server) at the form level | ||
|
|
||
| ```js | ||
| const { form } = useForm({ defaultValue: fetchedData }); | ||
|
|
||
| // And the defaultValue for each field will be automatically mapped to its paths | ||
| <UseField path="user.firstName" /> | ||
| <UseField path="user.lastName" /> | ||
| ``` | ||
|
|
||
| ### In the field `defaultValue` config parameter of the field config | ||
|
|
||
| When you are creating a new resource, the form is empty and there is no data coming from the server to map. You still might want to define a default value for your fields. | ||
|
|
||
| ```js | ||
| interface Props { | ||
| fetchedData?: { index: boolean } | ||
| } | ||
|
|
||
| export const MyForm = ({ fetchedData }: Props) => { | ||
| // fetchedData can be "undefined" or an object. | ||
| // If it is undefined, then the config.defaultValue will be used | ||
| const { form } = useForm({ defaultValue: fetchedData }); | ||
|
|
||
| return ( | ||
| <UseField path="index" config={{ defaultValue: true } /> | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| Or the same but using a form schema | ||
|
|
||
| ```js | ||
| const schema = { | ||
| // Field config for the path "index" declared below | ||
| index: { | ||
| defaultValue: true, | ||
| }, | ||
| }; | ||
|
|
||
| export const MyComponent = ({ fetchedData }: Props) => { | ||
| // 1. If defaultValue is not undefined **and** there is a value at the "index" path, use it | ||
| // 2. otherwise if there is a schema with a config at the "index" path read its "defaultValue" | ||
| // 3. if it's still undefined, use an "" (empty string) - which will throw an error for a checkbox field-. | ||
| const { form } = useForm({ schema, defaultValue: fetchedData }); | ||
|
|
||
| return ( | ||
| <UseField path="index" /> | ||
| ); | ||
| } | ||
| ``` |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.