# All files / src/Typeahead Typeahead.tsx

100% Statements 29/29
88% Branches 22/25
100% Functions 4/4
100% Lines 28/28

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
    10042x
    42x
    42x
    42x
    42x
    42x

    42x

    123x
    123x
    123x
    123x
    123x
    123x
    123x
    123x

    123x

    15x

    123x

    123x

    23x

    2x
    1x

    2x

    23x

    123x

    1x
    1x

    123x

     import { Clear, Search } from '@procore/core-icons/dist'
    import React from 'react'
    import { Button } from '../Button/Button'
    import { useLayoutEventListener } from '../_hooks/EventListener'
    import { mergeRefs } from '../_utils/mergeRefs'
    import { StyledIcon, StyledInput, StyledTypeahead } from './Typeahead.styles'
    import { TypeaheadInputProps, TypeaheadProps } from './Typeahead.types'

    /**
     @since 10.19.0

     @see [Storybook](https://procore.github.io/core/core-react/latest/?path=/story/demos-typeahead--demo)

     */
    export const Typeahead = React.forwardRef<
      HTMLInputElement,
      TypeaheadInputProps & TypeaheadProps
    >(function (
      {
        className,
        disabled,
        onChange: onChange_,
        style,
        value,
        type = 'search',
        onKeyDown: onKeyDown_,
        ...props
      },
      ref
    ) {
      const onChange = React.useCallback(
        function onChange(e: React.ChangeEvent<HTMLInputElement>) {
          onChange_?.(e.target.value, e)
        },
        [onChange_]
      )

      const innerRef = React.useRef(null)

      useLayoutEventListener({
        dependencies: [onChange_, onKeyDown_],
        event: 'keydown',
        handler: function onKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
          if (e.key === 'Escape' || e.key === 'Esc') {
            // stop propagation once to clear input
            if ((e.target as HTMLInputElement).value) {
              e.stopPropagation()
            }
            onChange_?.('', { ...e, target: { ...e.target, value: '' } })
          }

          onKeyDown_?.(e)
        },
        scope: innerRef,
      })

      const onClickClear = React.useCallback(
        function onClickClear(e: React.MouseEvent<HTMLButtonElement>) {
          if (!disabled) {
            onChange_?.('', { ...e, target: { ...e.target, value: '' } })
          }
        },
        [disabled, onChange_]
      )

      return (
        <StyledTypeahead
          className={className}
          style={style}
          data-qa={props['data-qa']}
        >
          <StyledInput
            {...props}
            type={type}
            data-qa="core-typeahead-input"
            ref={mergeRefs(innerRef, ref)}
            onChange={onChange}
            disabled={disabled}
            value={value}
          />
          <StyledIcon disabled={disabled}>
            {value ? (
              <Button
                aria-label="Clear the input"
                data-qa="core-typeahead-clear-icon"
                size="sm"
                variant="tertiary"
                icon={<Clear />}
                disabled={disabled}
                onClick={onClickClear}
                tabIndex={-1} // TODO revisit this accessibility
              />
            ) : (
              <Search data-qa="core-typeahead-search-icon" size="sm" />
            )}
          </StyledIcon>
        </StyledTypeahead>
      )
    })