react-intl-tel-input
Version:
Telephone input component. Rewrite intl-tel-input in React.js.
139 lines (119 loc) • 4.47 kB
JavaScript
import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import classNames from 'classnames';
import utils from './utils';
function partial(fn, ...args) {
return fn.bind(fn, ...args);
}
class CountryList extends Component {
static propTypes = {
dropdownContainer: PropTypes.string,
setFlag: PropTypes.func,
countries: PropTypes.array,
inputTop: PropTypes.number,
inputOuterHeight: PropTypes.number,
preferredCountries: PropTypes.array,
highlightedCountry: PropTypes.number,
changeHighlightCountry: PropTypes.func,
showDropdown: PropTypes.bool,
};
constructor() {
super();
this.handleMouseOver = this.handleMouseOver.bind(this);
this.setFlag = this.setFlag.bind(this);
this.appendListItem = this.appendListItem.bind(this);
this.setDropdownPosition = this.setDropdownPosition.bind(this);
}
componentWillReceiveProps(nextProps) {
if (nextProps.showDropdown) {
findDOMNode(this.refs.listElement).setAttribute('class', 'country-list v-hide');
this.setDropdownPosition();
}
}
shouldComponentUpdate(nextProps) {
return !utils.shallowEquals(this.props, nextProps);
}
setDropdownPosition() {
utils.removeClass(
findDOMNode(this.refs.listElement), 'hide');
const inputTop = this.props.inputTop;
const windowTop = (window.pageYOffset !== undefined) ?
window.pageYOffset :
(document.documentElement || document.body.parentNode || document.body).scrollTop;
const windowHeight = window.innerHeight || document.documentElement.clientHeight ||
document.body.clientHeight;
const inputOuterHeight = this.props.inputOuterHeight;
const countryListOuterHeight = utils.getOuterHeight(findDOMNode(this.refs.listElement));
const dropdownFitsBelow =
(inputTop + inputOuterHeight + countryListOuterHeight < windowTop + windowHeight);
const dropdownFitsAbove = (inputTop - countryListOuterHeight > windowTop);
// dropdownHeight - 1 for border
const cssTop = (!dropdownFitsBelow && dropdownFitsAbove) ?
`-${(countryListOuterHeight - 1)}px` : '';
findDOMNode(this.refs.listElement).style.top = cssTop;
findDOMNode(this.refs.listElement).setAttribute('class', 'country-list');
}
setFlag(iso2) {
this.props.setFlag(iso2);
}
appendListItem(countries, className) {
const preferredCountriesCount = this.props.preferredCountries.length;
return countries.map((country, index) => {
const actualIndex = (className === 'preferred') ? index : index + preferredCountriesCount;
const countryClassObj = {
country: true,
highlight: (this.props.highlightedCountry === actualIndex),
};
let countryClass = undefined;
countryClassObj[className] = true;
countryClass = classNames(countryClassObj);
return (
<li key={`country-${index}`}
className={countryClass}
data-dial-code={country.dialCode}
data-country-code={country.iso2}
onMouseOver={this.handleMouseOver}
onClick={partial(this.setFlag, country.iso2)}
>
<div ref="selectedFlag" className="flag-box">
<div ref="selectedFlagInner" className={`iti-flag ${country.iso2}`}></div>
</div>
<span className="country-name">{country.name}</span>
<span className="dial-code">+{country.dialCode}</span>
</li>
);
});
}
handleMouseOver(e) {
if (e.currentTarget.getAttribute('class').indexOf('country') > -1) {
const selectedIndex = utils.retrieveLiIndex(e.currentTarget);
this.props.changeHighlightCountry(true, selectedIndex);
}
}
render() {
let options = '';
const preferredCountries = this.props.preferredCountries;
let preferredOptions = undefined;
const countries = this.props.countries;
const className = classNames({
'country-list': true,
hide: !this.props.showDropdown,
});
let divider = undefined;
if (preferredCountries.length) {
preferredOptions = this.appendListItem(preferredCountries, 'preferred');
divider = (
<div className="divider"></div>
);
}
options = this.appendListItem(countries, '');
return (
<ul ref="listElement" className={className}>
{preferredOptions}
{divider}
{options}
</ul>
);
}
}
export default CountryList;