Commit c730e659 by Russ Committed by GitHub

Add FieldArray component (#26993)

parent 58627a0c
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} />
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>
);
};
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 });
};
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 type FormAPI<T> = Pick<
FormContextValues<T>,
'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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment