# YearPicker: API

## Пропсы корня

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `year` | `string` | — | Нет | Управляет текущим видимым годом — строка `YYYY-MM-DD` любого дня в нём. Этот проп определяет, **какой год сейчас в области видимости**, а не только какой год выбран. Его изменение может заставить пикер: прокрутить к соответствующей сетке годов; пересчитать видимое окно годов; обновить элементы навигации (назад / вперёд) |
| `calendar` | `CalendarSystem` | `gregorianCalendar` | Нет | Календарная система, к которой относятся годы, включая эры. По умолчанию — григорианский календарь. |
| `locale` | `string` | `getDefaultLocale()` | Нет | Локаль BCP 47 для подписей годов (и эр), например `ja-JP`. По умолчанию — локаль среды выполнения, как у `Intl`. |
| `size` | `DataGridPickerSize` | `'xs'` | Нет | Управляет визуальным размером элемента. Полезно для адаптации пикера к компактным или крупным раскладкам. |
| `variant` | `DataGridPickerVariant` | — | Нет | Предустановка внешнего вида пикера. |
| `selection` | `S` | `'single'` | Нет | Режим выбора. `'single'` — одновременно можно выбрать только одну ячейку; `'multiple'` — независимый множественный выбор (переключение по ячейке); `'range'` — выбор диапазона между двумя точками (Shift + стрелки или перетаскивание указателем) |
| `disabled` | `DataGridDisabled<string>` | — | Нет | Предикат или набор отключённых ячеек. Может быть: функцией `(key) => boolean`; массивом отключённых ключей; одним ключом. Отключённые ячейки нельзя выбрать или сфокусировать. |
| `excludeDisabled` | `boolean` | — | Нет | — |
| `expandable` | `boolean` | `true` | Нет | Включает расширение диапазонов выбора (Shift + стрелка или перетаскивание мышью). |
| `defaultActive` | `string` | — | Нет | Неконтролируемая начальная активная ячейка. |
| `active` | `string` | — | Нет | Контролируемая активная ячейка. |
| `selected` | `S extends "single" ? string \| null : string[]` | — | Нет | Контролируемые выбранные ячейки. В режиме `'single'` значение `null` означает контролируемое состояние без выбора. |
| `defaultSelected` | `S extends "single" ? string : string[]` | — | Нет | Неконтролируемые изначально выбранные ячейки. |
| `from` | `string` | — | Нет | Границы диапазона. Если заданы, ограничивают выбор ячейками между `from` и `to` на основе функции `compare`. |
| `to` | `string` | — | Нет | — |
| `resolveRange` | `(start: DataGridResolveValue<K>, end: DataGridResolveValue<K>, grid: Grid<HTMLElement, K>) => K[]` | — | Нет | Собственная логика построения диапазона для `selection="range"`. По начальному и конечному значениям возвращает список ключей, образующих диапазон. |
| `equals` | `(start: K \| undefined, end: K \| undefined) => boolean` | — | Нет | Собственная функция сравнения двух ключей ячеек на равенство. По умолчанию — строгое равенство (`===`). |
| `compare` | `(a: K, b: K) => -1 \| 0 \| 1` | — | Нет | Собственная функция упорядочивания двух ключей ячеек. Должна возвращать `-1`, `0` или `1`. |
| `onSelectCell` | `(value: S extends 'single' ? K : K[]) => void` | — | Нет | Вызывается, когда пользователь выбирает ячейку. Получает список ключей выбранных ячеек. |
| `onChangeActive` | `(active: K) => void` | — | Нет | Вызывается при изменении активной (сфокусированной) ячейки. |
| `ref` | `Ref<HTMLDivElement>` | — | Нет | Ref на корневой элемент сетки. |
| `apiRef` | `Ref<DataGridApiRef<string>>` | — | Нет | Ref на императивный API сетки. Предоставляет низкоуровневые структуры для сложных сценариев: `grid` — помощник навигации по матрице; `keyMap` — Map`<K, [row, col]>` для быстрого поиска |
| `wrap` | `DataGridWrap` | — | Нет | Режим зацикливания навигации. 'horizontal' — переход по столбцам в пределах строки; 'vertical' — переход по строкам в пределах столбца; 'both' — оба поведения; undefined — без зацикливания |
| `exclude` | `DataGridExclude<string>` | — | Нет | Исключает ячейки из обхода фокусом. Может быть: одним ключом; массивом ключей; предикатом `(key) => boolean` |
| `rowDelta` | `number` | — | Нет | Шаг навигации по строкам для PageUp/PageDown. `undefined` — переход к первой/последней строке; `number` — сдвиг на N строк относительно текущей |
| `onArrow` | `(e: KeyboardEvent<HTMLDivElement>, node: MatrixNode<HTMLElement, K>, prevNode: MatrixNode<HTMLElement, K>) => void` | — | Нет | Вызывается на каждом шаге навигации стрелками после смены фокуса |

Также принимает все атрибуты `<div>`.

## Дочерние части

- `YearPickerLayout`
- `YearPickerRowGroup`
- `YearPickerRow`
- `YearPickerItem`
- `YearPickerCell`
- `YearPickerScroller`
- `YearPickerScrollerContent`
- `YearPickerScrollerLayout`

### `YearPickerItem`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `range` | `DataGridPickerItemRangePosition` | — | Нет | Необязательный визуальный индикатор положения ячейки в диапазоне. Одно из: `"start" \| "between" \| "end"`. Если не задан, компонент вычисляет его автоматически по контексту выбора. |
| `size` | `DataGridPickerSize` | — | Нет | Управляет визуальным размером элемента. Полезно для адаптации пикера к компактным или крупным раскладкам. |
| `value` | `DataGridCellKey` | — | Нет | Логическое значение, связанное с этой ячейкой сетки. Используется как уникальный ключ выбора ячейки. |
| `variant` | `DataGridPickerVariant` | — | Нет | Предустановка внешнего вида пикера. |
| `disabled` | `boolean` | — | Нет | Отключает выбор кликом и с клавиатуры. Переопределяет значение из корневого DataGrid |
| `ref` | `Ref<HTMLDivElement>` | — | Нет | Внешний ref на корневой элемент ячейки. Объединяется с внутренней регистрацией `itemRef([row, col], key)`, если ячейка не исключена. |
| `col` | `number` | — | Да | Индекс столбца ячейки (с 0). Вместе с индексом строки из контекста строки образует координаты сетки: `[row, col]`. |
| `asChild` | `boolean` | `false` | Нет | Если `true`, рендерит дочерние элементы через `Slot` и передаёт пропсы и ref дочернему элементу вместо использования нативного `<div>`. |
| `excluded` | `boolean` | — | Нет | Исключает ячейки из обхода фокусом. Переопределяет значение из корневого DataGrid |

Также принимает все атрибуты `<div>`.

### `YearPickerCell`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `size` | `DataGridPickerSize` | — | Нет | Управляет визуальным размером элемента. Полезно для адаптации пикера к компактным или крупным раскладкам. |
| `range` | `DataGridPickerItemRangePosition` | — | Нет | Необязательный визуальный индикатор положения ячейки в диапазоне. Одно из: `"start" \| "between" \| "end"`. Если не задан, компонент вычисляет его автоматически по контексту выбора. |
| `variant` | `DataGridPickerVariant` | — | Нет | Предустановка внешнего вида пикера. |
| `disabled` | `boolean` | — | Нет | Отключает выбор кликом и с клавиатуры. Переопределяет значение из корневого DataGrid |
| `ref` | `Ref<HTMLDivElement>` | — | Нет | Внешний ref на корневой элемент ячейки. Объединяется с внутренней регистрацией `itemRef([row, col], key)`, если ячейка не исключена. |
| `asChild` | `boolean` | `false` | Нет | Если `true`, рендерит дочерние элементы через `Slot` и передаёт пропсы и ref дочернему элементу вместо использования нативного `<div>`. |
| `excluded` | `boolean` | — | Нет | Исключает ячейки из обхода фокусом. Переопределяет значение из корневого DataGrid |

Также принимает все атрибуты `<div>`.

### `YearPickerRow`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `row` | `number` | — | Да | Индекс строки (с нуля) для всех дочерних ячеек. Передаётся потомкам через контекст. |

Также принимает все атрибуты `<div>`.

### `YearPickerRowGroup`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `scope` | `DataGridScope` | — | Нет | Проп `scope` обязателен и идентифицирует логическую группу ячеек, которые рендерит эта группа строк. При использовании с `DataGridIndexedSnapScroller` scope обычно совпадает с текущим индексом или страницей. Scope позволяет DataGrid вернуть фокус на первую доступную ячейку, когда индекс меняется и рендерятся новые ячейки. |

Также принимает все атрибуты `<div>`.

### `YearPickerLayout`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `children` | `ReactNode` | — | Да | Шаблон ячейки года, рендерится один раз для каждого года страницы. Год читается через `useYearPickerCellContext()`; обычно `<YearPickerCell />`. |
| `rows` | `number` | `4` | Нет | Количество строк сетки для рендера. Управляет вертикальной плотностью матрицы годов. |
| `cols` | `number` | `3` | Нет | Количество столбцов сетки для рендера. Управляет горизонтальной плотностью матрицы годов. |
| `start` | `string` | — | Нет | Первый год страницы `0` — строка `YYYY-MM-DD` любого дня в нём. Страницы выравниваются по нему. По умолчанию — видимый год YearPicker. |
| `offset` | `number` | — | Нет | Индекс страницы относительно `start`. По умолчанию — страница, содержащая видимый год YearPicker. |
| `locale` | `string` | — | Нет | Локаль для форматирования годов. По умолчанию — локаль пикера. |
| `format` | `Intl.DateTimeFormatOptions['year']` | `'numeric'` | Нет | Формат отображения года (из `Intl.DateTimeFormatOptions`). |
| `scope` | `DataGridScope` | — | Нет | Проп `scope` обязателен и идентифицирует логическую группу ячеек, которые рендерит эта группа строк. При использовании с `DataGridIndexedSnapScroller` scope обычно совпадает с текущим индексом или страницей. Scope позволяет DataGrid вернуть фокус на первую доступную ячейку, когда индекс меняется и рендерятся новые ячейки. |

Также принимает все атрибуты `<div>`.

### `YearPickerScroller`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `onChangePeriod` | `(year: string) => void` | — | Нет | Вызывается, когда страница годов прокручивается в область видимости, с первым днём первого года этой страницы в виде строки `YYYY-MM-DD` в календарной системе YearPicker. |
| `defaultYear` | `string` | — | Нет | Начальный год для неконтролируемого использования вне YearPicker — строка `YYYY-MM-DD` любого дня в нём. По умолчанию — текущий год. |
| `period` | `number` | `12` | Нет | Количество годов на странице; должно совпадать с размером страницы в раскладке. |
| `start` | `number` | `-2` | Нет | Начальный индекс для генерации исходной последовательности страниц. Служит логической точкой отсчёта для скользящего окна индексов. |
| `startDir` | `-1 \| 1` | `1` | Нет | Направление, в котором растёт начальная последовательность индексов. `1` — индексы растут вправо (0, 1, 2…); `-1` — индексы убывают вправо (0, -1, -2…). Управляет порядком роста начального массива индексов. |
| `size` | `number` | `5` | Нет | Количество сегментов индексов, отрендеренных одновременно. Определяет размер виртуального «окна», по которому скроллер сдвигается при навигации влево или вправо. |
| `shift` | `number` | `2` | Нет | Количество страниц, добавляемых, когда прокрутка доходит до конца окна, чтобы быстрый свайп продолжался. Когда прокрутка останавливается, окно заново центрируется на странице привязки. |
| `index` | `number` | — | Нет | Управляет текущим активным логическим индексом. Если задан, скроллер держит этот индекс в области видимости: прокручивает к нему, если это возможно, или при необходимости перестраивает окно. |
| `preserveScroll` | `boolean` | `true` | Нет | Сохраняет текущий привязанный элемент после изменения содержимого (например, когда страницы добавляются в начало или конец). Если `true`, скроллер восстановит тот же индекс привязки через мгновенный `scrollIntoView`. |
| `apiRef` | `Ref<IndexedSnapScrollerApiRef>` | — | Нет | Предоставляет императивный API скроллера. Позволяет управлять им программно, например прокручивать к индексу или сбрасывать виртуальное окно. |
| `onOffset` | `(value: number) => void` | — | Нет | Вызывается, когда окно растёт у края. `-1` — прокрутка остановилась на первой странице (левый/верхний край); `+1` — прокрутка дошла до конца (правый/нижний край). Полезно для бесконечной подгрузки: добавляйте страницы в конец или в начало в зависимости от направления. |
| `ref` | `Ref<HTMLDivElement>` | — | Нет | Ref на элемент скроллера. |
| `defaultIndex` | `number` | — | Нет | Начальный индекс элемента, к которому выполняется привязка при монтировании. |
| `onScrollSnapChange` | `(element: HTMLElement, index: number) => void` | — | Нет | Вызывается, когда операция прокрутки с привязкой полностью завершена и скроллер остановился на новом индексе привязки. Колбэк вызывается после завершения всех анимаций прокрутки и привязки, когда активная позиция привязки считается стабильной. |
| `onScrollSnapChanging` | `(element: HTMLElement, index: number) => void` | — | Нет | Вызывается, пока операция прокрутки с привязкой идёт и активный индекс привязки ещё меняется. Колбэк может вызываться несколько раз за одну прокрутку или свайп, пока скроллер приближается к конечной позиции привязки. Полезен для оптимистичных обновлений интерфейса, превью или синхронизации промежуточного состояния во время прокрутки. |

Также принимает все атрибуты `<div>`.

### `YearPickerScrollerContent`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `ref` | `Ref<HTMLDivElement>` | — | Нет | Внешний ref на корневой элемент элемента. Объединяется с внутренним `itemRef(index)`, чтобы участвовать в логике привязки. |
| `asChild` | `boolean` | — | Нет | Рендерит содержимое как дочерний элемент (через `Slot`) вместо нативного `<div>`. Атрибуты и ref остаются привязанными к переданному дочернему элементу. |

Также принимает все атрибуты `<div>`.

### `YearPickerScrollerLayout`

| Проп | Тип | По умолчанию | Обязательный | Описание |
| --- | --- | --- | --- | --- |
| `children` | `ReactNode` | — | Да | Шаблон ячейки года, рендерится один раз для каждого года страницы. Год читается через `useYearPickerCellContext()`; обычно `<YearPickerCell />`. |
| `start` | `string` | — | Нет | Первый год страницы `0` — строка `YYYY-MM-DD` любого дня в нём. Страницы выравниваются по нему. По умолчанию — видимый год YearPicker. |
| `locale` | `string` | — | Нет | Локаль для форматирования годов. По умолчанию — локаль пикера. |
| `rows` | `number` | `4` | Нет | Количество строк сетки для рендера. Управляет вертикальной плотностью матрицы годов. |
| `format` | `Intl.DateTimeFormatOptions['year']` | `"numeric"` | Нет | Формат отображения года (из `Intl.DateTimeFormatOptions`). |
| `scope` | `DataGridScope` | — | Нет | Проп `scope` обязателен и идентифицирует логическую группу ячеек, которые рендерит эта группа строк. При использовании с `DataGridIndexedSnapScroller` scope обычно совпадает с текущим индексом или страницей. Scope позволяет DataGrid вернуть фокус на первую доступную ячейку, когда индекс меняется и рендерятся новые ячейки. |
| `cols` | `number` | `3` | Нет | Количество столбцов сетки для рендера. Управляет горизонтальной плотностью матрицы годов. |

Также принимает все атрибуты `<div>`.

## Типы

- `YearPickerProps`
- `YearPickerLayoutProps`
- `YearPickerRowGroupProps`
- `YearPickerRowProps`
- `YearPickerItemProps`
- `YearPickerCellProps`
- `YearPickerCellContextData`
- `YearPickerScrollerProps`
- `YearPickerScrollerContentProps`
- `YearPickerScrollerLayoutProps`

## Модель состояния

- Поведение выбора и границ наследуется от `DataGridPicker`.
- Годы идентифицируются своим первым днём в виде строки `YYYY-MM-DD`; `selected`, `from`, `to` и `disabled` используют такие же строки.
- Корень передаёт видимый `year` (его первый день) и `calendar` через `useYearPickerContext`.
- `createYearPickerGrid({ rows, cols, start, offset, calendar })` возвращает страницу из `rows × cols` последовательных лет, начиная с ISO-даты `start`.
- Страницы скроллера содержат `period` лет (по умолчанию `12`), отсчитанных от `referenceYear` (`useYearPickerScrollerContext`); держите `period` равным `rows × cols` раскладки. `onChangePeriod` получает первый день первого года страницы, прокрученной в область видимости.
- Дочерние элементы `YearPickerLayout` и `YearPickerScrollerLayout` — шаблон ячейки, который рендерится по одному разу на каждый год внутри контекста ячейки. Дочерние элементы обязательны; обычно это `<YearPickerCell />`, который показывает отформатированную подпись.
- `useYearPickerCellContext()` возвращает `{ col, date, fields, label }`; `date` — первый день года. Берите номера лет из `label` или `fields`, а не из ISO-строки `date`.
- `locale` и `calendar` — пропсы корня; раскладки принимают собственное переопределение `locale`.
