Сложные составные маски

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

Основой сложной маски является концепция blocks — массивов, определяющих длину сегментов ввода. Каждый блок задаёт количество символов, которые пользователь может ввести до автоматического перехода к следующему сегменту.

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

В данном примере формируется структура вида:

XXX-XXX-XXXX

где каждый блок строго ограничен по длине. При усложнении структуры блоки начинают комбинироваться с разными типами разделителей, создавая многоуровневые шаблоны.

Комбинирование блоков и разделителей

Составная маска формируется за счёт синхронизации двух массивов:

  • blocks — длины сегментов
  • delimiters — символы-разделители между ними
{
    blocks: [4, 4, 4, 4],
    delimiters: [' ', ' ', ' ']
}

Результат:

XXXX XXXX XXXX XXXX

При усложнении логики важно учитывать, что количество разделителей всегда равно blocks.length - 1. Нарушение этого соотношения приводит к некорректному отображению ввода.

Составные телефонные маски

Телефонные номера являются классическим примером сложных составных масок, поскольку включают:

  • международный код
  • региональный код
  • локальный номер
  • иногда добавочный номер
{
    prefix: '+',
    blocks: [3, 2, 3, 2, 2],
    delimiters: [' ', ' ', ' ', ' ']
}

Формат:

+XXX XX XXX XX XX

Более сложные сценарии требуют адаптации под разные страны. Здесь используется динамическая пересборка конфигурации.

Динамическая смена маски

Сложные составные маски часто не фиксированы. Например, телефон может изменять структуру при вводе кода страны.

cleave.setPhoneRegion('RU');

или через обновление опций:

cleave.setRawValue('');
cleave.destroy();

cleave = new Cleave(input, {
    blocks: [1, 3, 3, 2, 2],
    delimiters: [' ', ' ', '-', '-']
});

Подход через пересоздание инстанса применяется, когда структура полностью меняется, а не модифицируется частично.

Комбинирование числовых и буквенных блоков

Составные маски не ограничиваются цифрами. В одном поле могут использоваться разные типы символов.

{
    blocks: [2, 4, 2],
    delimiters: ['-', '-'],
    uppercase: true
}

Пример:

AB-12CD-EF

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

Составные маски для документов

Документные форматы (серийные номера, ID, лицензии) часто имеют фиксированную, но сложную структуру.

Пример:

AA-1234-BC-5678
{
    blocks: [2, 4, 2, 4],
    delimiters: ['-', '-', '-'],
    uppercase: true
}

Такие маски требуют строгого контроля длины, так как отклонение от структуры делает значение невалидным.

Кредитные карты как составная структура

Номер банковской карты — один из наиболее известных кейсов сложной маски.

{
    blocks: [4, 4, 4, 4],
    delimiters: [' ', ' ', ' ']
}

Однако реальные сценарии сложнее, поскольку разные платёжные системы имеют различную длину:

  • 16 цифр (Visa, MasterCard)
  • 15 цифр (American Express)
  • 19 цифр (некоторые банковские системы)

Поэтому применяется динамическое определение блока:

function getBlocksByCardType(type) {
    switch(type) {
        case 'amex':
            return [4, 6, 5];
        default:
            return [4, 4, 4, 4];
    }
}

Условные составные маски

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

cleave.on('valueChanged', function(e) {
    if (e.target.rawValue.startsWith('8')) {
        cleave.setPhoneRegion('RU');
    }
});

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

Многоуровневые составные структуры

Сложные маски могут включать несколько уровней логики:

  1. базовая структура (blocks + delimiters)
  2. фильтрация символов
  3. преобразование регистра
  4. динамическое изменение структуры
  5. постобработка rawValue

Пример комбинированной конфигурации:

{
    blocks: [3, 3, 4],
    delimiters: ['-', '-'],
    uppercase: true,
    numericOnly: true
}

Такая маска уже не является просто форматированием — она становится мини-парсером ввода.

Составные маски с префиксами

Префикс часто выступает фиксированной частью структуры, вокруг которой строится остальная маска.

{
    prefix: 'ID-',
    blocks: [2, 4, 3],
    delimiters: ['-', '-']
}

Результат:

ID-XX-XXXX-XXX

Особенность префиксов в том, что они не участвуют в блоковой логике, но влияют на расчёт позиции курсора.

Проблемы позиционирования курсора

При усложнении масок возникает ключевая проблема — смещение каретки.

Основные причины:

  • неодинаковая длина блоков
  • динамическая вставка разделителей
  • изменение значения через API

При неправильной настройке курсор может “прыгать” при вводе или удалении символов.

Рекомендуемый подход — избегать частого пересоздания инстанса и использовать обновление значений через API библиотеки.

Составные маски с переменной длиной последнего блока

Частый сценарий — последний блок переменной длины:

{
    blocks: [3, 3, 5],
    noImmediatePrefix: true
}

Здесь третий блок может расширяться, что позволяет вводить дополнительные символы без жёсткого ограничения.

Гибридные форматы (цифры + текст + разделители)

Сложные маски часто комбинируют разные типы данных:

AB12-CD34-XY56
{
    blocks: [4, 4, 4],
    delimiters: ['-', '-'],
    uppercase: true
}

Однако реальная сложность возникает не в конфигурации, а в необходимости поддерживать валидность на уровне бизнес-логики.

Постобработка rawValue

Составные маски не ограничиваются отображением. Важным аспектом является rawValue — значение без форматирования.

cleave.on('valueChanged', function(e) {
    console.log(e.target.rawValue);
});

При сложных масках часто требуется:

  • удаление префиксов
  • нормализация кодов стран
  • преобразование в стандартный формат хранения

Ограничения сложных составных масок

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

  • отсутствие встроенной системы условных ветвлений внутри одной маски
  • ограниченная поддержка вложенных структур
  • необходимость ручного управления динамическими сценариями

Поэтому сложные маски в Cleave.js чаще представляют собой комбинацию конфигурации библиотеки и внешней логики приложения.

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

В реальных приложениях составные маски обычно строятся по следующей схеме:

  • базовый шаблон (blocks + delimiters)
  • слой адаптации под тип данных
  • обработчики событий ввода
  • механизм переключения конфигурации
  • нормализация значения перед сохранением

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