ally.when.focusable

ally.when.focusable — это функция из библиотеки ally.js, предназначенная для управления доступностью элементов на странице. Она позволяет определить момент, когда элемент становится фокусируемым, и выполнить заданное действие в этот момент. Основное преимущество этого подхода — обработка динамически изменяемых интерфейсов, где элементы могут появляться, исчезать или меняться в DOM.

Функция возвращает промис, который разрешается, когда элемент удовлетворяет условиям фокусируемости.

ally.when.focusable(element).then(function(el) {
  console.log('Элемент готов к фокусу:', el);
});

Параметры и сигнатура

ally.when.focusable(target, options)
  • target — селектор CSS, DOM-элемент или NodeList.

  • options — объект с дополнительными настройками:

    • visible (boolean) — учитывать ли видимость элемента. По умолчанию true.
    • ignore (string|Node|NodeList) — исключает определенные элементы из проверки.
    • timeout (number) — максимальное время ожидания в миллисекундах.

Пример с опциями:

ally.when.focusable('#submit-button', {
  visible: true,
  timeout: 5000
}).then(function(button) {
  button.focus();
});

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

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

  • Если элемент никогда не станет фокусируемым до истечения timeout, промис будет отклонён с ошибкой.
  • Если timeout не указан, промис будет ожидать неограниченно, что полезно для динамически создаваемых интерфейсов, таких как модальные окна или асинхронные компоненты.
ally.when.focusable('.modal input', { timeout: 3000 })
  .then(input => input.focus())
  .catch(error => console.error('Элемент не стал фокусируемым:', error));

Основные сценарии применения

  1. Фокус на модальных окнах Модальные окна часто создаются динамически. ally.when.focusable позволяет автоматически поставить фокус на первый интерактивный элемент:

    function openModal() {
      const modal = document.querySelector('.modal');
      modal.style.display = 'block';
    
      ally.when.focusable(modal.querySelector('input'))
        .then(input => input.focus());
    }
  2. Динамически загружаемые элементы Если кнопка или форма подгружаются через AJAX, промис отслеживает появление:

    ally.when.focusable('#dynamic-button')
        .then(button => button.click());
  3. Игнорирование скрытых или неактивных элементов Опция visible: true предотвращает фокусировку на скрытых элементах, что улучшает UX и соответствует стандартам доступности.

Внутренний механизм

Функция использует следующие проверки:

  • Тег элемента: focusable теги — <input>, <button>, <a href> и элементы с tabindex.
  • Атрибут disabled: элемент с disabled считается нефокусируемым.
  • Видимость: элемент проверяется через offsetParent и вычисляемый стиль display/visibility.
  • DOM-изменения: подписка на MutationObserver позволяет отслеживать появление и изменение элементов.

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

Практические советы

  • Для элементов внутри скрытых контейнеров (display: none) важно дождаться их отображения перед вызовом focus().
  • Использование timeout предотвращает зависание промиса в интерфейсах с потенциальными ошибками загрузки.
  • Комбинируя ally.when.focusable с ally.query.focusable, можно управлять коллекциями интерактивных элементов.
// Получение всех фокусируемых элементов и ожидание одного из них
const focusables = ally.query.focusable('.form *');
focusables.forEach(el => {
  ally.when.focusable(el).then(e => console.log('Готов к фокусу:', e));
});

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

  • В React или Vue рекомендуется использовать useEffect / mounted для вызова ally.when.focusable после рендеринга.
  • Для SPA с динамической маршрутизацией важно повторно вызывать функцию при переходе между страницами, если элементы создаются асинхронно.
// React пример
useEffect(() => {
  const cleanup = ally.when.focusable('#react-input')
    .then(input => input.focus())
    .catch(() => {});
  
  return () => cleanup;
}, [currentRoute]);

Резюме по возможностям

  • Отслеживание доступности элементов для фокуса.
  • Работа с динамическими DOM-структурами.
  • Поддержка временных ограничений через timeout.
  • Опции видимости и исключения элементов.
  • Интеграция с современными фреймворками и SPA.

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