mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Add FieldArray component (#26993)
This commit is contained in:
parent
58627a0c38
commit
c730e659e3
40
packages/grafana-ui/src/components/Forms/FieldArray.mdx
Normal file
40
packages/grafana-ui/src/components/Forms/FieldArray.mdx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Meta, Props } from '@storybook/addon-docs/blocks';
|
||||||
|
import { FieldArray } from './FieldArray';
|
||||||
|
|
||||||
|
<Meta title="MDX|FieldArray" component={FieldArray} />
|
||||||
|
|
||||||
|
# FieldArray
|
||||||
|
|
||||||
|
`FieldArray` provides a way to render a list of dynamic inputs. It exposes the functionality of `useFieldArray` in [react-hook-form](https://react-hook-form.com/advanced-usage/#FieldArrays). `FieldArray` must be wrapped at some level by a `<Form>` element.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { Form, FieldArray } from '@grafana/ui';
|
||||||
|
|
||||||
|
<Form>
|
||||||
|
({control, register}) => (
|
||||||
|
<FieldArray control={control} name="People">
|
||||||
|
{({ fields, append }) => (
|
||||||
|
<div>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<div key={field.id}>
|
||||||
|
<Input key={index} ref={register()} name=`people[${index}].firstName` value={field.firstName} />
|
||||||
|
<Input ref={register()} name=`people[${index}].lastName` value={field.lastName} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Button onClick={() => append({firstName: 'Roger', lastName: 'Waters'})}>Append</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</FieldArray>
|
||||||
|
)
|
||||||
|
</Form>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### FieldArray API
|
||||||
|
|
||||||
|
The `FieldArray` component exposes its API via render prop. Properties exposed are: `fields`, `append`, `prepend`, `remove`, `swap`, `move`, `insert`
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
<Props of={FieldArray} />
|
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
|
import { withStoryContainer } from '../../utils/storybook/withStoryContainer';
|
||||||
|
import { Form, Input, Button, HorizontalGroup } from '@grafana/ui';
|
||||||
|
import { FieldArray } from './FieldArray';
|
||||||
|
import mdx from './FieldArray.mdx';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Forms/FieldArray',
|
||||||
|
component: FieldArray,
|
||||||
|
decorators: [withStoryContainer, withCenteredStory],
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
page: mdx,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const simple = () => {
|
||||||
|
const defaultValues = {
|
||||||
|
people: [{ firstName: 'Janis', lastName: 'Joplin' }],
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Form onSubmit={values => console.log(values)} defaultValues={defaultValues}>
|
||||||
|
{({ control, register }) => (
|
||||||
|
<div>
|
||||||
|
<FieldArray control={control} name="people">
|
||||||
|
{({ fields, append }) => (
|
||||||
|
<>
|
||||||
|
<div style={{ marginBottom: '1rem' }}>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<HorizontalGroup key={field.id}>
|
||||||
|
<Input ref={register()} name={`people[${index}].firstName`} value={field.firstName} />
|
||||||
|
<Input ref={register()} name={`people[${index}].lastName`} value={field.lastName} />
|
||||||
|
</HorizontalGroup>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
style={{ marginRight: '1rem' }}
|
||||||
|
onClick={() => append({ firstName: 'Roger', lastName: 'Waters' })}
|
||||||
|
>
|
||||||
|
Add another
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</FieldArray>
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
};
|
15
packages/grafana-ui/src/components/Forms/FieldArray.tsx
Normal file
15
packages/grafana-ui/src/components/Forms/FieldArray.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { useFieldArray, UseFieldArrayProps } from 'react-hook-form';
|
||||||
|
import { FieldArrayApi } from '../../types';
|
||||||
|
|
||||||
|
export interface FieldArrayProps extends UseFieldArrayProps {
|
||||||
|
children: (api: FieldArrayApi) => JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FieldArray: FC<FieldArrayProps> = ({ name, control, children }) => {
|
||||||
|
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
|
||||||
|
control,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
return children({ fields, append, prepend, remove, swap, move, insert });
|
||||||
|
};
|
@ -1,7 +1,19 @@
|
|||||||
import { FormContextValues } from 'react-hook-form';
|
import { FormContextValues, FieldValues, ArrayField } from 'react-hook-form';
|
||||||
export { OnSubmit as FormsOnSubmit, FieldErrors as FormFieldErrors } from 'react-hook-form';
|
export { OnSubmit as FormsOnSubmit, FieldErrors as FormFieldErrors } from 'react-hook-form';
|
||||||
|
|
||||||
export type FormAPI<T> = Pick<
|
export type FormAPI<T> = Pick<
|
||||||
FormContextValues<T>,
|
FormContextValues<T>,
|
||||||
'register' | 'errors' | 'control' | 'formState' | 'getValues' | 'watch'
|
'register' | 'errors' | 'control' | 'formState' | 'getValues' | 'watch'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
type FieldArrayValue = Partial<FieldValues> | Array<Partial<FieldValues>>;
|
||||||
|
|
||||||
|
export interface FieldArrayApi {
|
||||||
|
fields: Array<Partial<ArrayField<FieldValues, 'id'>>>;
|
||||||
|
append: (value: FieldArrayValue) => void;
|
||||||
|
prepend: (value: FieldArrayValue) => void;
|
||||||
|
remove: (index?: number | number[]) => void;
|
||||||
|
swap: (indexA: number, indexB: number) => void;
|
||||||
|
move: (from: number, to: number) => void;
|
||||||
|
insert: (index: number, value: FieldArrayValue) => void;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user