import { ExampleCodeBlock, Specifications, SymbolDoc } from '@workday/canvas-kit-docs';
import Basic from './examples/Basic';
import Alert from './examples/Alert';
import Error from './examples/Error';
import Disabled from './examples/Disabled';
import HiddenLabel from './examples/HiddenLabel';
import LabelPositionHorizontalStart from './examples/LabelPositionHorizontalStart';
import LabelPositionHorizontalEnd from './examples/LabelPositionHorizontalEnd';
import RefForwarding from './examples/RefForwarding';
import Required from './examples/Required';
import Custom from './examples/Custom';
import CustomId from './examples/CustomId';
import AllFields from './examples/AllFields';
import Hint from './examples/Hint';
import Grow from './examples/Grow';
import ThemedError from './examples/ThemedErrors';
import GroupedInputs from './examples/GroupedInputs';


# Canvas Kit Form Field

FormField allows users to wrap input components to make them accessible. You can customize the field
by passing in `TextInput`, `Select`, `RadioGroup` and other form elements to `FormField.Input`.

## Installation

```sh
yarn add @workday/canvas-kit-react
```

## Accessibility

The `FormField` adds a `for` attribute to the `FormField.Label` (`<label>` element) element that
matches the `id` attribute of the `FormField.Input` which is usually a `input` element. This both
labels the input for screen readers and other assitive technology as well as will focus on the input
when the user clicks on the label. If your form field input component is more complicated, the
`FormField` will also add an `id` to the `FormField.Label` and an `aria-labelledby` to the
`FormField.Input` component. You can then forward the `aria-labelledby` to whatever elements you
need for the proper accessibility.

For example, the DOM will look something like this:

```html
<div>
  <label id="label-abc" for="input-abc">First Name</label>
  <input id="input-abc" aria-labelledby="label-abc" />
</div>
```

Some components, like `MultiSelect`, have an additional `role=listbox` element that also needs to
link to the `label` element. The resulting DOM will look something like:

```html
<div>
  <label id="label-abc" for="input-abc">States you've lived in</label>
  <input id="input-abc" aria-labelledby="label-abc" role="combobox" ... />
  <ul role="listbox" aria-labelledby="label-abc">
    <li>Texas</li>
    <li>California</li>
  </ul>
</div>
```

The `MultiSelect` component gets the `aria-labelledby` from the `FormField.Input` and forwards it to
both the `input[role=combobox]` element and the `ul[role=listbox]` element so the screen reader
knows the label for both is "States you've lived in".

## Usage

### Basic

Form Field should be used in tandem with most Canvas Kit input components to ensure they meet
accessibility standards. The orientation of the label by default is `vertical`.

<ExampleCodeBlock code={Basic} />

### Error States

Set the `error` prop of the Form Field or define it in the model to indicate it has an error.
`error` accepts the following values:

`"error" | "alert" | undefined`

### Alert

Use the alert state when a value is valid but there is additional information.

<ExampleCodeBlock code={Alert} />

### Error

Use the error state when the value is no longer valid.

<ExampleCodeBlock code={Error} />

### Disabled

Set the `disabled` prop of `FormField.Input` to prevent users from interacting with it.

<ExampleCodeBlock code={Disabled} />

### Hint

Use `FormField.Hint` to display a short message below the input component and `FormField.Field` to
ensure proper alignment.

<ExampleCodeBlock code={Hint} />

### Label Position

Set the `orientation` prop of the Form Field to designate the position of the label relative to the
input component. By default, the orientation will be set to `vertical`. If you want your label to be
horizontal, you have two options: `horizontalStart` and `horizontalEnd`.

If you want the position of the label at the start of the container, set orientation prop to
`horizontalStart`.

<ExampleCodeBlock code={LabelPositionHorizontalStart} />

If you want the position of the label at the end of the container, set orientation prop to
`horizontalEnd`.

<ExampleCodeBlock code={LabelPositionHorizontalEnd} />

### Grow

Set the `grow` prop of the Form Field to `true` to configure it (including the wrapped input
component) to expand to the width of its container.

**Note: This Prop is deprecated and will be removed in a future major version.**

<ExampleCodeBlock code={Grow} />

### Ref Forwarding

If you need full customization you can use the `FormField` behavior hooks to build your own
solution. It is also easy it work with custom components or third party libraries and get the CKR
accessibility guarantees by using the `as` prop.

<ExampleCodeBlock code={RefForwarding} />

### Required

Set the `isRequired` prop of the Form Field to `true` to indicate that the field is required. Labels
for required fields are suffixed by a red asterisk.

<ExampleCodeBlock code={Required} />

### Grouped Inputs

Use `FormFieldGroup` when you have a group of inputs that need to be associated to one another, like
`RadioGroup` or a group of `Checkbox`'s. `FormFieldGroup` renders a `fieldset` element and
`FormFieldGroup.Label` renders a `legend` element. These elements will allow for correct
accessibility of grouped inputs.

`FormFieldGroup` supports the same props of `FormField`:

- `error`: `"alert" | "error"` Defines the error around the whole group of inputs.
- `orientation`: `"horizontal" | "vertical"` Defines the legend placement.
- `isRequired`: `true` Defines if a group like RadioGroup is required.

<ExampleCodeBlock code={GroupedInputs} />

### Custom

If you need full customization you can use the `FormField` behavior hooks to build your own
solution. It is also easy it work with custom components or third party libraries and get the CKR
accessibility guarantees by using the `as` prop.

<ExampleCodeBlock code={Custom} />

### Custom id

Form Field will automatically generate an HTML `id` for its input element to link it to the
correponding label. Alternatively, you may set the `id` prop of the Form Field to specify a custom
`id` for the input element. The `id` will be appended by `input-${your-unique-id}`.

<ExampleCodeBlock code={CustomId} />

### All Fields

Form Field should allow you to use it with all `inputs` including `Select`, `TextInput`, `Checkbox`,
`TextArea`, `Switch`, and `RadioGroup`.

<ExampleCodeBlock code={AllFields} />

### Hidden Label

In cases where you want to hide the label while still meeting accessibility standards, you can add
`isHidden` on the `<FormField.Label/>`. This prop will visually hide the label.

<ExampleCodeBlock code={HiddenLabel} />

### Themed Errors

You can theme your error rings by wrapping an input in a `CanvasProvider` and defining
`focusOutline` and `error` properties on the `theme`.

<ExampleCodeBlock code={ThemedError} />

### Custom Styles

Form Field and its subcomponents support custom styling via the `cs` prop. For more information,
check our
["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-how-to-customize-styles--docs).

## Component API

<SymbolDoc name="FormField" />

## Specifications

<Specifications file="FormField.spec.tsx" name="FormField" />