import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks'
import * as FormStories from './Form.stories'

<Meta of={FormStories} />

# Form

The fields and the button that sends them. Enter in a field, or a submit
button, sends it; the page never reloads; while it sends, everything inside
is switched off at once.

<Canvas of={FormStories.WhileSending} />

## When

- Any set of fields that is sent: a dialog's fields, a one-line field with
  its button, a composer.
- **`busy`** while the sending is waited on.

## When not

- One field that saves itself as you leave it → **EditableText**.
- A field that filters a list as you type → **SearchInput**; nothing is sent.

A `Field`, `TextInput` or `Textarea` with no `Form` around it is refused by
the gate (`estiva/no-field-outside-a-form`). A question with a field in it is
**DialogShell** with a form, never **ConfirmDialog**.

## How

```tsx
import { Button, Field, Form, TextInput } from '@estiva-app/ui'

<Form onSubmit={send} busy={sending}>
  <Field label="Title" required error={titleError}>
    <TextInput value={title} onChange={(e) => { setTitle(e.target.value); setTitleError(undefined) }} />
  </Field>
  <Button variant="primary" type="submit">Send</Button>
</Form>
```

- **`onSubmit` takes nothing.** The page's own submit is already prevented;
  there is no event to stop. Every way of sending — Enter, Ctrl+Enter, a
  submit button — arrives here the same way, after the same field check.
- **`enterSends={false}`** keeps Enter in a one-line field from sending, where
  only Ctrl+Enter may: a form inside **CommandPalette**, which uses it.
- **`busy` switches off every field and button inside**, so they do not
  each need `disabled={busy}`. A button outside the form that sends it —
  a dialog's footer, with `form="<id>"` and the form's `id` — is outside,
  and keeps its own `disabled`.
- **Focus waits on the form while it is busy.** A browser drops focus to the
  page the moment the focused field is switched off; the form holds it
  instead. When `busy` ends, focus goes to the first field showing an error,
  else back to what sent the form, else to the first control. If focus was
  moved somewhere else while it waited, it stays there.
- **A field showing its `error` stops the form from sending**, and Enter moves
  focus to that field instead (Base UI checks every field before it sends).
  Clear the error when the field changes, as in the example; an error left
  standing keeps the form from ever sending.
- The browser's own validation bubbles are off (`noValidate`). `Field`'s
  `required` marks a field; it does not block sending by itself.
- **The form places its fields: one column, 24px apart** (Katerina, 28
  September), so every form reads the same. Pass no layout of your own: the
  gate lint refuses a gap, a direction or a grid on a `Form`. `className`
  still places the form itself: its space around, its size.
- **Words before the fields go inside the form**, as one block (a title and
  its sentence, 8px apart): the form then puts the same 24px between them
  and the first field. A box of your own around the words and the form, with
  its own gap, sets that space instead, and the gate lint refuses it
  (Katerina, 1 October: Archive read 12px where Move read 24px).
- **`layout="free"`** is for a form that is not a list of fields: a field and
  its button, a composer. It places nothing, and `className` lays it out.
- The form draws no box, and neither does the `<fieldset>` inside it.

## What it owns

It does these by itself. Write none of them around it.

| It does | So you never write | Refused when written by hand |
|---|---|---|
| Sends on Enter in a one-line field, and on Ctrl+Enter anywhere inside | a key handler that submits |  |
| Leaves Enter alone where it means something else: a Textarea, a list, a people picker | exceptions of your own |  |
| Does nothing while it is sending: no second send, and nothing inside takes focus | a busy flag on every control |  |
| Stacks its fields in one column, 24px apart | a gap, a direction or a grid on the form | `no-restyled-part` |
| Puts 24px between the words before the fields and the first one | a spaced box around the words and the form | `no-restyled-part` |

## Keys

The same in every form.

| Key | Does |
|---|---|
| Enter, in a one-line field | Sends the form — with or without a submit button, however many fields. Not with `enterSends={false}`. |
| Shift+Enter or Alt+Enter, in a one-line field | Nothing — the browser would send the form on its own; the form stops it. |
| Enter, in a Textarea | A new line; it does not send. |
| Enter, in a list or a people picker | Picks; it does not send. |
| Enter, in a field that handles Enter itself | What the field does; the form does not send. |
| Ctrl+Enter (Cmd+Enter), anywhere inside | Sends the form. |
| Any of these, while busy | Nothing: a form that is sending does not send again. |
| Tab, while busy | Nothing inside takes focus. |

## Props

<Controls of={FormStories.Default} />
