Навигация с клавиатуры

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

Базовая модель фокуса

При открытии календаря Pikaday устанавливает фокус на активной дате. Если значение поля уже задано, фокусируется соответствующий день. При отсутствии выбранной даты используется текущая дата или первый доступный день месяца, в зависимости от конфигурации и ограничений (minDate, maxDate).

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

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

Открытие и первичная активация

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

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

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

Перемещение по дням

Основной механизм навигации реализуется через стрелочные клавиши:

  • ArrowLeft — переход к предыдущему дню;
  • ArrowRight — переход к следующему дню;
  • ArrowUp — переход на неделю назад;
  • ArrowDown — переход на неделю вперед.

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

Если включены ограничения minDate и maxDate, навигация блокируется на недоступных датах. В таких случаях фокус либо остается на текущем элементе, либо перескакивает к ближайшему допустимому значению.

Особое значение имеет обработка неактивных дней (например, отключенных через disableDayFn). Такие ячейки пропускаются при навигации, что обеспечивает непрерывное перемещение по валидным датам.

Переключение месяцев

Для быстрого изменения периода используются клавиши:

  • PageUp — переход к предыдущему месяцу;
  • PageDown — переход к следующему месяцу.

При этом активная дата сохраняет свой день месяца, если он существует в новом месяце. Если соответствующего дня нет (например, переход с 31 января на февраль), выбирается последний доступный день месяца.

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

Переключение годов

В стандартной конфигурации Pikaday поддерживает ускоренное изменение года:

  • Shift + PageUp — переход на предыдущий год;
  • Shift + PageDown — переход на следующий год.

Такая комбинация позволяет быстро перемещаться по большим временным диапазонам без последовательной смены месяцев.

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

Выбор даты

Клавиша Enter используется для подтверждения текущей активной даты. При нажатии происходит:

  • установка значения в связанное input-поле;
  • вызов callback-функции onSelect, если она задана;
  • обновление состояния компонента;
  • при необходимости закрытие календаря.

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

Если активная ячейка недоступна (например, из-за ограничения диапазона), подтверждение не происходит, и фокус остается на текущем элементе.

Закрытие календаря

Закрытие компонента осуществляется клавишей Escape. Поведение включает:

  • скрытие DOM календаря;
  • возврат фокуса в поле ввода (если календарь привязан к input);
  • сохранение или отмену текущего состояния в зависимости от настроек.

Закрытие через Escape является критическим элементом доступности, позволяющим быстро выйти из режима выбора даты без завершения действия.

Tab-навигация и управление фокусом

Клавиша Tab выводит фокус из календаря. Pikaday не реализует жесткий focus trap по умолчанию, что соответствует общей практике HTML-компонентов: пользователь может покинуть календарь и перейти к следующему интерактивному элементу страницы.

Однако при интеграции в модальные окна или кастомные UI-контейнеры часто добавляется внешний focus trap, который ограничивает перемещение внутри диалога. В таких случаях календарь должен корректно взаимодействовать с родительским механизмом управления фокусом.

Shift + Tab обеспечивает обратное перемещение по таб-цепочке, также без специальной логики внутри Pikaday.

Поведение при ограничениях дат

Клавиатурная навигация тесно связана с настройками диапазона:

  • minDate ограничивает движение назад;
  • maxDate ограничивает движение вперед.

При достижении границы диапазона:

  • стрелочные клавиши не переводят фокус на недопустимые даты;
  • PageUp/PageDown корректируются к ближайшему допустимому месяцу;
  • Enter блокируется для недопустимых значений.

Это обеспечивает согласованность между визуальным состоянием и фактическими данными.

Работа с неактивными днями

Функция disableDayFn позволяет отключать отдельные даты на уровне бизнес-логики. Такие даты:

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

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

Клавиатурные события и внутренний обработчик

Внутренний обработчик клавиш Pikaday анализирует keydown события и сопоставляет их с действиями календаря. Логика обработки обычно включает:

  • определение кода клавиши;
  • вычисление новой даты относительно текущей активной;
  • проверку валидности нового значения;
  • обновление состояния компонента;
  • перерисовку UI при необходимости.

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

Доступность и ARIA-атрибуты

Клавиатурная навигация тесно связана с доступностью. Pikaday использует ARIA-атрибуты для обозначения роли календаря и текущего состояния элементов:

  • role="dialog" или role="application" для контейнера;
  • aria-selected для активной даты;
  • aria-disabled для недоступных дней;
  • aria-live для обновления заголовков месяца.

Фокусируемые элементы получают корректные состояния, позволяющие screen reader-устройствам интерпретировать изменения месяца и выбранной даты.

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

Особенности поведения в разных режимах

В зависимости от конфигурации Pikaday клавиатурная навигация может изменяться:

  • при bound: false календарь может работать как независимый компонент, сохраняя фокус внутри себя;
  • при field-привязке поведение Enter и Escape влияет на input напрямую;
  • при кастомных форматах даты логика выбора сохраняется, но отображение меняется только на уровне представления.

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

Производительность обработки ввода

Клавиатурная навигация оптимизирована под минимальное количество перерисовок DOM. Изменение активной даты приводит к:

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

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

Итоговые принципы взаимодействия

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