summaryrefslogtreecommitdiffhomepage
path: root/desktop/packages/mullvad-vpn/src/renderer/components/SearchBar.tsx
blob: dcefbdff7e3e1de808c7854aabae8888170cf203 (plain)
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
import { useCallback } from 'react';
import styled from 'styled-components';

import { messages } from '../../shared/gettext';
import { useFocusReferenceBeforePaint } from '../hooks';
import { Icon, IconButton } from '../lib/components';
import { colors } from '../lib/foundations';
import { useStyledRef } from '../lib/utility-hooks';
import { normalText } from './common-styles';

export const StyledSearchContainer = styled.div({
  position: 'relative',
  display: 'flex',
});

export const StyledSearchInput = styled.input.attrs({ type: 'text' })({
  ...normalText,
  flex: 1,
  border: 'none',
  borderRadius: '4px',
  padding: '9px 38px',
  margin: 0,
  lineHeight: '24px',
  color: colors.whiteAlpha60,
  backgroundColor: colors.whiteOnDarkBlue10,
  '&&::placeholder': {
    color: colors.whiteOnDarkBlue60,
  },
  '&&:focus': {
    color: colors.blue,
    backgroundColor: colors.white,
  },
  '&&:disabled': {
    backgroundColor: colors.whiteOnDarkBlue5,
    '&&::placeholder': {
      color: colors.whiteAlpha20,
    },
  },
});

export const StyledClearButton = styled(IconButton)({
  position: 'absolute',
  top: '50%',
  transform: 'translateY(-50%)',
  right: '9px',
});

export const StyledClearIcon = styled(Icon)({
  background: colors.whiteOnDarkBlue60,
  '&&:hover': {
    backgroundColor: colors.whiteOnDarkBlue40,
  },
});

export const StyledSearchIcon = styled(Icon)({
  position: 'absolute',
  top: '50%',
  transform: 'translateY(-50%)',
  left: '8px',
  [`${StyledSearchInput}:focus ~ &&`]: {
    backgroundColor: colors.blue,
  },
  [`${StyledSearchInput}:disabled ~ &&`]: {
    backgroundColor: colors.whiteAlpha20,
  },
});

export interface ISearchBarProps {
  searchTerm: string;
  disabled?: boolean;
  onSearch: (searchTerm: string) => void;
  className?: string;
  disableAutoFocus?: boolean;
}

export default function SearchBar(props: ISearchBarProps) {
  const { disabled, onSearch } = props;

  const inputRef = useStyledRef<HTMLInputElement>();
  useFocusReferenceBeforePaint(inputRef, !props.disableAutoFocus);

  const onInput = useCallback(
    (event: React.FormEvent) => {
      const element = event.target as HTMLInputElement;
      onSearch(element.value);
    },
    [onSearch],
  );

  const onClear = useCallback(() => {
    onSearch('');
    inputRef.current?.blur();
  }, [inputRef, onSearch]);

  return (
    <StyledSearchContainer className={props.className}>
      <StyledSearchInput
        disabled={disabled}
        ref={inputRef}
        value={props.searchTerm}
        onInput={onInput}
        placeholder={messages.gettext('Search for...')}
      />
      <StyledSearchIcon icon="search" color="whiteAlpha60" />
      {props.searchTerm.length > 0 && (
        <StyledClearButton variant="secondary" onClick={onClear}>
          <StyledClearIcon icon="cross-circle" />
        </StyledClearButton>
      )}
    </StyledSearchContainer>
  );
}