Создание кастомных телефонных масок

Телефонные маски в Cleave.js строятся на основе декларативного описания структуры номера: блоков цифр, разделителей, префиксов и правил региональной логики. Несмотря на наличие встроенной поддержки телефонов, реальные проекты почти всегда требуют расширения стандартного поведения — из-за различий национальных форматов, корпоративных шаблонов или нестандартных правил ввода.

Кастомная телефонная маска в этом контексте представляет собой конфигурацию, в которой разработчик явно контролирует:

  • структуру номера (blocks),
  • символы-разделители (delimiters),
  • поведение ввода (numericOnly, noImmediatePrefix),
  • наличие и позицию кода страны (prefix),
  • динамическую смену формата.

Базовая модель телефонной маски

В основе телефонной логики Cleave.js лежит разбиение строки на блоки фиксированной или переменной длины.

Типичная структура:

new Cleave(input, {
    phone: true,
    phoneRegionCode: 'US'
});

Однако такой вариант ограничен стандартными форматами региона и не подходит для кастомных схем, например:

  • корпоративные внутренние номера: +7 (123) 456-78-90-01
  • гибридные форматы с добавочным кодом
  • номера с нестандартной длиной последнего блока

Полный контроль через blocks и delimiters

Ключевой механизм кастомизации — ручное определение структуры номера.

new Cleave(input, {
    delimiters: ['(', ')', ' ', '-'],
    blocks: [2, 3, 3, 2, 2],
    numericOnly: true
});

Логика blocks

Массив blocks определяет, как именно вводимые цифры группируются:

  • первый блок — код страны или региона
  • второй — код оператора или города
  • последующие — локальный номер
  • финальные блоки — расширения или внутренние добавочные

Например:

+7 (123) 456-78-90

раскладывается как:

[1-2] [3] [3] [2] [2]

Важный момент: Cleave.js не ограничивает длину массива blocks, что позволяет строить сложные телефонные схемы, включая корпоративные расширения.


Работа с префиксами и кодами стран

Для телефонных масок критично правильно управлять международным префиксом.

new Cleave(input, {
    prefix: '+7',
    noImmediatePrefix: true,
    blocks: [2, 3, 3, 2, 2],
    delimiters: [' ', ' ', '-']
});

Поведение prefix

  • prefix фиксирует начальную часть строки

  • noImmediatePrefix контролирует момент его появления:

    • true — префикс появляется только после начала ввода
    • false — отображается сразу

Это особенно важно для UX, поскольку предотвращает ситуации, когда пользователь вынужден стирать фиксированный код страны.


Разделители как инструмент семантики номера

В кастомных масках разделители играют не только визуальную роль, но и семантическую.

Пример:

delimiters: [' ', ' ', '-', '-']

Формирует номер:

+7 777 123-45-67

Разделители могут:

  • улучшать читаемость
  • подчеркивать структуру региона
  • отделять логические сегменты (код / оператор / абонент)

В Cleave.js разделители применяются строго по позиции блоков, что позволяет гарантировать предсказуемый результат независимо от скорости ввода.


Динамические телефонные маски

Одно из ключевых требований реальных интерфейсов — смена формата в зависимости от выбранной страны или типа номера.

Подход реализуется через пересоздание экземпляра или обновление конфигурации:

let cleave = new Cleave(input, {
    numericOnly: true,
    blocks: [3, 3, 4],
    delimiters: ['-', '-']
});

// смена формата
cleave.destroy();

cleave = new Cleave(input, {
    prefix: '+44',
    numericOnly: true,
    blocks: [2, 4, 4],
    delimiters: [' ', ' ']
});

Такой подход позволяет реализовать:

  • выбор страны через dropdown
  • автоматическое переключение формата
  • адаптацию под тип номера (мобильный / городской / внутренний)

Интеграция пользовательской логики форматирования

Кастомные телефонные маски часто выходят за рамки стандартных конфигураций и требуют вмешательства в поток данных.

Для этого используется обработка события изменения значения:

new Cleave(input, {
    numericOnly: true,
    blocks: [3, 3, 4],
    onValueChanged: function (e) {
        const raw = e.target.rawValue;
    }
});

rawValue как источник истины

  • rawValue содержит чистую последовательность цифр
  • форматированное значение — лишь визуальное представление

Это разделение критично при:

  • валидации номера
  • отправке данных на сервер
  • интеграции с CRM или API телефонии

Нестандартные маски с расширениями

Во многих системах телефон включает добавочный номер:

+1 (212) 555-1234 x99

Реализация через Cleave.js:

new Cleave(input, {
    prefix: '+1',
    blocks: [3, 3, 4, 2],
    delimiters: [' (', ') ', '-', ' x']
});

Такая структура позволяет:

  • отделить основной номер
  • явно обозначить extension
  • сохранить читаемость без дополнительной логики UI

Ограничения и обход нестандартных сценариев

Несмотря на гибкость, система масок имеет ограничения:

1. Отсутствие условных блоков

Нельзя напрямую задать:

  • “если страна X — использовать один формат”
  • “если длина больше N — менять структуру”

Это компенсируется внешней логикой.

2. Фиксированная позиционность

blocks и delimiters работают позиционно, а не контекстно.

3. Ограниченная семантика ввода

Библиотека не понимает смысл номера — только структуру.


Гибридные стратегии кастомизации

Для сложных систем применяется комбинация подходов:

  • внешний контроллер формата (страна / тип номера)
  • пересоздание инстанса Cleave.js
  • хранение rawValue как единственного источника данных
  • валидация через отдельные библиотеки (например, libphonenumber)

Пример архитектурного подхода:

  1. UI выбирает страну
  2. логика определяет маску
  3. Cleave пересоздаётся
  4. ввод форматируется только визуально
  5. отправляется rawValue

Практическая структура сложной телефонной маски

Пример универсального кастомного шаблона:

new Cleave(input, {
    prefix: '+',
    numericOnly: true,
    blocks: [3, 3, 3, 4],
    delimiters: [' ', ' ', ' ']
});

Подходит для унифицированных систем, где:

  • международный код фиксирован по длине
  • локальная часть стандартизирована
  • отсутствуют расширения

Поведение при редактировании внутри строки

Важная особенность Cleave.js — перерасчёт структуры при изменении любого символа внутри строки.

Это означает:

  • удаление символа пересобирает всю маску
  • вставка в середину не нарушает блоки
  • курсор автоматически корректируется

Это поведение критично для UX, поскольку предотвращает “разрушение” форматирования при редактировании.


Итоговая модель проектирования кастомных телефонных масок

Архитектурно кастомная маска в Cleave.js строится как комбинация:

  • структурного описания (blocks + delimiters)
  • фиксированных элементов (prefix)
  • режимов поведения ввода (numericOnly, noImmediatePrefix)
  • внешнего управления логикой формата
  • работы с rawValue как источником данных

Такой подход позволяет адаптировать библиотеку под любые телефонные стандарты без изменения её внутренней логики.