Компонент для номера телефона
Около месяца назад я писал пост про библиотеку imask, чтобы стандартизировать ввод номера телефона, с помощью использования маски. Тогда же я упомянул, что основным минусом, на мой взгляд, является то, что нужно написать много дополнительного кода, чтобы достичь желаемого результата.
Пару недель назад я как раз столкнулся с подобной задачей в рамках проекта на react и захотел попробовать реализовать это с помощью imask, но столкнулся с проблемой: нужно отображать список стран, с привязанным к ним кодом. В imask есть возможность решить это, но нет готового набора кодов номеров телефонов. Я вспомнил о решении, которое мои сотрудники находили. Попробовал его адаптировать и понял, что я особо не могу его кастомизировать (по дизайну требовалось выводить двухбуквенное название страны, а не флаг), несмотря на его описание, — "Advanced, highly customizable phone input component for Ant Design."
Поняв, что нахожусь в сложной ситуации, я пошёл искать библиотеки, которые предоставляют просто список телефонных кодов по странам, чтобы реализовать это с помощью imask и нашёл такое решение. По сути, это простая библиотечка, которая возвращает нам объект из пар ключ-значение в том формате, в котором нам необходимо. Казалось бы, всё замечательно. Можно брать динамически маски в imask, генерировать их с помощью этих самых кодов и идти спокойно пить чай. Но в этот момент я осознал, что у разных стран, буквально, могут быть разные маски для ввода номера телефона и это окончательно закопало мою прекрасную идею об использовании imask для решения этой задачи.
Пример с самого сайта imask, где наглядно видно, что маски вообще не подчиняются единым правилам и могут выглядеть абсолютно как угодно:
[ { mask: '+00 {21} 0 000 0000', startsWith: '30', lazy: false, country: 'Greece' }, { mask: '+0 000 000-00-00', startsWith: '7', lazy: false, country: 'Russia' }, { mask: '+00-0000-000000', startsWith: '91', lazy: false, country: 'India' }, { mask: '0000000000000', startsWith: '', country: 'unknown' } ]
Ресёрч пришлось продолжать. Я нашёл библиотеку, которая позволяла валидировать номер телефона относительно двухбуквенного кода страны, к которой этот номер относится. Кроме прочего, в этой библиотеке есть и возможность форматирования номера телефона, как раз под маску, принятую в конкретной стране. В описании библиотеки также упоминался react-компонент, который использует эту самую библиотеку. И на основе уже этого компонента, я собрал своё решение с использованием ant-design (разумеется, оно не идеальное, но достаточно хорошее, чтобы использовать в условном продакшне):
import PhoneInput from 'react-phone-number-input'; import PropTypes from 'prop-types'; import { getCountries } from 'react-phone-number-input'; import { Select as AntdSelect } from 'antd'; const phoneCountryLabels = () => { const countryLabels = {}; getCountries().forEach((country) => (countryLabels[country] = country)); return countryLabels; }; const CountrySelect = ({ value, onChange, labels, variant = 'filled', ...rest }) => ( <AntdSelect {...rest} value={value} showSearch optionFilterProp="label" onChange={onChange} variant={variant} size="large" style={{ '--ant-select-single-item-height-lg': '3rem' }} /> ); CountrySelect.propTypes = { value: PropTypes.string, onChange: PropTypes.func.isRequired, labels: PropTypes.objectOf(PropTypes.string).isRequired, variant: PropTypes.string, }; const PhoneNumberInput = ({ onChange, country = 'US' }) => { return ( <div className="base-phone-number"> <PhoneInput onChange={onChange} defaultCountry={country} international limitMaxLength labels={phoneCountryLabels()} countrySelectComponent={CountrySelect} numberInputProps={{ className: 'ant-input ant-input-filled css-var-r1 ant-input-css-var base-input', }} /> </div> ); }; PhoneNumberInput.propTypes = { onChange: PropTypes.func.isRequired, country: PropTypes.string, }; export default PhoneNumberInput;
А как вы решали подобные задачи? Делитесь, будет интересно узнать.
P. S. как появится немного времени, планирую тоже самое адаптировать под vue-компонент и поделиться результатом