Skip to content

Commit

Permalink
Re-add countrySearch option
Browse files Browse the repository at this point in the history
  • Loading branch information
jackocnr committed Jul 17, 2024
1 parent b44d7a7 commit a725d73
Show file tree
Hide file tree
Showing 16 changed files with 1,048 additions and 570 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ Additional classes to add to the (injected) wrapper `<div>`.
Type: `Array` Default: `null`
Specify the ordering for the country list with an array of iso2 country codes. Any ommitted countries will appear after those specified e.g. setting `countryOrder` to `["jp", "kr"]` will result in the list: Japan, South Korea, Afghanistan, Albanbia, Algeria etc...

**countrySearch**
Type: `Boolean` Default: `true`
Add a search input to the top of the dropdown, so users can filter the displayed countries.

**customPlaceholder**
Type: `Function` Default: `null`
Change the placeholder generated by autoPlaceholder. Must return a string.
Expand Down
2 changes: 2 additions & 0 deletions build/js/intlTelInput.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ declare module "intl-tel-input" {
autoPlaceholder: string;
containerClass: string;
countryOrder: string[];
countrySearch: boolean;
customPlaceholder: ((selectedCountryPlaceholder: string, selectedCountryData: object) => string) | null;
dropdownContainer: HTMLElement | null;
excludeCountries: string[];
Expand Down Expand Up @@ -934,6 +935,7 @@ declare module "intl-tel-input" {
private _openDropdown;
private _setDropdownPosition;
private _bindDropdownListeners;
private _searchForCountry;
private _filterCountries;
private _updateSearchResultsText;
private _handleUpDownKey;
Expand Down
158 changes: 102 additions & 56 deletions build/js/intlTelInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,8 @@ var factoryOutput = (() => {
containerClass: "",
//* The order of the countries in the dropdown. Defaults to alphabetical.
countryOrder: null,
//* Add a country search input at the top of the dropdown.
countrySearch: true,
//* Modify the auto placeholder.
customPlaceholder: null,
//* Append menu to specified element.
Expand Down Expand Up @@ -1524,6 +1526,7 @@ var factoryOutput = (() => {
if (this.options.separateDialCode) {
this.options.allowDropdown = true;
this.options.nationalMode = false;
this.options.countrySearch = true;
}
if (!this.options.showFlags && !this.options.separateDialCode) {
this.options.nationalMode = false;
Expand Down Expand Up @@ -1676,6 +1679,7 @@ var factoryOutput = (() => {
dropdownContainer,
fixDropdownWidth,
useFullscreenPopup,
countrySearch,
i18n
} = this.options;
let parentClass = "iti";
Expand Down Expand Up @@ -1752,26 +1756,28 @@ var factoryOutput = (() => {
id: `iti-${this.id}__dropdown-content`,
class: `iti__dropdown-content iti__hide ${extraClasses}`
});
this.searchInput = createEl(
"input",
{
type: "text",
class: "iti__search-input",
placeholder: i18n.searchPlaceholder,
role: "combobox",
"aria-expanded": "true",
"aria-label": i18n.searchPlaceholder,
"aria-controls": `iti-${this.id}__country-listbox`,
"aria-autocomplete": "list",
"autocomplete": "off"
},
this.dropdownContent
);
this.searchResultsA11yText = createEl(
"span",
{ class: "iti__a11y-text" },
this.dropdownContent
);
if (countrySearch) {
this.searchInput = createEl(
"input",
{
type: "text",
class: "iti__search-input",
placeholder: i18n.searchPlaceholder,
role: "combobox",
"aria-expanded": "true",
"aria-label": i18n.searchPlaceholder,
"aria-controls": `iti-${this.id}__country-listbox`,
"aria-autocomplete": "list",
"autocomplete": "off"
},
this.dropdownContent
);
this.searchResultsA11yText = createEl(
"span",
{ class: "iti__a11y-text" },
this.dropdownContent
);
}
this.countryList = createEl(
"ul",
{
Expand All @@ -1782,8 +1788,10 @@ var factoryOutput = (() => {
},
this.dropdownContent
);
this._appendListItems(this.countries, "iti__standard");
this._updateSearchResultsText();
this._appendListItems();
if (countrySearch) {
this._updateSearchResultsText();
}
if (dropdownContainer) {
let dropdownClasses = "iti iti--container";
if (useFullscreenPopup) {
Expand Down Expand Up @@ -1818,15 +1826,16 @@ var factoryOutput = (() => {
}
}
}
//* For each of the passed countries: add a country <li> to the countryList <ul> container.
_appendListItems(countries, className) {
for (let i = 0; i < countries.length; i++) {
const c = countries[i];
//* For each country: add a country list item <li> to the countryList <ul> container.
_appendListItems() {
for (let i = 0; i < this.countries.length; i++) {
const c = this.countries[i];
const extraClass = i === 0 ? "iti__highlight" : "";
const listItem = createEl(
"li",
{
id: `iti-${this.id}__item-${c.iso2}`,
class: `iti__country ${className}`,
class: `iti__country ${extraClass}`,
tabindex: "-1",
role: "option",
"data-dial-code": c.dialCode,
Expand Down Expand Up @@ -2067,24 +2076,26 @@ var factoryOutput = (() => {
}
//* Open the dropdown.
_openDropdown() {
const { fixDropdownWidth } = this.options;
const { fixDropdownWidth, countrySearch } = this.options;
if (fixDropdownWidth) {
this.dropdownContent.style.width = `${this.telInput.offsetWidth}px`;
}
this.dropdownContent.classList.remove("iti__hide");
this.selectedCountry.setAttribute("aria-expanded", "true");
this._setDropdownPosition();
const firstCountryItem = this.countryList.firstElementChild;
if (firstCountryItem) {
this._highlightListItem(firstCountryItem, false);
this.countryList.scrollTop = 0;
if (countrySearch) {
const firstCountryItem = this.countryList.firstElementChild;
if (firstCountryItem) {
this._highlightListItem(firstCountryItem, false);
this.countryList.scrollTop = 0;
}
this.searchInput.focus();
}
this.searchInput.focus();
this._bindDropdownListeners();
this.dropdownArrow.classList.add("iti__arrow--up");
this._trigger("open:countrydropdown");
}
//* Decide if should position dropdown above or below input (depends on position within viewport, and scroll).
//* Set the dropdown position
_setDropdownPosition() {
if (this.options.dropdownContainer) {
this.options.dropdownContainer.appendChild(this.dropdown);
Expand Down Expand Up @@ -2130,6 +2141,8 @@ var factoryOutput = (() => {
"click",
this._handleClickOffToClose
);
let query = "";
let queryTimer = null;
this._handleKeydownOnDropdown = (e) => {
if (["ArrowUp", "ArrowDown", "Enter", "Escape"].includes(e.key)) {
e.preventDefault();
Expand All @@ -2142,29 +2155,56 @@ var factoryOutput = (() => {
this._closeDropdown();
}
}
};
document.addEventListener("keydown", this._handleKeydownOnDropdown);
const doFilter = () => {
const inputQuery = this.searchInput.value.trim();
if (inputQuery) {
this._filterCountries(inputQuery);
} else {
this._filterCountries("", true);
if (!this.options.countrySearch && /^[a-zA-ZÀ-ÿа-яА-Я ]$/.test(e.key)) {
e.stopPropagation();
if (queryTimer) {
clearTimeout(queryTimer);
}
query += e.key.toLowerCase();
this._searchForCountry(query);
queryTimer = setTimeout(() => {
query = "";
}, 1e3);
}
};
let keyupTimer = null;
this._handleSearchChange = () => {
if (keyupTimer) {
clearTimeout(keyupTimer);
document.addEventListener("keydown", this._handleKeydownOnDropdown);
if (this.options.countrySearch) {
const doFilter = () => {
const inputQuery = this.searchInput.value.trim();
if (inputQuery) {
this._filterCountries(inputQuery);
} else {
this._filterCountries("", true);
}
};
let keyupTimer = null;
this._handleSearchChange = () => {
if (keyupTimer) {
clearTimeout(keyupTimer);
}
keyupTimer = setTimeout(() => {
doFilter();
keyupTimer = null;
}, 100);
};
this.searchInput.addEventListener("input", this._handleSearchChange);
this.searchInput.addEventListener("click", (e) => e.stopPropagation());
}
}
//* Hidden search (countrySearch disabled): Find the first list item whose name starts with the query string.
_searchForCountry(query) {
for (let i = 0; i < this.countries.length; i++) {
const c = this.countries[i];
const startsWith = c.name.substr(0, query.length).toLowerCase() === query;
if (startsWith) {
const listItem = c.nodeById[this.id];
this._highlightListItem(listItem, false);
this._scrollTo(listItem);
break;
}
keyupTimer = setTimeout(() => {
doFilter();
keyupTimer = null;
}, 100);
};
this.searchInput.addEventListener("input", this._handleSearchChange);
this.searchInput.addEventListener("click", (e) => e.stopPropagation());
}
}
//* Country search enabled: Filter the countries according to the search query.
_filterCountries(query, isReset = false) {
let noCountriesAddedYet = true;
this.countryList.innerHTML = "";
Expand Down Expand Up @@ -2292,7 +2332,9 @@ var factoryOutput = (() => {
this.highlightedItem.setAttribute("aria-selected", "true");
const activeDescendant = this.highlightedItem.getAttribute("id") || "";
this.selectedCountry.setAttribute("aria-activedescendant", activeDescendant);
this.searchInput.setAttribute("aria-activedescendant", activeDescendant);
if (this.options.countrySearch) {
this.searchInput.setAttribute("aria-activedescendant", activeDescendant);
}
}
if (shouldFocus) {
this.highlightedItem.focus();
Expand Down Expand Up @@ -2449,10 +2491,14 @@ var factoryOutput = (() => {
if (this.highlightedItem) {
this.highlightedItem.setAttribute("aria-selected", "false");
}
this.searchInput.removeAttribute("aria-activedescendant");
if (this.options.countrySearch) {
this.searchInput.removeAttribute("aria-activedescendant");
}
this.dropdownArrow.classList.remove("iti__arrow--up");
document.removeEventListener("keydown", this._handleKeydownOnDropdown);
this.searchInput.removeEventListener("input", this._handleSearchChange);
if (this.options.countrySearch) {
this.searchInput.removeEventListener("input", this._handleSearchChange);
}
document.documentElement.removeEventListener(
"click",
this._handleClickOffToClose
Expand Down
2 changes: 1 addition & 1 deletion build/js/intlTelInput.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit a725d73

Please sign in to comment.