diff --git a/package.json b/package.json
index a0e041a5..fd673ac5 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"build-storybook": "build-storybook -s public"
},
"dependencies": {
+ "@reach/combobox": "^0.10.4",
"history": "^4.10.1",
"lodash": "^4.17.15",
"react": "^16.13.1",
diff --git a/public/images/arrowDown.svg b/public/images/arrowDown.svg
new file mode 100644
index 00000000..94f5058a
--- /dev/null
+++ b/public/images/arrowDown.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/features/Common/Input/styled.tsx b/src/features/Common/Input/styled.tsx
index 708cd621..873080ba 100644
--- a/src/features/Common/Input/styled.tsx
+++ b/src/features/Common/Input/styled.tsx
@@ -1,11 +1,11 @@
-import styled from 'styled-components/macro'
+import styled, { css } from 'styled-components/macro'
export type TInputWrapper = {
paddingX?: number,
wrapperWidth?: number,
}
-export const InputWrapper = styled.div`
+export const wrapperStyles = css`
width: ${({ wrapperWidth }) => (wrapperWidth ? `${wrapperWidth}px` : '100%')};
height: 48px;
margin: 20px 0;
@@ -20,6 +20,10 @@ export const InputWrapper = styled.div`
border-radius: 2px;
`
+export const InputWrapper = styled.div`
+ ${wrapperStyles}
+`
+
type TLabel = {
labelWidth?: number,
}
@@ -39,7 +43,7 @@ type TInputStyled = {
inputWidth?: number,
}
-export const InputStyled = styled.input`
+export const inputStyles = css`
flex-grow: 1;
font-weight: bold;
font-size: 20px;
@@ -68,3 +72,7 @@ export const InputStyled = styled.input`
-webkit-text-fill-color: ${({ theme: { colors } }) => colors.text};
}
`
+
+export const InputStyled = styled.input`
+ ${inputStyles}
+`
diff --git a/src/features/CountrySelector/hooks.tsx b/src/features/CountrySelector/hooks.tsx
new file mode 100644
index 00000000..61a69061
--- /dev/null
+++ b/src/features/CountrySelector/hooks.tsx
@@ -0,0 +1,88 @@
+import type { ChangeEvent, FocusEvent } from 'react'
+import type { Countries } from 'requests'
+
+import {
+ useEffect,
+ useState,
+ useCallback,
+} from 'react'
+
+import toLower from 'lodash/toLower'
+import slice from 'lodash/slice'
+import find from 'lodash/find'
+
+import { getCountries } from 'requests'
+
+import { matchSort } from './helpers'
+
+// временно, будем считывать из стора(контекста) лексики
+const useCurrentLang = () => 'eng'
+
+const useCountriesList = () => {
+ const [countries, setCountries] = useState([])
+
+ useEffect(() => {
+ getCountries().then(setCountries)
+ }, [])
+
+ return countries
+}
+
+const useQuery = () => {
+ const [query, setQuery] = useState('')
+
+ const onQueryChange = useCallback(({ target }: ChangeEvent) => {
+ setQuery(target.value)
+ }, [])
+
+ return {
+ onQueryChange,
+ query,
+ setQuery,
+ }
+}
+
+const isOptionClicked = (target: HTMLElement) => target?.getAttribute('role') === 'option'
+
+export const useCountrySelector = () => {
+ const lang = useCurrentLang()
+ const countries = useCountriesList()
+ const {
+ onQueryChange,
+ query,
+ setQuery,
+ } = useQuery()
+
+ const keyToSortBy = `name_${lang}` as 'name_eng'
+
+ const results = matchSort(
+ countries,
+ keyToSortBy,
+ query,
+ )
+
+ const onBlur = (event: FocusEvent) => {
+ const target = event.relatedTarget as HTMLElement | null
+ // клик по элементу списка тоже вызывает onBlur
+ // если кликали элемент списка то событие обрабатывается onCountrySelect
+ if (target && isOptionClicked(target)) return
+
+ const found = find(
+ countries,
+ (country) => toLower(country[keyToSortBy]) === toLower(query),
+ )
+ setQuery(found ? found[keyToSortBy] : '')
+ }
+
+ return {
+ countries: slice(
+ results,
+ 0,
+ 20,
+ ),
+ onBlur,
+ onCountrySelect: setQuery,
+ onQueryChange,
+ query,
+ }
+}
diff --git a/src/features/CountrySelector/index.tsx b/src/features/CountrySelector/index.tsx
new file mode 100644
index 00000000..07912710
--- /dev/null
+++ b/src/features/CountrySelector/index.tsx
@@ -0,0 +1,63 @@
+import React from 'react'
+
+import isEmpty from 'lodash/isEmpty'
+import map from 'lodash/map'
+import {
+ ComboboxPopover,
+ ComboboxList,
+ ComboboxOption,
+} from '@reach/combobox'
+import '@reach/combobox/styles.css'
+
+import { Label } from 'features/Common/Input/styled'
+
+import { useCountrySelector } from './hooks'
+import {
+ ComboboxStyled,
+ ComboboxInputStyled,
+ Arrow,
+} from './styled'
+
+type Props = {
+ labelWidth?: number,
+}
+
+export const CountrySelector = ({ labelWidth }: Props) => {
+ const {
+ countries,
+ onBlur,
+ onCountrySelect,
+ onQueryChange,
+ query,
+ } = useCountrySelector()
+
+ return (
+
+
+
+ {!isEmpty(countries) && (
+
+
+ {map(countries, ({ id, name_eng }) => (
+
+ ))}
+
+
+ )}
+
+ )
+}
diff --git a/src/features/CountrySelector/styled.tsx b/src/features/CountrySelector/styled.tsx
new file mode 100644
index 00000000..bcd76ac8
--- /dev/null
+++ b/src/features/CountrySelector/styled.tsx
@@ -0,0 +1,27 @@
+import styled from 'styled-components/macro'
+
+import { Combobox, ComboboxInput } from '@reach/combobox'
+
+import { wrapperStyles, inputStyles } from 'features/Common/Input/styled'
+
+export const ComboboxStyled = styled(Combobox)`
+ ${wrapperStyles}
+ position: relative;
+`
+
+export const ComboboxInputStyled = styled(ComboboxInput)`
+ ${inputStyles}
+ padding-right: 24px;
+`
+
+export const Arrow = styled.div`
+ position: absolute;
+ right: 20px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 12px;
+ height: 12px;
+ background-image: url(/images/arrowDown.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+`
diff --git a/src/features/Register/Steps/Registration/index.tsx b/src/features/Register/Steps/Registration/index.tsx
index 9e5a5fe8..3eefccde 100644
--- a/src/features/Register/Steps/Registration/index.tsx
+++ b/src/features/Register/Steps/Registration/index.tsx
@@ -2,6 +2,7 @@ import React from 'react'
import { PAGES } from 'config'
+import { CountrySelector } from 'features/CountrySelector'
import { Input } from 'features/Common'
import {
BlockTitle,
@@ -38,15 +39,15 @@ export const Registration = () => (
label='E-mail'
labelWidth={labelWidth}
/>
- {/* TODO: it should be Dropdown */}
+