# MoleculeSelect

`MoleculeSelect` is a customized `select` created from a combination of `AtomInput`, `MoleculeInputTags`, `MoleculeDropdownList` and `MoleculeDropdownOption`

It allows Single and Multiple Selection

[![documentation](https://img.shields.io/badge/read%20the%20doc-black?logo=readthedocs)](https://sui-components.vercel.app/workbench/molecule/select/)
[![issue](https://img.shields.io/badge/report%20a%20bug-black?logo=openbugbounty&logoColor=red)](https://github.com/SUI-Components/sui-components/issues/new?&projects=4&template=bug-report.yml&assignees=&template=report-a-bug.yml&title=🪲+&labels=bug,component,molecule,select)
[![npm](https://img.shields.io/npm/dt/%40s-ui/react-molecule-select?logo=npm&labelColor=black)](https://www.npmjs.com/package/@s-ui/react-molecule-select)

[![Issues open](https://img.shields.io/github/issues-search/SUI-Components/sui-components?query=is%3Aopen%20label%3Acomponent%20label%3Aselect&logo=openbugbounty&logoColor=red&label=issues%20open&color=red)](https://github.com/SUI-Components/sui-components/issues?q=is%3Aopen+label%3Acomponent+label%3Aselect)
[![NPM](https://img.shields.io/npm/l/%40s-ui%2Freact-molecule-select)](https://github.com/SUI-Components/sui-components/blob/main/components/molecule/select/LICENSE.md)

## Installation

```sh
$ npm install @s-ui/react-molecule-select --save
```

## Usage

```js
import MoleculeSelect, {
  moleculeSelectDropdownListSizes
} from '@s-ui/react-molecule-select'
import MoleculeSelectOption from '@s-ui/react-molecule-dropdown-option'

const IconCloseTag = () => <span>x</span>
const IconArrowDown = () => <span>▼</span>

const options = ['John', 'Paul', 'George', 'Ringo']
```

### Single Selection

#### Basic usage

```js
<MoleculeSelect
  placeholder="Select a Country..."
  onChange={(_, {value}) => console.log(value)}
  iconArrowDown={<IconArrowDown />}
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

#### With default value

```js
<MoleculeSelect
  placeholder="Select a Country..."
  onChange={(_, {value}) => console.log(value)}
  iconArrowDown={<IconArrowDown />}
  value="John"
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

#### Large List

```js
<MoleculeSelect
  placeholder="Select a Country..."
  onChange={(_, {value}) => console.log(value)}
  iconArrowDown={<IconArrowDown />}
  size={moleculeSelectDropdownListSizes.LARGE}
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

#### With a search input

```js
<MoleculeSelect
  placeholder="Select a Country..."
  onChange={(_, {value}) => console.log(value)}
  iconArrowDown={<IconArrowDown />}
  hasSearch
  onSearch={({value}) => console.log(value)}
  searchPlaceholder="Search a country..."
  noResults={
    <div>
      No results found...
    </div>
  }
  size={moleculeSelectDropdownListSizes.LARGE}
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

#### With state highlight

Can be `success`, `error` or `alert`.

```js
<MoleculeSelect
  placeholder="Select a Country..."
  onChange={(_, {value}) => console.log(value)}
  iconArrowDown={<IconArrowDown />}
  state="success"
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

### Multiple Selection

#### Basic usage

```js
<MoleculeSelect
  iconCloseTag={<IconCloseTag />}
  iconArrowDown={<IconArrowDown />}
  multiselection
  value={['John', 'Paul']}
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

#### With selected items limit

```js
<MoleculeSelect
  iconCloseTag={<IconCloseTag />}
  iconArrowDown={<IconArrowDown />}
  multiselection
  value={['John', 'Paul']}
  max={2}
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelect>
```

## Managing State

### Custom component from `MoleculeSelect` that handle State

`MoleculeSelect` is a stateless component, so to manage dynamic options we need to create a wrapper component that manages this and pass proper `props` and proper children (`MoleculeSelectOption`) to `MoleculeSelect`

Example:

```js
import React, {Component} from 'react'

import MoleculeSelect from '@s-ui/react-molecule-select'
import MoleculeSelectOption from '@s-ui/react-molecule-dropdown-option'

const options = ['John', 'Paul', 'George', 'Ringo']

export default class SelectSingleWithAsyncOptions extends Component {
  state = {value: ''}

  onChange = async (e, {value}) => {
    this.setState({value})
  }

  render() {
    const {value} = this.state
    const {onChange, props} = this

    return (
      <MoleculeSelect {...props} value={value} onChange={onChange}>
        {options.map((option, i) => (
          <MoleculeSelectOption key={i} value={option}>
            {option}
          </MoleculeSelectOption>
        ))}
      </MoleculeSelect>
    )
  }
}
```

so then, the `SelectSingleWithAsyncOptions` can used in this way...

```js
<SelectSingleWithAsyncOptions iconClear={<IconClear />} />
```

### Using the hoc `withStateValue`

There's a hoc called `withStateValue` available at `@s-ui/hoc`
that can be used to simplify the use of this component with internal state

```js
import MoleculeSelect from '@s-ui/react-molecule-select'
import MoleculeSelectOption from '@s-ui/react-molecule-dropdown-option'

import withDynamicOptions from './hoc/withDynamicOptions'
import {withStateValue} from '@s-ui/hoc'

const MoleculeSelectWithState = withStateValue(MoleculeSelect)
const options = ['John', 'Paul', 'George', 'Ringo']
```

so then, the `MoleculeSelectWithState` can be used in this way...

```js
<MoleculeSelectWithState
  placeholder="Type a Country name..."
  onChange={(_, {value}) => console.log(value)}
  iconClear={<IconClear />}
>
  {options.map((option, i) => (
    <MoleculeSelectOption key={i} value={option}>
      {option}
    </MoleculeSelectOption>
  ))}
</MoleculeSelectWithState>
```

## Create custom option compatible w/ `MoleculeSelect`

If you need an option that cannot be customized from `MoleculeDropdownOption` you can create your own option compatible w/ `MoleculeSelect` y `MoleculeSelect` by using the `handlersFactory` method available in `MoleculeDropdownOption` that you can use to create proper handlers needed to work properly along w/ `MoleculeSelect` y `MoleculeSelect`

```js
import React from 'react'
import {handlersFactory} from '@s-ui/react-molecule-dropdown-option'

const BASE_CLASS = 'AlternativeOption'

const AlternativeOption = ({children, onSelect, innerRef, value}) => {
  const {handleClick, handleKeyDown, handleFocus} = handlersFactory({
    value,
    onSelect
  })

  return (
    <div
      className={BASE_CLASS}
      ref={innerRef}
      tabIndex="0"
      onFocus={handleFocus}
      onClick={handleClick}
      onKeyDown={handleKeyDown}
    >
      {children}
    </div>
  )
}

AlternativeOption.displayName = 'AlternativeOption'

AlternativeOption.defaultProps = {
  onSelect: () => {},
  innerRef: React.createRef()
}

export default AlternativeOption
```

so then you can do something like...

```js
<MoleculeSelect
  placeholder="Select an Option..."
  onChange={(_, {value}) => console.log(value)}
  iconArrowDown={<IconArrowDown />}
>
  {options.map((option, i) => (
    <AlternativeOption key={i} value={option}>
      {option}
    </AlternativeOption>
  ))}
</MoleculeSelect>
```

> **Find full description and more examples in the [demo page](https://sui-components.now.sh/workbench/molecule/select/demo).**
