Skip to content

Commit

Permalink
wip: refactor phone input
Browse files Browse the repository at this point in the history
  • Loading branch information
HellWolf93 committed Dec 9, 2021
1 parent 0196f9b commit 8abbcb1
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 117 deletions.
172 changes: 91 additions & 81 deletions src/components/PhoneInput/countriesDropdown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,94 +22,104 @@ import StyledSearchIcon from '../../Lookup/options/styled/searchIcon';
import StyledOptionsContainer from '../../Lookup/options/styled/optionsContainer';
import StyledEmptyMessage from '../../Lookup/options/styled/emptyMessage';

const CountriesDropdown = memo(props => {
const {
country,
countries,
isOpen,
searchRef,
setFocusIndex,
onCountryChange,
handleFocus,
handleBlur,
} = props;
const CountriesDropdown = memo(
React.forwardRef((props, ref) => {
console.log('rendering');
const {
country,
countries,
isOpen,
searchRef,
setFocusIndex,
onCountryChange,
handleFocus,
handleBlur,
} = props;

const scrollableRef = useRef();
const [query, countriesFiltered, setQuery] = useFilterCountries(countries, country);
const itemsRef = useItemsRef(countriesFiltered.length);
const handleCountryChange = useHandleCountryChange(scrollableRef, onCountryChange, setQuery);
const handleActiveChange = useKeyboardNavigation(
country,
countriesFiltered,
searchRef,
scrollableRef,
itemsRef,
handleCountryChange,
setFocusIndex,
);
const {
showScrollUp,
showScrollDown,
handleScrollUpMouseEnter,
handleScrollDownouseEnter,
stopScroll,
} = useScrollControls(scrollableRef);
const scrollableRef = useRef();
const [query, countriesFiltered, setQuery] = useFilterCountries(countries, country);
const itemsRef = useItemsRef(countriesFiltered.length);
const handleCountryChange = useHandleCountryChange(
scrollableRef,
onCountryChange,
setQuery,
);
const handleActiveChange = useKeyboardNavigation(
country,
countriesFiltered,
searchRef,
scrollableRef,
itemsRef,
handleCountryChange,
setFocusIndex,
);
const {
showScrollUp,
showScrollDown,
handleScrollUpMouseEnter,
handleScrollDownouseEnter,
stopScroll,
} = useScrollControls(scrollableRef);

const listHeight = countriesFiltered.length * 45;
const listHeight = countriesFiltered.length * 45;

return (
<StyledDropdown isOpen={isOpen}>
<StyledSearchContainer>
<StyledSearch
ref={searchRef}
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
onFocus={event => handleFocus(event, 1)}
onBlur={handleBlur}
/>
</StyledSearchContainer>
<StyledScrollControls>
<RenderIf isTrue={showScrollUp}>
return (
<StyledDropdown isOpen={isOpen} ref={ref}>
<StyledSearchContainer>
<StyledSearch
ref={searchRef}
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
onFocus={event => handleFocus(event, 1)}
onBlur={handleBlur}
/>
</StyledSearchContainer>
<StyledScrollControls>
<RenderIf isTrue={showScrollUp}>
<Arrow
direction="up"
onMouseEnter={handleScrollUpMouseEnter}
onMouseLeave={stopScroll}
/>
</RenderIf>
<StyledScrollable ref={scrollableRef}>
<RenderIf isTrue={countriesFiltered.length > 0}>
<StyledUl role="listbox" listHeight={listHeight}>
<CountriesList
countries={countriesFiltered}
country={country}
itemsRef={itemsRef}
handleCountryChange={handleCountryChange}
handleActiveChange={handleActiveChange}
/>
</StyledUl>
</RenderIf>
<RenderIf isTrue={countriesFiltered.length === 0}>
<StyledOptionsContainer
as="div"
data-id="phone-country-empty-container"
>
<StyledSearchIcon />
<StyledEmptyMessage>
Our robots did not find any match for
<span>{` "${query}"`}</span>
</StyledEmptyMessage>
</StyledOptionsContainer>
</RenderIf>
</StyledScrollable>
</StyledScrollControls>
<RenderIf isTrue={showScrollDown}>
<Arrow
direction="up"
onMouseEnter={handleScrollUpMouseEnter}
direction="down"
onMouseEnter={handleScrollDownouseEnter}
onMouseLeave={stopScroll}
/>
</RenderIf>
<StyledScrollable ref={scrollableRef}>
<RenderIf isTrue={countriesFiltered.length > 0}>
<StyledUl role="listbox" listHeight={listHeight}>
<CountriesList
countries={countriesFiltered}
country={country}
itemsRef={itemsRef}
handleCountryChange={handleCountryChange}
handleActiveChange={handleActiveChange}
/>
</StyledUl>
</RenderIf>
<RenderIf isTrue={countriesFiltered.length === 0}>
<StyledOptionsContainer as="div" data-id="phone-country-empty-container">
<StyledSearchIcon />
<StyledEmptyMessage>
Our robots did not find any match for
<span>{` "${query}"`}</span>
</StyledEmptyMessage>
</StyledOptionsContainer>
</RenderIf>
</StyledScrollable>
</StyledScrollControls>
<RenderIf isTrue={showScrollDown}>
<Arrow
direction="down"
onMouseEnter={handleScrollDownouseEnter}
onMouseLeave={stopScroll}
/>
</RenderIf>
</StyledDropdown>
);
});
</StyledDropdown>
);
}),
);

CountriesDropdown.propTypes = {
countries: PropTypes.array,
Expand Down
17 changes: 1 addition & 16 deletions src/components/PhoneInput/countriesDropdown/styled/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import styled from 'styled-components';
import attachThemeAttrs from '../../../../styles/helpers/attachThemeAttrs';

const StyledDropdown = attachThemeAttrs(styled.div)`
position: absolute;
position: relative;
overflow: hidden;
z-index: 2000;
left: 50%;
float: left;
width: 100%;
margin-top: 0.25rem;
Expand All @@ -16,20 +14,7 @@ const StyledDropdown = attachThemeAttrs(styled.div)`
font-size: 0.75rem;
background: ${props => props.palette.background.main};
box-shadow: ${props => props.shadows.shadow_2};
transform: translateX(-50%);
display: none;
opacity: 0;
transition: opacity 0.1s linear, visibility 0.1s linear;
visibility: hidden;
top: 100%;
${props =>
props.isOpen &&
`
display: block;
opacity: 1;
transition: opacity 0.1s linear, visibility 0.1s linear;
visibility: visible;
`}
`;

export default StyledDropdown;
17 changes: 17 additions & 0 deletions src/components/PhoneInput/helpers/positionResolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import InternalOverlay from '../../InternalOverlay';

export default function positionResolver(opts) {
const { trigger, viewport, content } = opts;
const newOpts = {
trigger,
viewport,
content: {
...content,
width: trigger.width,
},
};
return {
...InternalOverlay.defaultPositionResolver(newOpts),
width: trigger.width,
};
}
5 changes: 5 additions & 0 deletions src/components/PhoneInput/hooks/useHandleCountryChange.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { useCallback } from 'react';
export default function useHandleCountryChange(phone, onChange, setFocusIndex, isOpen) {
return useCallback(
newCountry => {
console.log({
countryCode: newCountry.countryCode,
isoCode: newCountry.isoCode,
phone,
});
setFocusIndex(2);
onChange({
countryCode: newCountry.countryCode,
Expand Down
52 changes: 32 additions & 20 deletions src/components/PhoneInput/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/no-unused-prop-types */
import React, { useRef, useImperativeHandle } from 'react';
import React, { useRef, useImperativeHandle, useState } from 'react';
import PropTypes from 'prop-types';
import { useOutsideClick } from '@rainbow-modules/hooks';
import Label from '../Input/label';
Expand All @@ -8,6 +8,7 @@ import StyledContainer from '../Input/styled/container';
import HelpText from '../Input/styled/helpText';
import ErrorText from '../Input/styled/errorText';
import AssistiveText from '../AssistiveText';
import InternalOverlay from '../InternalOverlay';
import {
StyledInputContainer,
StyledInput,
Expand All @@ -27,6 +28,7 @@ import {
useHandleCountryChange,
} from './hooks';
import CountriesDropdown from './countriesDropdown';
import positionResolver from './helpers/positionResolver';

/**
* phone input are used for freeform data entry.
Expand Down Expand Up @@ -61,6 +63,7 @@ const PhoneInput = React.forwardRef((props, ref) => {
const triggerRef = useRef();
const searchRef = useRef();
const inputRef = useRef();
const pickerRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
Expand All @@ -81,18 +84,20 @@ const PhoneInput = React.forwardRef((props, ref) => {
const countries = useCountries(countriesProps);
const country = useCountry(value, countries);
const { countryCode, isoCode, flagIcon } = country;
const [focusIndex, setFocusIndex] = useFocusIndex(
containerRef,
triggerRef,
searchRef,
inputRef,
);
const [focusIndex, setFocusIndex] = useFocusIndex(containerRef, triggerRef, inputRef);
console.log(focusIndex);
useOutsideClick(
containerRef,
() => {
setFocusIndex(-1);
pickerRef,
event => {
if (
event.target !== triggerRef.current &&
!triggerRef.current.contains(event.target) &&
!pickerRef.current.contains(event.target)
) {
setFocusIndex(-1);
}
},
focusIndex > -1,
isOpen,
);

const handleFocus = useHandleFocus(focusIndex, onFocus, setFocusIndex, value);
Expand Down Expand Up @@ -202,6 +207,20 @@ const PhoneInput = React.forwardRef((props, ref) => {
<RenderIf isTrue={icon}>
<StyledIconContainer error={error}>{icon}</StyledIconContainer>
</RenderIf>
</StyledInputContainer>
<RenderIf isTrue={bottomHelpText}>
<HelpText alignSelf="center">{bottomHelpText}</HelpText>
</RenderIf>
<RenderIf isTrue={error}>
<ErrorText alignSelf="center" id={errorMessageId}>
{error}
</ErrorText>
</RenderIf>
<InternalOverlay
isVisible={isOpen}
positionResolver={positionResolver}
triggerElementRef={() => containerRef}
>
<CountriesDropdown
country={country}
countries={countries}
Expand All @@ -211,16 +230,9 @@ const PhoneInput = React.forwardRef((props, ref) => {
handleFocus={handleFocus}
handleBlur={handleBlur}
onCountryChange={handleCountryChange}
ref={pickerRef}
/>
</StyledInputContainer>
<RenderIf isTrue={bottomHelpText}>
<HelpText alignSelf="center">{bottomHelpText}</HelpText>
</RenderIf>
<RenderIf isTrue={error}>
<ErrorText alignSelf="center" id={errorMessageId}>
{error}
</ErrorText>
</RenderIf>
</InternalOverlay>
</StyledContainer>
);
});
Expand Down

0 comments on commit 8abbcb1

Please sign in to comment.