import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import { Input, Flexbox, OldIcon, Typography } from '../../..';
import Renderers from './Renderers.png';
import { PseudoComponentWithPropsConsistingOfContext } from './lib/context.ts';

<Meta component={Input.Select} />

# Input.Select

<ArgsTable height={200} of={Input.Select} />

## General Info

This component is build using statecharts.

### User stories:

1. When user clicks (or using the keyboard) on some trigger area, list of options appears
1. If user clicks outside, list hides
1. When user hovers/changing focus on items in list, they appears focused
1. When user presses up/down, the next/previous list item gets highlighted/focused
1. When user clicks an item in the list, different things can happen:
   - If the item was selected before and this is single select component, do nothing
   - If the item was selected before and this is multi select component, unselect the item
   - If the item was not selected before and this is single select component, select the item, hide list of options
   - If the item was not selected before and this is multi select component, select the item

### Contexts (where the component can live):

1. Inside a form
1. Standalone component

## Architecture

1. OnChange and value
1. Customizable renderers (visuals)

### OnChange and value

**value** of the Input.Select is _always_ an array of objects, which corresponds to the `options` you provided to the component.
The onChange will be called with the new **value**, again, an array of selected options.
This allows to have the same api for multi- and single- selects.

The options passed to `value` will be checked with `options` first by referential equality and then by `option.value` equality.

### Renderers:

<Typography type="primary">
  <Flexbox container>
    <Flexbox item>
      <img src={Renderers} />
    </Flexbox>
    <Flexbox item container>
      <Flexbox container direction="column">
        <Flexbox item container alignItems="center" gap={2}>
          <OldIcon.SolidCircle color={(t) => 'rgb(255,147,1)'} /> FormField
        </Flexbox>
        <Flexbox item container alignItems="center" gap={2}>
          <OldIcon.SolidCircle color={(t) => 'rgb(25,25,255)'} /> SelectedValue
        </Flexbox>
        <Flexbox item container alignItems="center" gap={2}>
          <OldIcon.SolidCircle color={(t) => 'rgb(255,25,1)'} /> List
        </Flexbox>
        <Flexbox item container alignItems="center" gap={2}>
          <OldIcon.SolidCircle color={(t) => 'rgb(25,100,25)'} /> ListItem
        </Flexbox>
      </Flexbox>
    </Flexbox>
  </Flexbox>
</Typography>

You can redefine `SelectedValue`, `List` and `ListItem` renderers using `components` prop.
Also, there is always hidden `Search` component, which becomes visible if you pass `showSearch` prop.
You can redefine that one as well.

Every renderer has type:

```typescript
type ListItem = ({ index }: { index: number }) => React.ReactNode;
```

```typescript
type List = ({
  children,
  position,
  searchComponent,
}: {
  children: React.ReactNode;
  position: 'left' | 'right' | 'middle';
  searchComponent: React.ReactNode;
}) => React.ReactNode;
```

```typescript
type SelectedValue = () => React.ReactNode;
```

```typescript
// Search needs ref, since it is always in focus
type Search = (_, ref) => React.ReactNode;
```

When writing custom renderers, use hook to grab state chart's state from context:

```js
const { useSelectMachineFromContext } = Input.Select;
const [state] = useSelectMachineFromContext();
```

### State type

<ArgsTable of={PseudoComponentWithPropsConsistingOfContext} />

Example:

```jsx
const ListItemRenderer = (props) => <div>Hey there {props.index}</div>;
```

```jsx
<Input.Select
  components={{
    ListItem: ListItemRenderer,
  }}
  options={[
    { label: '1', value: 1 },
    { label: '2', value: 2 },
  ]}
/>
```

<Input.Select
  id="demo-1"
  components={{
    ListItem: (props) => <div>Hey there {props.index}</div>,
  }}
  options={[
    { label: '1', value: 1 },
    { label: '2', value: 2 },
  ]}
/>

You can also _hide_ **FormField** with `noFormField` prop, but then you need to redefine **SelectedValue** renderer
