useCalendarGrid для сетки

useCalendarGrid — это хук из библиотеки React Aria, предназначенный для управления доступностью и взаимодействием с календарными сетками. Он предоставляет все необходимые атрибуты и состояния для рендеринга календаря, учитывая спецификации ARIA для интерактивных таблиц и дат. Основная задача хука — абстрагировать сложную логику выбора дат и фокусировки, предоставляя готовый API для компонентов календаря.


Подключение и базовое использование

Импорт хука осуществляется следующим образом:

import { useCalendarGrid } from '@react-aria/calendar';
import { useLocale } from '@react-aria/i18n';
import { useCalendarState } from '@react-stately/calendar';

Для работы useCalendarGrid необходим объект состояния календаря (CalendarState) из библиотеки React Stately. Этот объект управляет текущей датой, выбранной датой и диапазоном, а также навигацией по месяцам.

Пример создания состояния календаря:

const { locale } = useLocale();
const state = useCalendarState({ locale, visibleDuration: { months: 1 }, minValue: new Date(2023, 0, 1), maxValue: new Date(2025, 11, 31) });

API хука useCalendarGrid

Хук возвращает объект с ключевыми свойствами:

  • gridProps — атрибуты для контейнера сетки календаря (role="grid", aria-labelledby, обработка клавиатурной навигации).
  • headerProps — атрибуты для строки заголовка дней недели.
  • weekDays — массив объектов с информацией о днях недели (например, сокращённые названия дней).
  • weeks — массив объектов, каждый из которых представляет неделю и содержит массив дней с полной информацией.
  • getCellProps(day) — функция, возвращающая атрибуты для конкретной ячейки дня (role="gridcell", состояние aria-selected, aria-disabled).

Пример применения:

const { gridProps, headerProps, weeks, getCellProps } = useCalendarGrid({ state });

return (
  <table {...gridProps}>
    <thead {...headerProps}>
      <tr>
        {state.weekDays.map(day => <th key={day}>{day}</th>)}
      </tr>
    </thead>
    <tbody>
      {weeks.map((week, wi) => (
        <tr key={wi}>
          {week.map(day => {
            const cellProps = getCellProps(day);
            return <td key={day.date.toString()} {...cellProps}>{day.date.getDate()}</td>;
          })}
        </tr>
      ))}
    </tbody>
  </table>
);

Работа с состояниями ячеек

Каждая ячейка календаря может находиться в нескольких состояниях:

  • Выбрана (selected) — если дата соответствует выбранной дате или диапазону.
  • Неактивна (disabled) — если дата выходит за пределы minValue или maxValue, либо находится вне активного месяца.
  • Фокус (focused) — для обработки клавиатурной навигации. Хук автоматически управляет фокусом с помощью ARIA и стрелок клавиатуры.
  • Сегодняшний день (today) — текущая дата для визуального выделения.

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


Локализация и форматирование

useCalendarGrid учитывает локализацию через объект locale:

  • Названия дней недели автоматически подстраиваются под локаль.
  • Порядок дней (начало недели) соответствует региональным стандартам.
  • Форматирование дат для скринридеров происходит с учётом локали.

Пример:

const { locale } = useLocale();
const state = useCalendarState({ locale, ... });
const { weeks, getCellProps } = useCalendarGrid({ state });

weeks.forEach(week => {
  week.forEach(day => {
    const cell = getCellProps(day);
    // cell['aria-label'] уже содержит локализованную строку даты
  });
});

Клавиатурная навигация

useCalendarGrid обеспечивает стандартное управление стрелками:

  • Стрелка влево/вправо — перемещение на один день.
  • Стрелка вверх/вниз — перемещение на одну неделю.
  • Home / End — переход к началу или концу недели.
  • Page Up / Page Down — переход на предыдущий или следующий месяц.
  • Enter / Space — выбор даты.

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


Настройка внешнего вида и кастомизация

Хотя useCalendarGrid отвечает за логику и доступность, визуальное оформление полностью на стороне разработчика:

  • Таблица может быть стилизована через CSS или CSS-in-JS.
  • Дни текущего месяца, выбранные даты и диапазоны можно выделять с помощью классов, возвращаемых из getCellProps.
  • Для поддержки темной темы или дополнительных индикаторов (например, праздников) можно расширять объект ячеек данными из state.

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

<td
  key={day.date.toString()}
  {...getCellProps(day)}
  className={day.isToday ? 'today' : ''}
>
  {day.date.getDate()}
</td>

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

useCalendarGrid полностью совместим с диапазонами дат:

  • При использовании state.selectionMode = 'range' ячейки автоматически получают атрибуты aria-selected и визуальные индикаторы для начала, конца и промежуточных дат.
  • Можно легко интегрировать с другими компонентами React Aria, такими как useDatePicker или useCalendar, для построения сложных интерфейсов выбора дат.

Особенности и рекомендации

  • Не нужно вручную управлять ARIA-атрибутами: useCalendarGrid генерирует их автоматически.
  • Сетка календаря всегда должна использовать <table> с role="grid" для корректной доступности.
  • Ячейки должны рендериться через getCellProps для корректного взаимодействия с клавиатурой и скринридерами.
  • Для поддержки нескольких месяцев достаточно использовать visibleDuration в состоянии календаря.

useCalendarGrid предоставляет мощный инструмент для построения доступных и локализованных календарных интерфейсов в React, позволяя сосредоточиться на дизайне и пользовательском опыте, не погружаясь в тонкости ARIA и управления фокусом.