# All files / Select Select.tsx

0% Statements 0/41
0% Branches 0/9
0% Functions 0/7
0% Lines 0/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116

     import * as React from 'react'
    import classNames from 'classnames'
    import { createUseStyles } from '@fluent-ui/styles'
    import { styles } from './Select.styled'
    import { Theme } from '../styles'

    import { usePopper, useClick, useClickOutside } from '@fluent-ui/hooks'
    import { ChevronDownMed as DownIcon } from '@fluent-ui/icons'
    import { SelectClassProps, SelectProps, SelectPropTypes } from './Select.type'
    import Transition from '../Transition'
    import List from '../List'

    export const name = 'Select'

    const useStyles = createUseStyles<Theme, SelectClassProps>(styles, { name })

    const Select: React.FC<SelectProps> = React.forwardRef<HTMLInputElement, SelectProps>(
      (props, ref): React.ReactElement => {
        const {
          as: Component = 'span',
          className: classNameProp,
          value,
          onChange,
          disabled = false,
          children,
          ...rest
        } = props

        const [referenceRef, popperRef] = usePopper<HTMLDivElement, HTMLDivElement>({
          placement: 'bottom-start',
          positionFixed: false
        })

        const [visible, setVisible] = React.useState(false)
        const handleVisible = React.useCallback(
          (status): void => {
            disabled !== true && setVisible(status)
          },
          [disabled]
        )
        const [_, bind] = useClick(handleVisible)
        useClickOutside(
          referenceRef,
          (): void => {
            setVisible(false)
          }
        )

        const [currentText, setCurrentText] = React.useState('')
        React.useEffect((): void => {
          React.Children.forEach(
            children,
            (child: React.ReactElement): void => {
              const active = child.props.value === value
              active && setCurrentText(child.props.children)
            }
          )
        }, [children, value])
        const theChildren = React.Children.map(
          children,
          (child: React.ReactElement): React.ReactElement => {
            function onClick(): void {
              child.props.value && onChange && onChange(child.props.value)
              setCurrentText(child.props.children)
              setVisible(false)
            }
            const active = child.props.value === value
            return React.cloneElement(child, {
              onClick,
              active
            })
          }
        )

        const classes = useStyles(props)
        const className = classNames(
          classes.root,
          {
            [classes.disabled]: disabled
          },
          classNameProp
        )
        const selectClassName = classNames(classes.select, {
          [classes.selectDisabled]: disabled
        })
        const iconClassName = classNames(classes.icon, {
          [classes.disabledIcon]: disabled
        })

        return (
          <Component className={className} ref={referenceRef} {...bind}>
            <button className={selectClassName}>{currentText}</button>
            <span className={iconClassName}>
              <DownIcon />
            </span>
            <input type="hidden" value={value} disabled={disabled} ref={ref} {...rest} />
            <Transition type="grow" visible={visible} wrapper={false} mountOnEnter unmountOnExit>
              <List zIndex={1002} ref={popperRef}>
                {theChildren}
              </List>
            </Transition>
          </Component>
        )
      }
    )

    Select.displayName = `F${name}`

    Select.propTypes = SelectPropTypes

    Select.defaultProps = {
      disabled: false
    }

    export default Select