import { useState } from 'react';
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';

import {
  Toolbar,
  ToolbarIconButton,
  ToolbarLabel,
  ToolbarButton,
} from '@devseed-ui/toolbar';

import {
  CollecticonTrashBin,
  CollecticonXmarkSmall,
  CollecticonCircleInformation,
} from '@devseed-ui/collecticons';

import {
  Form,
  FormGroup,
  FormGroupHeader,
  FormLabel,
  FormGroupBody,
  FormInput,
  FormTextarea,
  FormSelect,
  FormCheckable,
  FormCheckableGroup,
  FormSwitch,
  FormHelper,
  FormHelperMessage,
  FormHelperCounter,
  FormFieldset,
  FormFieldsetHeader,
  FormLegend,
  FormFieldsetBody,
  FormGroupFooter,
  FormGroupStructure,
} from './';

<Meta title="Components/Form" />

# Form

The `form` package provides a series of components that can be used to compose forms.  
All the base components are available for usage, but this package also provides more complex components which take care of setting up a recommended structure.

```
yarn add @devseed-ui/form
```

```js
import {
  Form,

  FormGroup,
  FormGroupHeader,
  FormLabel,
  FormGroupBody,
  FormGroupFooter,
  FormGroupStructure,

  FormHelper,
  FormHelperMessage,
  FormHelperCounter,

  FormFieldset,
  FormFieldsetHeader,
  FormLegend,
  FormFieldsetBody,

  FormCheckable,
  FormCheckableGroup,

  FormInput,
  FormSelect,
  FormTextarea,
  FormSwitch
} from '@devseed-ui/form';
```

## Structure

Each form field should be wrapped in a `FormGroup`. This adds some wrapper elements that help with styling and ensure consistency.  
For accessibility purposes it is recommended that every form element has a `FormGroupHeader` with `FormLabel`. The `FormGroupHeader`, can be hidden if needed, via the `isHidden` prop.

<Canvas>
  <Story
    name="Base structure"
    argTypes={{
      hideFormHeader: {
        name: 'isHidden',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description: 'Whether or not to visually hide the FormGroupHeader',
        table: {
          category: 'Form Group Header',
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
    }}
  >
    {args => (
      <FormGroup>
        <FormGroupHeader isHidden={args.hideFormHeader}>
          <FormLabel>Form label</FormLabel>
        </FormGroupHeader>
        <FormGroupBody>Body content where the form field goes</FormGroupBody>
        <FormGroupFooter>Footer content</FormGroupFooter>
      </FormGroup>
    )}
  </Story>
</Canvas>

<ArgsTable story="Base structure" />

### Form label

<Canvas>
  <Story
    name="Form label"
    argTypes={{
      optional: {
        name: 'optional',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description: 'Display an (optional) hint',
        table: {
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
      required: {
        name: 'required',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description: 'Display a (required) hint. Overrides the optional hint',
        table: {
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
      hint: {
        name: 'hint',
        type: { name: 'node', required: false },
        defaultValue: undefined,
        description: 'Display a custom hint. Overrides the required hint',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: {
          type: 'text',
        },
      },
    }}
  >
    {args => <FormLabel {...args}>Form label</FormLabel>}
  </Story>
</Canvas>

<ArgsTable story="Form label" />

## Form Structure component

To facilitate the setup of the structure above, the `FormGroupStructure` wraps all that in a single component

<Canvas>
  <Story
    name="Form group structure"
    argTypes={{
      id: {
        name: 'id',
        type: { name: 'node', required: true },
        defaultValue: 'form-structure',
        description:
          "Value for the label's htmlFor attribute. Prop passed to the `FormLabel`. **Must match the `id` of the input field.**",
        table: {
          type: { summary: 'text' },
          defaultValue: { summary: undefined },
        },
        control: {
          type: 'text',
        },
      },
      label: {
        name: 'label',
        type: { name: 'node', required: true },
        defaultValue: 'Field label',
        description: 'Value for the label',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: {
          type: 'text',
        },
      },
      optional: {
        name: 'optional',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description:
          'Display an (optional) hint. Prop passed to the `FormLabel`',
        table: {
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
      required: {
        name: 'required',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description:
          'Display a (required) hint. Overrides the optional hint. Prop passed to the `FormLabel`',
        table: {
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
      hint: {
        name: 'hint',
        type: { name: 'node', required: false },
        defaultValue: undefined,
        description:
          'Display a custom hint. Overrides the required hint. Prop passed to the `FormLabel`',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: {
          type: 'text',
        },
      },
      isHidden: {
        name: 'isHidden',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description:
          'Whether or not to visually hide the `FormGroupHeader`. Prop passed to the `FormGroupHeader`',
        table: {
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
      toolbar: {
        name: 'toolbar',
        type: { name: 'node', required: false },
        defaultValue: undefined,
        description:
          'Space to render a Toolbar. Will be rendered in the `FormGroupHeader` after `FormLabel`. Should be a `Toolbar` component.',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: null,
      },
      children: {
        name: 'children',
        type: { name: 'node', required: false },
        defaultValue: 'undefined',
        description:
          'The children of `FormGroupStructure` should be the actual form element',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: null,
      },
      helper: {
        name: 'helper',
        type: { name: 'node', required: false },
        defaultValue: undefined,
        description: 'Content rendered inside `FormHelper`. See info below.',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: null,
      },
      footerContent: {
        name: 'footerContent',
        type: { name: 'node', required: false },
        defaultValue: undefined,
        description: 'Content for the `FormGroupFooter`',
        table: {
          type: { summary: 'react node' },
          defaultValue: { summary: undefined },
        },
        control: {
          type: 'text',
        },
      },
    }}
  >
    {args => (
      <Form>
        <FormGroupStructure {...args}>Form element</FormGroupStructure>
      </Form>
    )}
  </Story>
</Canvas>

<ArgsTable story="Form group structure" />

## Form helper

There are 3 components related to Form helper:

- `FormHelper` - The wrapper where the helper components are rendered. If using `FormGroupStructure` this wrapper is already present when using `helper` prop.
- `FormHelperMessage` - Helper message.
- `FormHelperCounter` - Counter component, shown on the right. Useful for text based inputs. Will change color as the `value` reaches the `max`.

<Canvas>
  <Story
    name="Form helper"
    argTypes={{
      invalidMessage: {
        name: 'invalid',
        type: { name: 'boolean', required: false },
        defaultValue: false,
        description: 'Whether or not the helper message is showing an error.',
        table: {
          category: 'Form Helper Message',
          type: { summary: 'boolean' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'boolean',
        },
      },
      message: {
        name: 'children',
        type: { name: 'node', required: false },
        defaultValue: 'This message provides some help. Hopefully!',
        description: 'The message to display',
        table: {
          category: 'Form Helper Message',
          type: { summary: 'react node' },
          defaultValue: { summary: false },
        },
        control: {
          type: 'text',
        },
      },
      counterValue: {
        name: 'value',
        type: { name: 'number', required: true },
        defaultValue: 10,
        description: 'The current value to show on the counter',
        table: {
          category: 'Form Helper Counter',
          type: { summary: 'number' },
          defaultValue: { summary: null },
        },
        control: {
          type: 'number',
        },
      },
      counterMax: {
        name: 'max',
        type: { name: 'number', required: true },
        defaultValue: 20,
        description: 'The max value to show on the counter',
        table: {
          category: 'Form Helper Counter',
          type: { summary: 'number' },
          defaultValue: { summary: null },
        },
        control: {
          type: 'number',
        },
      },
      counterWarnAt: {
        name: 'warnAt',
        type: { name: 'number', required: false },
        defaultValue: undefined,
        description: 'The value at which the counter color changes to warning.',
        table: {
          category: 'Form Helper Counter',
          type: { summary: 'number' },
          defaultValue: { summary: '90% of max' },
        },
        control: {
          type: 'number',
        },
      },
    }}
  >
    {args => (
      <FormHelper>
        <FormHelperMessage invalid={args.invalidMessage}>
          {args.message}
        </FormHelperMessage>
        <FormHelperCounter
          value={args.counterValue}
          max={args.counterMax}
          warnAt={args.counterWarnAt}
        />
      </FormHelper>
    )}
  </Story>
</Canvas>

<ArgsTable story="Form helper" />

export const invalidArg = {
  name: 'invalid',
  type: { name: 'boolean', required: false },
  defaultValue: false,
  description: 'Whether or not the value in this field is invalid',
  table: {
    type: { summary: 'boolean' },
    defaultValue: { summary: false },
  },
  control: {
    type: 'boolean',
  },
};

export const baseInputArgs = {
  size: {
    name: 'size',
    type: { name: 'text', required: false },
    defaultValue: 'medium',
    description: 'Size of the input field',
    options: ['small', 'medium', 'large', 'xlarge'],
    table: {
      type: { summary: 'string' },
      defaultValue: { summary: 'medium' },
    },
    control: {
      type: 'select',
    },
  },
  invalid: invalidArg,
  stressed: {
    name: 'stressed',
    type: { name: 'boolean', required: false },
    defaultValue: false,
    description:
      'A stressed input will animate to call attention. It is useful to notify of errors.',
    table: {
      type: { summary: 'boolean' },
      defaultValue: { summary: false },
    },
    control: {
      type: 'boolean',
    },
  },
};

## Form Input

The `FormInput` is a styled-component version on `<input>` therefore the standard html attributes for this element are available.

<Canvas>
  <Story name="Form input" argTypes={baseInputArgs}>
    {args => (
      <FormGroupStructure label="Input for something" id="input-something">
        <FormInput
          placeholder="Placeholder of the input"
          id="input-something"
          {...args}
        />
      </FormGroupStructure>
    )}
  </Story>
</Canvas>

<ArgsTable story="Form input" />

## Form Textarea

The `FormTextarea` is a styled-component version on `<textarea>` therefore the standard html attributes for this element are available.

<Canvas>
  <Story name="Form textarea" argTypes={baseInputArgs}>
    {args => (
      <FormGroupStructure label="A longer message" id="input-textarea">
        <FormTextarea
          placeholder="Placeholder of the textarea"
          id="input-textarea"
          {...args}
        />
      </FormGroupStructure>
    )}
  </Story>
</Canvas>

<ArgsTable story="Form textarea" />

## Form Select

The `FormSelect` is a styled-component version on `<select>` therefore the standard html attributes for this element are available.

<Canvas>
  <Story name="Form select" argTypes={baseInputArgs}>
    {args => (
      <FormGroupStructure label="A couple of options" id="input-selecting">
        <FormSelect id="input-selecting" {...args}>
          <option value="option-1">Option 1</option>
          <option value="option-2">Option 2</option>
          <option value="option-3">Option 3</option>
          <option value="option-4">Option 4</option>
        </FormSelect>
      </FormGroupStructure>
    )}
  </Story>
</Canvas>

<ArgsTable story="Form select" />

export const checkableBaseArgs = {
  children: {
    name: 'children',
    type: { name: 'node', required: true },
    defaultValue: 'Here is some label',
    description: 'The label for this checkable',
    table: {
      type: { summary: 'react node' },
      defaultValue: { summary: null },
    },
    control: {
      type: 'text',
    },
  },
  textPlacement: {
    name: 'textPlacement',
    type: { name: 'string', required: true },
    defaultValue: 'right',
    description: 'Position of the checkable label',
    options: ['right', 'left'],
    table: {
      type: { summary: 'string' },
      defaultValue: { summary: 'right' },
    },
    control: {
      type: 'inline-radio',
    },
  },
  hideText: {
    name: 'hideText',
    type: { name: 'boolean', required: false },
    defaultValue: false,
    description: 'Whether or not to hide the checkable label',
    table: {
      type: { summary: 'boolean' },
      defaultValue: { summary: false },
    },
    control: {
      type: 'boolean',
    },
  },
};

export const checkableArgs = {
  type: {
    name: 'type',
    type: { name: 'string', required: true },
    defaultValue: 'checkbox',
    description: 'Type of checkable to use',
    options: ['checkbox', 'radio'],
    table: {
      type: { summary: 'string' },
      defaultValue: { summary: 'checkbox' },
    },
    control: {
      type: 'inline-radio',
    },
  },
  invalid: invalidArg,
  ...checkableBaseArgs,
};

## Form Checkable

Form checkables can be either `checkboxes` or `radio` buttons.

<Canvas>
  <Story name="Form checkable" argTypes={checkableArgs}>
    {args => (
      <FormCheckable
        name="example-checkable"
        id="example-checkable"
        {...args}
      />
    )}
  </Story>
</Canvas>

<ArgsTable story="Form checkable" />

### Form Checkable Group

When using multiple `FormCheckable` elements, they should be wrapped with `FormCheckableGroup`, for styling purposes.

<Canvas>
  <Story name="Form checkable group">
    <FormCheckableGroup>
      <FormCheckable
        textPlacement="right"
        checked={undefined}
        type="radio"
        name="radio-ex-a"
        id="radio-ex-a1"
      >
        Radio A
      </FormCheckable>
      <FormCheckable
        textPlacement="right"
        checked={undefined}
        type="radio"
        name="radio-ex-a"
        id="radio-ex-a2"
      >
        Radio B
      </FormCheckable>
      <FormCheckable
        textPlacement="right"
        checked={undefined}
        type="radio"
        name="radio-ex-a"
        id="radio-ex-a3"
      >
        Radio C
      </FormCheckable>
      <FormCheckable
        textPlacement="right"
        checked={undefined}
        type="radio"
        name="radio-ex-a"
        id="radio-ex-a4"
      >
        Radio D
      </FormCheckable>
    </FormCheckableGroup>
  </Story>
</Canvas>

## Form Switch

A variation on the `FormCheckable` for on/off situations.

<Canvas>
  <Story name="Form switch" argTypes={checkableBaseArgs}>
    {args => <FormSwitch name="example-switch" id="example-switch" {...args} />}
  </Story>
</Canvas>

<ArgsTable story="Form switch" />

## Form Fieldset

A form fieldset is useful to group form elements, and they can be nested.

<Canvas>
  <Story name="Form fieldset">
    {args => (
      <FormFieldset>
        <FormFieldsetHeader>
          <FormLegend>Form legend</FormLegend>
        </FormFieldsetHeader>
        <FormFieldsetBody>
          <p>A form fieldset is useful to contain other form elements.</p>
          <FormFieldset>
            <FormFieldsetHeader>
              <FormLegend>Form legend</FormLegend>
            </FormFieldsetHeader>
            <FormFieldsetBody>
              <p>A fieldset can also contain another fieldset.</p>
            </FormFieldsetBody>
          </FormFieldset>
        </FormFieldsetBody>
      </FormFieldset>
    )}
  </Story>
</Canvas>

## Example: text input

Example of using a `FormGroupStructure` with helper messages and the inclusion of a toolbar from the Toolbar package.

<Canvas>
  <Story
    name="Example: text input"
    parameters={{
      docs: {
        source: {
          type: 'code',
        },
      },
    }}
  >
    {args => {
      const [value, setValue] = useState('');
      return (
        <FormGroupStructure
          label="First name"
          id="first-name"
          required
          toolbar={
            <Toolbar size="small">
              <ToolbarIconButton
                title="Clear field"
                onClick={() => setValue('')}
              >
                <CollecticonTrashBin title="Clear field" meaningful />
              </ToolbarIconButton>
            </Toolbar>
          }
          helper={
            <>
              <FormHelperMessage invalid={value.length > 10}>
                {value.length > 10
                  ? 'Your name must have fewer than 10 characters.'
                  : 'Come on. Let us know what we should call you.'}
              </FormHelperMessage>
              <FormHelperCounter value={value.length} max={10} />
            </>
          }
        >
          <FormInput
            placeholder="Write your name"
            id="first-name"
            type="text"
            value={value}
            onChange={e => setValue(e.target.value)}
          />
        </FormGroupStructure>
      );
    }}
  </Story>
</Canvas>

## Showcase

<Canvas>
  <Story name="Showcase">
    <Form>
      <FormFieldset>
        <FormFieldsetHeader>
          <FormLegend>Form legend with a toolbar</FormLegend>
          <Toolbar>
            <ToolbarIconButton>
              <CollecticonXmarkSmall title="Close" meaningful />
            </ToolbarIconButton>
          </Toolbar>
        </FormFieldsetHeader>
        <FormFieldsetBody>
          <FormGroupStructure
            label="Form label"
            id="input-text-a"
            required
            toolbar={
              <Toolbar size="small">
                <ToolbarIconButton>
                  <CollecticonCircleInformation
                    title="View more information"
                    meaningful
                  />
                </ToolbarIconButton>
              </Toolbar>
            }
            helper={
              <>
                <FormHelperMessage invalid>
                  This is an error message.
                </FormHelperMessage>
                <FormHelperCounter value={0} max={80} />
              </>
            }
          >
            <FormInput
              type="text"
              size="large"
              id="input-text-a"
              placeholder="This is a text input"
              invalid
            />
          </FormGroupStructure>
          <FormGroupStructure
            label="Form label"
            id="checkboxes"
            toolbar={
              <Toolbar size="small">
                <ToolbarLabel>Select</ToolbarLabel>
                <ToolbarButton>All</ToolbarButton>
                <ToolbarButton>None</ToolbarButton>
              </Toolbar>
            }
          >
            <FormCheckableGroup>
              <FormCheckable
                checked={undefined}
                type="checkbox"
                name="checkbox-a"
                id="checkbox-a"
              >
                Checkbox A
              </FormCheckable>
              <FormCheckable
                checked={undefined}
                type="checkbox"
                name="checkbox-b"
                id="checkbox-b"
              >
                Checkbox B
              </FormCheckable>
            </FormCheckableGroup>
          </FormGroupStructure>
          <FormGroupStructure label="Form label" id="checkboxes">
            <FormCheckableGroup>
              <FormCheckable
                textPlacement="right"
                checked={undefined}
                type="radio"
                name="radio-a"
                id="radio-a1"
              >
                Radio A
              </FormCheckable>
              <FormCheckable
                textPlacement="right"
                checked={undefined}
                type="radio"
                name="radio-a"
                id="radio-a2"
              >
                Radio B
              </FormCheckable>
              <FormCheckable
                textPlacement="right"
                checked={undefined}
                type="radio"
                name="radio-a"
                id="radio-a3"
              >
                Radio C
              </FormCheckable>
              <FormCheckable
                textPlacement="right"
                checked={undefined}
                type="radio"
                name="radio-a"
                id="radio-a4"
              >
                Radio D
              </FormCheckable>
            </FormCheckableGroup>
          </FormGroupStructure>
          <FormFieldset>
            <FormFieldsetHeader>
              <FormLegend>Form legend</FormLegend>
              <Toolbar>
                <ToolbarIconButton>
                  <CollecticonTrashBin
                    title="Remove fieldset icon"
                    meaningful
                  />
                </ToolbarIconButton>
              </Toolbar>
            </FormFieldsetHeader>
            <FormFieldsetBody>
              <FormGroupStructure label="Form label" id="textarea-b">
                <FormTextarea
                  size="large"
                  id="textarea-b"
                  placeholder="This is a textarea"
                />
              </FormGroupStructure>
            </FormFieldsetBody>
          </FormFieldset>
          <FormGroupStructure
            label="Form label"
            id="select-a"
            optional
            helper={
              <FormHelperMessage>This is some help text.</FormHelperMessage>
            }
          >
            <FormSelect size="large" id="select-a">
              <option value="option-1">Option 1</option>
              <option value="option-2">Option 2</option>
              <option value="option-3">Option 3</option>
              <option value="option-4">Option 4</option>
            </FormSelect>
          </FormGroupStructure>
          <FormGroupStructure
            label="Form label"
            id="textarea-c"
            helper={
              <FormHelperMessage invalid>
                This is an error message.
              </FormHelperMessage>
            }
          >
            <FormTextarea
              size="large"
              id="textarea-c"
              placeholder="This is a textarea"
              invalid
            />
          </FormGroupStructure>
          <FormSwitch name="example-switch2" id="example-switch2">
            Enable this switch
          </FormSwitch>
        </FormFieldsetBody>
      </FormFieldset>
    </Form>
  </Story>
</Canvas>
