Skip to content
Snippets Groups Projects

Hin 1138 country menu

Merged Larisa Andrici requested to merge HIN-1138-Country-Menu into develop
Files
3
import React from 'react'
import { Menu } from '@pubsweet/ui'
import { startsWith, toLower, get } from 'lodash'
import { compose, withState, withHandlers } from 'recompose'
import React, { Fragment } from 'react'
import styled from 'styled-components'
import { th } from '@pubsweet/ui-toolkit'
import { startsWith, toLower, get } from 'lodash'
import { th, override } from '@pubsweet/ui-toolkit'
import { withCountries } from 'pubsweet-component-faraday-ui'
import { compose, withState, withHandlers, withProps } from 'recompose'
const filteredCountries = (countries, userInput) =>
const filteredCountries = ({ countries, userInput }) =>
countries.filter(o => startsWith(toLower(o.label), toLower(userInput)))
const firstFilteredCountry = props =>
filteredCountries(props.countries, props.userInput)[0]
const firstFilteredCountry = ({ countries, userInput }) =>
filteredCountries({ countries, userInput })[0]
const CustomOpener = ({
selected,
const Menu = ({
open,
options,
onEnter,
userInput,
toggleMenu,
placeholder,
optionLabel,
onChange,
onEnter,
handleSelect,
onTextChange,
}) => (
<Input
onChange={onChange}
onClick={toggleMenu}
onKeyUp={onEnter}
placeholder={selected ? optionLabel(selected) : placeholder}
value={userInput}
/>
<Fragment>
{open && <CloseOverlay onClick={toggleMenu} />}
<Main>
<Input
onChange={onTextChange}
onClick={toggleMenu}
onKeyUp={onEnter}
placeholder={placeholder}
value={userInput}
/>
{open && (
<Options>
{options.map(option => (
<Option key={option.value} onClick={handleSelect(option.value)}>
{option.label}
</Option>
))}
</Options>
)}
</Main>
</Fragment>
)
const MenuCountry = ({ countries = [], ...input }) => (
<Menu
{...input}
options={filteredCountries(countries, input.userInput)}
placeholder="Please select"
renderOpener={CustomOpener}
/>
)
const enhance = compose(
export default compose(
withCountries,
withState('userInput', 'updateUserInput', ''),
withState('open', 'updateOptionsVisibility', false),
withHandlers({
onChange: ({ updateUserInput, onChange }) => value => {
// this value is an input DOM event while typing and a dropdown value when
// selected
if (typeof value === 'string') {
onChange(value)
}
updateUserInput(get(value, 'target.value', ''))
handleSelect: ({
onChange,
countryLabel,
updateUserInput,
updateOptionsVisibility,
}) => value => () => {
onChange(value)
updateUserInput(countryLabel(value))
updateOptionsVisibility(false)
},
onEnter: props => event => {
}),
withHandlers({
toggleMenu: ({ updateOptionsVisibility, open }) => () => {
updateOptionsVisibility(!open)
},
onTextChange: ({ updateUserInput }) => event => {
updateUserInput(get(event, 'target.value', ''))
},
onEnter: ({ handleSelect, userInput, countries }) => event => {
if (event.which === 13) {
props.onChange(firstFilteredCountry(props).value)
props.updateUserInput(firstFilteredCountry(props).label)
handleSelect(firstFilteredCountry({ countries, userInput }).value)()
}
},
}),
)
export default enhance(MenuCountry)
withProps(({ countries, userInput }) => ({
options: filteredCountries({ countries, userInput }),
})),
)(Menu)
// #region styles
const Input = styled.input`
width: 100%;
height: calc(${th('gridUnit')} * 4);
border: ${th('accordion.border')};
border-radius: ${th('borderRadius')};
padding: 0 ${th('gridUnit')};
font-family: ${th('fontHeading')};
::placeholder {
color: ${th('colorText')};
opacity: 1;
font-family: ${th('fontWriting')};
font-style: italic;
}
:focus {
border-color: ${th('action.colorActive')}
outline: none;
}
`
const CloseOverlay = styled.div`
background-color: transparent;
position: fixed;
bottom: 0;
left: 0;
top: 0;
right: 0;
z-index: 10;
${override('ui.MenuCountry.CloseOverlay')};
`
const Label = styled.label`
font-size: ${th('fontSizeBaseSmall')};
line-height: ${th('lineHeightBaseSmall')};
display: block;
${override('ui.Label')};
${override('ui.MenuCountry.Label')};
`
const Main = styled.div.attrs(props => ({
role: 'listbox',
}))`
position: relative;
${override('ui.MenuCountry.Main')};
`
const Options = styled.div`
position: absolute;
top: 35px;
left: 0;
right: 0;
background-color: ${th('colorBackground')};
border: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')};
border-radius: ${th('borderRadius')};
overflow-y: auto;
max-height: ${({ maxHeight }) => `${maxHeight || 250}px`};
max-width: ${({ maxWidth }) => `${maxWidth || 200}px`};
z-index: 100;
${override('ui.MenuCountry.Options')};
`
const Option = styled.div.attrs(props => ({
role: 'option',
tabIndex: '0',
'aria-selected': props.active,
}))`
color: ${props => (props.active ? props.theme.textColor : '#444')};
font-weight: ${props => (props.active ? '600' : 'inherit')};
cursor: pointer;
font-family: ${th('fontAuthor')};
padding: calc(${th('gridUnit')} - ${th('borderWidth')} * 2)
calc(${th('gridUnit')} * 2);
border: ${th('borderWidth')} ${th('borderStyle')} transparent;
border-width: ${th('borderWidth')} 0 ${th('borderWidth')} 0;
white-space: nowrap;
&:hover {
background: ${th('colorBackgroundHue')};
border-color: ${th('colorBorder')};
}
&:first-child:hover {
border-top-color: ${th('colorBackgroundHue')};
}
&:last-child:hover {
border-bottom-color: ${th('colorBackgroundHue')};
}
${override('ui.MenuCountry.Option')};
`
// #endregion