# All files / src/components search-input.tsx

100% Statements 12/12
100% Branches 9/9
100% Functions 2/2
100% Lines 12/12

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

    11x

    18x
    18x
    4x
    4x
    1x

    18x
    1x
    17x
    6x

    11x

    18x

     import {
      useRef,
      type FC,
      type KeyboardEvent,
      type ChangeEventHandler,
      type ChangeEvent,
      type InputHTMLAttributes,
    } from 'react';

    import SearchIcon from '../svg/search.svg';
    import SpinnerIcon from '../svg/spinner.svg';
    import CloseIcon from '../svg/times.svg';

    import '../styles/components/search-input.scss';

    type Props = {
      /**
       * The value to display in the text input.
       */
      value?: string;
      /**
       * Value change callback for the text input component.
       */
      onChange?: ChangeEventHandler<HTMLInputElement>;
      /**
       * Key pressed callback for the text input component.
       */
      onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
      /**
       * Text to place in the text input component in the absence of value.
       */
      placeholder?: string;
      /**
       * Text to place in the text input component in the absence of value.
       */
      isLoading?: boolean;
    } & InputHTMLAttributes<HTMLInputElement>;

    const SearchInput: FC<Props> = ({
      value,
      onChange,
      onKeyDown,
      placeholder,
      isLoading = false,
      ...props
    }) => {
      const inputRef = useRef<HTMLInputElement>(null);
      const handleSuffixInteraction = () => {
        inputRef?.current?.focus();
        if (value && !isLoading) {
          onChange?.({ target: { value: '' } } as ChangeEvent<HTMLInputElement>);
        }
      };

      let icon;
      if (isLoading) {
        icon = <SpinnerIcon width={14} height={14} />;
      } else if (value) {
        icon = <CloseIcon width={14} height={14} />;
      } else {
        icon = <SearchIcon width={14} height={14} />;
      }

      return (
        <span className="search-input">
          <input
            data-testid="search-input"
            type="search"
            value={value}
            onChange={onChange}
            onKeyDown={onKeyDown}
            placeholder={placeholder}
            ref={inputRef}
            {...props}
          />
          <span
            data-testid="search-input-suffix"
            role="presentation"
            className="search-input__suffix"
            onKeyPress={handleSuffixInteraction}
            onClick={handleSuffixInteraction}
          >
            {icon}
          </span>
        </span>
      );
    };

    export default SearchInput;