Управление фокусом и навигацией

Модель управления фокусом в Cleave.js строится вокруг идеи виртуального разбиения одного DOM-инпута на логические блоки ввода. Несмотря на то, что на уровне HTML используется один <input>, библиотека ведёт себя так, как будто поле состоит из нескольких сегментов. Это напрямую влияет на поведение курсора, обработку клавиш, переходы между частями значения и реакцию на удаление символов.

Ключевой особенностью является то, что Cleave.js не создаёт дополнительных элементов для каждого сегмента. Вместо этого фокус остаётся в одном input, а навигация реализуется через управление позиции курсора (selectionStart, selectionEnd) и трансформацию значения.

Внутренний цикл обработки фокуса

Каждое событие ввода проходит через несколько этапов:

  • перехват события (keydown, input, focus, blur)
  • нормализация значения (rawValue)
  • применение маски или форматтера
  • пересчёт отображаемого значения
  • восстановление позиции курсора

После каждого изменения Cleave.js пытается восстановить логическую позицию курсора, соответствующую “сырому” значению, а не форматированному.

Это особенно важно при форматировании чисел, дат и телефонных номеров, где добавляются разделители, влияющие на физические позиции символов.

Управление курсором и mapping позиций

Основная проблема форматированных input — несоответствие между индексами raw-строки и отображаемой строки.

Cleave.js решает это через построение отображаемого offset-map:

  • raw index → formatted index
  • formatted index → raw index

При каждом вводе символа:

  1. фиксируется текущая позиция курсора
  2. вычисляется соответствующий индекс в raw-строке
  3. выполняется вставка/удаление
  4. формируется новое форматированное значение
  5. курсор возвращается на пересчитанную позицию

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

Поведение при вводе и удалении символов

Ввод символов

При вставке символа в середину строки Cleave.js:

  • извлекает raw-значение
  • вставляет символ в соответствующую позицию raw-строки
  • пересобирает formatted output
  • корректирует курсор с учётом добавленных разделителей

Особое внимание уделяется случаям, когда формат добавляет символы автоматически (например, +7 (___) ___-__-__).

Backspace и Delete

Удаление символов требует обратного отображения:

  • Backspace удаляет символ слева от курсора в raw-модели
  • Delete удаляет символ справа

При этом разделители формата игнорируются как “невидимые” элементы. Это создаёт эффект удаления только значимых символов.

Навигация между блоками ввода

В конфигурациях Cleave.js, где используется несколько логических блоков (например, дата или кредитная карта), навигация реализуется через:

  • анализ текущего блока
  • определение границ сегмента
  • принудительный перенос курсора

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

Важное поведение:

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

Работа с программным фокусом

Cleave.js не управляет фокусом DOM напрямую, но предоставляет поведение, которое взаимодействует с внешними системами управления формами.

Типовые сценарии:

  • установка фокуса на input через element.focus()
  • восстановление позиции курсора после программного изменения value
  • синхронизация с React/Vue state-менеджерами

При программной установке значения:

  1. вызывается метод обновления instance
  2. значение форматируется
  3. курсор устанавливается в конец или в сохранённую позицию

При этом библиотека пытается минимизировать “прыжки” курсора, характерные для controlled inputs.

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

При blur Cleave.js фиксирует:

  • текущее raw-значение
  • позицию курсора
  • состояние форматирования

При focus:

  • пересчитывается отображение (если требуется)
  • восстанавливается курсор
  • синхронизируется internal state

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

Сценарии с множественными input-полями

При использовании нескольких экземпляров Cleave.js в одной форме возникает необходимость координации фокуса между полями.

Типовые схемы поведения:

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

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

Управление навигацией в числовых форматах

Числовые поля демонстрируют особое поведение:

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

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

Поведение при автозаполнении браузера

Autofill создаёт дополнительные сложности для навигации:

  • значение вставляется мгновенно
  • события input могут агрегироваться
  • курсор устанавливается браузером произвольно

Cleave.js реагирует на это полной переработкой value и принудительной нормализацией состояния после события change.

Поддержка клавиатурной навигации

Обработка клавиш включает:

  • стрелки (← →) — смещение по raw-символам
  • Home/End — переход к началу или концу raw-значения
  • Tab — стандартный переход фокуса вне поля
  • Backspace/Delete — удаление значимых символов

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

Взаимодействие с мобильными клавиатурами

На мобильных устройствах Cleave.js учитывает:

  • особенности автокоррекции
  • вставку групп символов
  • нестабильность selection API

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

Стабилизация позиции курсора

Одной из ключевых задач является предотвращение “прыгающего курсора”. Для этого используется стратегия:

  • сохранение logicalIndex до изменения
  • пересчёт formattedIndex после форматирования
  • восстановление позиции с учётом вставленных символов

Если точное восстановление невозможно, курсор смещается к ближайшей валидной позиции внутри текущего сегмента.

Особенности интеграции с внешними библиотеками форм

При использовании с React, Vue или Angular управление фокусом часто становится конкурирующим процессом между:

  • виртуальным DOM
  • Cleave.js internal state
  • native input behaviour

Чтобы избежать конфликтов, Cleave.js опирается на минимальные DOM-операции и не вмешивается в lifecycle фреймворков, ограничиваясь только перерасчётом значения и курсора.

Ограничения модели навигации

Система имеет ряд ограничений:

  • невозможность полноценного multi-cursor поведения
  • ограниченная работа с выделением диапазонов
  • зависимость от корректной работы selection API браузера
  • потенциальные рассинхронизации при внешнем обновлении value без уведомления instance

Эти ограничения связаны с тем, что вся логика навигации построена поверх одного DOM-элемента без виртуального разделения на реальные input-поля.

Согласование фокуса и форматирования

Финальный аспект — синхронизация форматирования с активным фокусом.

При активном вводе:

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

При неактивном фокусе:

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

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