@sberbusiness/triplex-next-mcp-server 0.24.0-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +124 -0
  2. package/bundle/.gitkeep +0 -0
  3. package/bundle/components/AbstractTree.md +198 -0
  4. package/bundle/components/AccordionBase.md +227 -0
  5. package/bundle/components/Alert.md +317 -0
  6. package/bundle/components/Amount.md +225 -0
  7. package/bundle/components/AmountField.md +289 -0
  8. package/bundle/components/Avatar.md +209 -0
  9. package/bundle/components/Badge.md +277 -0
  10. package/bundle/components/Body.md +167 -0
  11. package/bundle/components/Button.md +230 -0
  12. package/bundle/components/ButtonDropdown.md +159 -0
  13. package/bundle/components/ButtonIcon.md +122 -0
  14. package/bundle/components/Calendar.md +445 -0
  15. package/bundle/components/Card.md +374 -0
  16. package/bundle/components/CarouselExtended.md +250 -0
  17. package/bundle/components/Checkbox.md +126 -0
  18. package/bundle/components/CheckboxTree.md +280 -0
  19. package/bundle/components/CheckboxTreeExtended.md +321 -0
  20. package/bundle/components/CheckboxXGroup.md +68 -0
  21. package/bundle/components/CheckboxYGroup.md +67 -0
  22. package/bundle/components/Chip.md +404 -0
  23. package/bundle/components/ChipGroup.md +179 -0
  24. package/bundle/components/Col.md +221 -0
  25. package/bundle/components/CollapsableTree.md +255 -0
  26. package/bundle/components/Confirm.md +343 -0
  27. package/bundle/components/DateField.md +371 -0
  28. package/bundle/components/DatePickerExtended.md +342 -0
  29. package/bundle/components/DateRange.md +275 -0
  30. package/bundle/components/DesignTokens.md +385 -0
  31. package/bundle/components/Divider.md +196 -0
  32. package/bundle/components/DocumentNumberEdit.md +280 -0
  33. package/bundle/components/Dropdown.md +433 -0
  34. package/bundle/components/Ellipsis.md +208 -0
  35. package/bundle/components/EmptyView.md +99 -0
  36. package/bundle/components/ExpandAnimation.md +281 -0
  37. package/bundle/components/Footer.md +339 -0
  38. package/bundle/components/FormField.md +326 -0
  39. package/bundle/components/FormGroup.md +99 -0
  40. package/bundle/components/Gap.md +113 -0
  41. package/bundle/components/Header.md +280 -0
  42. package/bundle/components/HelpBox.md +154 -0
  43. package/bundle/components/IconWrapper.md +145 -0
  44. package/bundle/components/Island.md +197 -0
  45. package/bundle/components/IslandAccordion.md +230 -0
  46. package/bundle/components/IslandWidget.md +233 -0
  47. package/bundle/components/KeyDownListener.md +157 -0
  48. package/bundle/components/LightBox.md +322 -0
  49. package/bundle/components/Link.md +161 -0
  50. package/bundle/components/List.md +247 -0
  51. package/bundle/components/ListMaster.md +204 -0
  52. package/bundle/components/Loader.md +161 -0
  53. package/bundle/components/LoaderScreen.md +134 -0
  54. package/bundle/components/Marker.md +127 -0
  55. package/bundle/components/MarkerStatus.md +148 -0
  56. package/bundle/components/MediaWidth.md +169 -0
  57. package/bundle/components/MobileView.md +120 -0
  58. package/bundle/components/ModalWindow.md +308 -0
  59. package/bundle/components/MonthYearField.md +168 -0
  60. package/bundle/components/MultiselectField.md +213 -0
  61. package/bundle/components/Notification.md +233 -0
  62. package/bundle/components/NumberField.md +178 -0
  63. package/bundle/components/OrderedList.md +169 -0
  64. package/bundle/components/Overlay.md +237 -0
  65. package/bundle/components/Page.md +246 -0
  66. package/bundle/components/Pagination.md +298 -0
  67. package/bundle/components/Portal.md +119 -0
  68. package/bundle/components/Radio.md +174 -0
  69. package/bundle/components/Row.md +125 -0
  70. package/bundle/components/SMSField.md +160 -0
  71. package/bundle/components/SegmentedControl.md +235 -0
  72. package/bundle/components/SelectExtendedField.md +322 -0
  73. package/bundle/components/SelectField.md +213 -0
  74. package/bundle/components/Skeleton.md +129 -0
  75. package/bundle/components/Slider.md +157 -0
  76. package/bundle/components/SliderExtended.md +210 -0
  77. package/bundle/components/SliderRange.md +160 -0
  78. package/bundle/components/SmallInput.md +101 -0
  79. package/bundle/components/Spoiler.md +121 -0
  80. package/bundle/components/StatusTracker.md +151 -0
  81. package/bundle/components/Step.md +121 -0
  82. package/bundle/components/Stepper.md +163 -0
  83. package/bundle/components/Suggest.md +160 -0
  84. package/bundle/components/SuggestField.md +157 -0
  85. package/bundle/components/SwipeableArea.md +144 -0
  86. package/bundle/components/Table.md +199 -0
  87. package/bundle/components/Tabs.md +152 -0
  88. package/bundle/components/TabsExtended.md +273 -0
  89. package/bundle/components/TabsLine.md +189 -0
  90. package/bundle/components/Tag.md +135 -0
  91. package/bundle/components/TagColor.md +121 -0
  92. package/bundle/components/TagGroup.md +100 -0
  93. package/bundle/components/TextField.md +152 -0
  94. package/bundle/components/TextareaField.md +124 -0
  95. package/bundle/components/ThemeProvider.md +181 -0
  96. package/bundle/components/Tooltip.md +254 -0
  97. package/bundle/components/TopOverlay.md +145 -0
  98. package/bundle/components/TreeView.md +224 -0
  99. package/bundle/components/Triggers.md +121 -0
  100. package/bundle/guides/codestyle.md +205 -0
  101. package/bundle/guides/commits.md +166 -0
  102. package/bundle/guides/context.md +277 -0
  103. package/bundle/guides/stories.md +618 -0
  104. package/bundle/guides/template.md +154 -0
  105. package/bundle/guides/tests.md +301 -0
  106. package/bundle/icons.json +4156 -0
  107. package/bundle/manifest.json +796 -0
  108. package/bundle/release-notes/1.1.0.mdx +26 -0
  109. package/bundle/release-notes/1.1.1.mdx +14 -0
  110. package/bundle/release-notes/1.10.0.mdx +43 -0
  111. package/bundle/release-notes/1.11.0.mdx +19 -0
  112. package/bundle/release-notes/1.12.0.mdx +21 -0
  113. package/bundle/release-notes/1.13.0.mdx +43 -0
  114. package/bundle/release-notes/1.14.0.mdx +29 -0
  115. package/bundle/release-notes/1.15.0.mdx +56 -0
  116. package/bundle/release-notes/1.16.0.mdx +55 -0
  117. package/bundle/release-notes/1.17.0.mdx +15 -0
  118. package/bundle/release-notes/1.18.0.mdx +24 -0
  119. package/bundle/release-notes/1.19.0.mdx +48 -0
  120. package/bundle/release-notes/1.19.1.mdx +9 -0
  121. package/bundle/release-notes/1.2.0.mdx +80 -0
  122. package/bundle/release-notes/1.20.0.mdx +48 -0
  123. package/bundle/release-notes/1.21.0.mdx +66 -0
  124. package/bundle/release-notes/1.22.0.mdx +75 -0
  125. package/bundle/release-notes/1.23.0.mdx +50 -0
  126. package/bundle/release-notes/1.24.0.mdx +59 -0
  127. package/bundle/release-notes/1.25.0.mdx +52 -0
  128. package/bundle/release-notes/1.26.0.mdx +11 -0
  129. package/bundle/release-notes/1.3.0.mdx +21 -0
  130. package/bundle/release-notes/1.4.0.mdx +37 -0
  131. package/bundle/release-notes/1.5.0.mdx +24 -0
  132. package/bundle/release-notes/1.6.0.mdx +37 -0
  133. package/bundle/release-notes/1.6.1.mdx +11 -0
  134. package/bundle/release-notes/1.7.0.mdx +29 -0
  135. package/bundle/release-notes/1.8.0.mdx +38 -0
  136. package/bundle/release-notes/1.9.0.mdx +28 -0
  137. package/dist/index.d.ts +2 -0
  138. package/dist/index.js +324 -0
  139. package/dist/index.js.map +1 -0
  140. package/package.json +51 -0
@@ -0,0 +1,445 @@
1
+ ---
2
+ component: Calendar
3
+ category: Date & Time
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [DateField, DateRange, DatePickerExtended, MonthYearField]
7
+ tokens:
8
+ - --triplex-next-Calendar-Background
9
+ - --triplex-next-Calendar-View_Header_Color
10
+ - --triplex-next-Calendar-View_Item_Background_Default
11
+ - --triplex-next-Calendar-View_Item_Background_Hover
12
+ - --triplex-next-Calendar-View_Item_Background_Selected_Default
13
+ - --triplex-next-Calendar-View_Item_Background_Selected_Hover
14
+ - --triplex-next-Calendar-View_Item_Background_Selected_Muted_Default
15
+ - --triplex-next-Calendar-View_Item_Background_Selected_Muted_Hover
16
+ - --triplex-next-Calendar-View_Item_BorderColor_Default
17
+ - --triplex-next-Calendar-View_Item_BorderColor_Focus
18
+ - --triplex-next-Calendar-View_Item_Color_Default
19
+ - --triplex-next-Calendar-View_Item_Color_Disabled
20
+ - --triplex-next-Calendar-View_Item_Color_Muted
21
+ - --triplex-next-Calendar-View_Item_Color_Selected
22
+ - --triplex-next-Calendar-View_Item_Color_Selected_Muted_Default
23
+ - --triplex-next-Calendar-View_Item_Color_Selected_Muted_Hover
24
+ - --triplex-next-Calendar-View_Item_Mark_Basic_Background_Default
25
+ - --triplex-next-Calendar-View_Item_Mark_Basic_Background_Selected_Default
26
+ - --triplex-next-Calendar-View_Item_Mark_Basic_Background_Selected_Hover
27
+ - --triplex-next-Calendar-View_Item_Mark_Standard_Background_Default
28
+ - --triplex-next-Calendar-View_Item_Mark_Standard_Background_Selected_Default
29
+ - --triplex-next-Calendar-View_Item_Mark_Standard_Background_Selected_Hover
30
+ - --triplex-next-Calendar-View_Item_Mark_Attention_Background_Default
31
+ - --triplex-next-Calendar-View_Item_Mark_Attention_Background_Selected_Default
32
+ - --triplex-next-Calendar-View_Item_Mark_Attention_Background_Selected_Hover
33
+ - --triplex-next-Calendar-View_Item_Mark_Critical_Background_Default
34
+ - --triplex-next-Calendar-View_Item_Mark_Critical_Background_Selected_Default
35
+ - --triplex-next-Calendar-View_Item_Mark_Critical_Background_Selected_Hover
36
+ stories: stories/Calendar/Calendar.stories.tsx
37
+ version: "1.0"
38
+ ---
39
+
40
+ # Calendar
41
+
42
+ ## Назначение
43
+
44
+ Интерактивный компонент выбора даты в виде классической сетки календаря.
45
+ Рендерит заголовок с навигацией (предыдущий/следующий период, смена вида),
46
+ сетку периода (дни/месяцы/годы) и опциональный футер с кнопками быстрого
47
+ перехода (Вчера/Сегодня/Завтра).
48
+
49
+ Поддерживает два режима выбора: `datePick` (день → месяц → год) и
50
+ `monthYearPick` (только месяц+год, без выбора конкретного дня). Позволяет
51
+ отмечать дни цветными метками четырёх типов (BASIC/STANDARD/ATTENTION/CRITICAL),
52
+ ограничивать диапазон допустимых дат, запрещать отдельные дни.
53
+
54
+ Используй когда: нужен самостоятельный календарь в inline-режиме (например,
55
+ в попапе DateField, в модальном окне бронирования).
56
+ Не используй когда: нужен input с календарным попапом — бери `DateField`
57
+ (обёртка с `DateFieldPicker`); нужен range picker — бери `DateRange`; нужен
58
+ компактный picker только месяц+год — для input'а используй `MonthYearField`.
59
+
60
+ ---
61
+
62
+ ## Файловая структура
63
+
64
+ ```text
65
+ src/components/Calendar/
66
+ ├── Calendar.tsx # React.PureComponent (class), root компонент
67
+ ├── CalendarContext.tsx # Контекст с format/limitRange/pickType/viewDate/viewMode/periodId + обработчики
68
+ ├── CalendarViewContext.tsx # Контекст с viewItemFocusedRef (mutable)
69
+ ├── enums.ts # ECalendarPickType, ECalendarViewMode, ECalendarDateMarkType
70
+ ├── types.ts # ICalendarProps, TPickedDate, TCalendarMarkedDays, и др.
71
+ ├── utils.ts # parsePickedDate, getHeader, formatDate, isDateOutOfRange, isDayDisabled
72
+ ├── index.ts # Barrel: Calendar + enums + types
73
+ ├── styles/
74
+ │ ├── Calendar.module.less # Root (width 300px, adaptive)
75
+ │ ├── CalendarControls.module.less # Заголовок с кнопками prev/next/view
76
+ │ ├── CalendarView.module.less # Таблица сетки, все состояния и метки
77
+ │ └── CalendarFooter.module.less # Футер с кнопками дат
78
+ └── components/ # Внутренние (не экспортируются наружу)
79
+ ├── CalendarControls.tsx # Заголовок + prev/next/view кнопки
80
+ ├── CalendarView.tsx # Переключатель между Days/Months/Years
81
+ ├── CalendarViewDays.tsx # Сетка дней с weekday-шапкой
82
+ ├── CalendarViewMonths.tsx # Сетка 12 месяцев
83
+ ├── CalendarViewYears.tsx # Сетка 12 лет (диапазон -5..+6 от viewDate)
84
+ ├── CalendarViewItem.tsx # Ячейка: день/месяц/год + marks/states
85
+ ├── CalendarFooter.tsx # Контейнер футера
86
+ └── CalendarFooterButton.tsx # Кнопка "Вчера"/"Сегодня"/"Завтра"
87
+ ```
88
+
89
+ Особенности:
90
+ - **`Calendar` — class component (`React.PureComponent`)**, не функция и не
91
+ `forwardRef`. Это легаси и осознанное решение: state-машина viewMode + viewDate
92
+ + header проще как класс (cоответствующая рефакторинговая задача не запланирована).
93
+ - **Нет `forwardRef`** — один из немногих компонентов без него. Не добавлять
94
+ без согласования, класс не поддерживает forwardRef без обёртки.
95
+ - **Два контекста**: `CalendarContext` (данные + обработчики) и
96
+ `CalendarViewContext` (мутабельный ref для управления фокусом между viewMode).
97
+ - **`moment.js`** — зависимость времени. Весь внешний API построен вокруг
98
+ `Moment` и строк с `format`. Пользователь должен подключить локаль через
99
+ `moment.locale("ru")` (делается в stories).
100
+
101
+ ---
102
+
103
+ ## Варианты и props
104
+
105
+ ### `ICalendarProps extends ICalendarNestedProps`
106
+
107
+ **Обязательные:**
108
+
109
+ | Prop | Тип | Описание |
110
+ |---|---|---|
111
+ | `pickedDate` | `TPickedDateProp = string \| Moment \| null` | Выбранная дата. Строка парсится по `format`. |
112
+ | `onDateChange` | `(date: Moment) => void` | Коллбек при выборе даты/месяца в сетке. Всегда Moment. |
113
+
114
+ **Опциональные (основные):**
115
+
116
+ | Prop | Тип | Default | Описание |
117
+ |---|---|---|---|
118
+ | `format` | `string` | `"YYYY-MM-DD"` (`dateFormatYYYYMMDD`) | Формат для парсинга/форматирования строковых дат. |
119
+ | `pickType` | `ECalendarPickType` | `datePick` | Режим выбора: день или месяц+год. |
120
+ | `limitRange` | `IDateLimitRange` | `globalLimitRange` | `{ dateFrom?, dateTo? }`. Даты вне диапазона недоступны. |
121
+ | `markedDays` | `TCalendarMarkedDays` | — | Массив строк дат (`BASIC`) или объект `{ [date]: ECalendarDateMarkType }`. |
122
+ | `disabledDays` | `string[]` | — | Даты, недоступные для выбора (формат = `format`). |
123
+ | `reversedPick` | `boolean` | `false` | Начинать выбор с года (YEARS → MONTHS → DAYS) вместо обычного. |
124
+ | `defaultViewDate` | `string \| Moment` | — | Дата, на которой открывается календарь при отсутствии `pickedDate`. |
125
+ | `adaptiveMode` | `boolean` | — | `width: auto; padding: 20px` вместо `300px/8px 12px`. Для модальных окон. |
126
+ | `onPageChange` | `(viewDate, viewMode) => void` | — | Срабатывает при prev/next. |
127
+ | `onViewChange` | `(viewDate, viewMode) => void` | — | Срабатывает при смене viewMode (клик по заголовку или выбор месяца/года). |
128
+
129
+ **Опциональные (кастомизация кнопок и ячеек через `ICalendarNestedProps`):**
130
+
131
+ Все `*ButtonProps` принимают либо объект HTML-атрибутов кнопки, либо функцию,
132
+ возвращающую атрибуты. Для `todayButtonProps` функция получает
133
+ `{viewMode, currentPeriodSelected}`, остальные — только `viewMode`.
134
+
135
+ | Prop | Тип | Назначение |
136
+ |---|---|---|
137
+ | `prevButtonProps` | `TButtonHTMLAttributesWithData \| (viewMode) => ...` | Кнопка "Предыдущий". Обязательные `data-*` атрибуты. |
138
+ | `nextButtonProps` | `TButtonHTMLAttributesWithData \| (viewMode) => ...` | Кнопка "Следующий". |
139
+ | `viewButtonProps` | `TButtonHTMLAttributesWithData \| (viewMode) => ...` | Заголовок (кнопка смены viewMode). |
140
+ | `yesterdayButtonProps` | `TButtonHTMLAttributesWithData \| (viewMode) => ...` | Только в `datePick`+DAYS+текущий месяц. |
141
+ | `todayButtonProps` | `TButtonHTMLAttributesWithData \| ({viewMode, currentPeriodSelected}) => ...` | **Ключевой: если не передан — футер не рендерится вообще.** |
142
+ | `tomorrowButtonProps` | `TButtonHTMLAttributesWithData \| (viewMode) => ...` | Только в `datePick`+DAYS+текущий месяц. |
143
+ | `dayHtmlAttributes` | `TTdHTMLAttributesWithData \| (params: {marked}) => ...` | Атрибуты `<td>` ячейки дня. Функция получает `{marked: boolean}`. |
144
+ | `monthHtmlAttributes` | `TTdHTMLAttributesWithData` | Атрибуты `<td>` ячейки месяца. |
145
+ | `yearHtmlAttributes` | `TTdHTMLAttributesWithData` | Атрибуты `<td>` ячейки года. |
146
+
147
+ **`TButtonHTMLAttributesWithData` / `TTdHTMLAttributesWithData`** — требуют
148
+ минимум один `data-*` атрибут (intersection-тип). Это форсит потребителя
149
+ добавлять testId-подобные атрибуты.
150
+
151
+ ---
152
+
153
+ ### Enums
154
+
155
+ #### `ECalendarPickType` (numeric enum)
156
+
157
+ | Значение | Числовой код | Описание |
158
+ |---|---|---|
159
+ | `datePick` | 0 | Выбор конкретного дня. ViewMode начинает с DAYS. |
160
+ | `monthYearPick` | 1 | Выбор месяца+года. ViewMode начинает с MONTHS, нет DAYS. |
161
+
162
+ #### `ECalendarViewMode` (string enum)
163
+
164
+ | Значение | Что видно в сетке |
165
+ |---|---|
166
+ | `"days"` (DAYS) | Сетка 6×7: weekday-шапка + дни месяца (включая края соседних). |
167
+ | `"months"` (MONTHS) | Сетка 3×4 из 12 месяцев года. |
168
+ | `"years"` (YEARS) | Сетка 3×4 из 12 лет (диапазон viewDate −5..+6). |
169
+
170
+ #### `ECalendarDateMarkType` (numeric enum)
171
+
172
+ | Значение | Код | Назначение |
173
+ |---|---|---|
174
+ | `BASIC` | 0 | Нейтральная метка (общие события). |
175
+ | `STANDARD` | 1 | Стандартная метка (выплаты, платежи). |
176
+ | `ATTENTION` | 2 | Внимание (срочно, но не критично). |
177
+ | `CRITICAL` | 3 | Критическая метка (просрочка, ошибка). |
178
+
179
+ Каждая метка — отдельный токен для `Default`/`Selected_Default`/`Selected_Hover`
180
+ (всего 12 токенов цветов меток).
181
+
182
+ ---
183
+
184
+ ## Ключевые особенности реализации
185
+
186
+ ### Инициализация viewMode в конструкторе
187
+
188
+ ```ts
189
+ if (reversedPick) {
190
+ viewMode = ECalendarViewMode.YEARS;
191
+ } else if (pickType == ECalendarPickType.monthYearPick) {
192
+ viewMode = ECalendarViewMode.MONTHS;
193
+ } else {
194
+ viewMode = ECalendarViewMode.DAYS;
195
+ }
196
+ ```
197
+
198
+ `reversedPick` имеет приоритет над `pickType` — всегда начинает с YEARS.
199
+ В обычном `monthYearPick` стартует с MONTHS. По умолчанию — DAYS.
200
+
201
+ ### Синхронизация `pickedDate` → `viewDate` в `componentDidUpdate`
202
+
203
+ Если внешний `pickedDate` изменился на валидную дату в **другом месяце**
204
+ относительно текущего `viewDate`, календарь автоматически переключается
205
+ в DAYS и навигирует на месяц новой даты. Это не типичный controlled-паттерн —
206
+ `viewDate` не контролируется потребителем, он производится от `pickedDate`.
207
+
208
+ ### `uniqueId()` для `periodId`
209
+
210
+ ```ts
211
+ private periodId = `calendar-period-${uniqueId()}`;
212
+ ```
213
+
214
+ Генерируется в инстансе класса. Нужен для связывания weekday-шапки в
215
+ CalendarViewDays и сетки дней через `headers`/`id` ARIA-атрибуты (a11y для
216
+ screen reader'а: "Понедельник, 15 января").
217
+
218
+ ### `CalendarContext.Provider` — единственный способ доступа subcomponent'ов
219
+
220
+ Внутренние компоненты (`CalendarView`, `CalendarControls`, `CalendarFooter`)
221
+ не принимают большинство props от Calendar напрямую. Все данные и обработчики
222
+ идут через контекст. Исключение — `prevButtonProps`/`nextButtonProps`/
223
+ `viewButtonProps` передаются в `CalendarControls` пропсами, так как имеют
224
+ различные типы и легче передать явно.
225
+
226
+ ### Футер рендерится только при `todayButtonProps`
227
+
228
+ ```tsx
229
+ {todayButtonProps && this.renderFooter()}
230
+ ```
231
+
232
+ Это единственный гейт — без `todayButtonProps` футер не появляется. Кнопки
233
+ "Вчера" и "Завтра" показываются дополнительно только в `datePick`+DAYS,
234
+ когда `viewDate` находится в текущем месяце (`currentPeriodSelected`).
235
+
236
+ ### `currentPeriodSelected` имеет разный смысл для pickType
237
+
238
+ ```ts
239
+ if (pickType === ECalendarPickType.datePick) {
240
+ currentPeriodSelected = viewMode === DAYS && viewDate.isSame(todayDate, "month");
241
+ } else {
242
+ currentPeriodSelected = viewMode === MONTHS && viewDate.isSame(todayDate, "year");
243
+ }
244
+ ```
245
+
246
+ Для `datePick` — "текущий месяц в поле зрения". Для `monthYearPick` —
247
+ "текущий год в поле зрения". Потребитель получает этот флаг в
248
+ `todayButtonProps`-функции, чтобы менять текст кнопки ("Сегодня" vs
249
+ "К текущей дате").
250
+
251
+ ### `adaptiveMode` — не responsive, а переключатель размера
252
+
253
+ Не про media-queries. Прокидывает `.adaptive` класс на root, меняет ширину
254
+ на `auto` и паддинги на `20px`. Используется в контексте модальных окон /
255
+ DatePickerExtended, где родитель управляет шириной.
256
+
257
+ ### `formatDate` для YEARS показывает диапазон
258
+
259
+ ```ts
260
+ case YEARS:
261
+ const yearFrom = checkedDate.clone().add(-5, "y").format("YYYY");
262
+ const yearTo = checkedDate.clone().add(6, "y").format("YYYY");
263
+ return `${yearFrom} - ${yearTo}`;
264
+ ```
265
+
266
+ 12-летний диапазон, где viewDate находится на 6-м месте (−5 назад, +6 вперёд).
267
+ Это определяет и заголовок, и сами ячейки.
268
+
269
+ ### `TCalendarMarkedDays` — два формата
270
+
271
+ ```ts
272
+ type TCalendarMarkedDays = string[] | Record<string, ECalendarDateMarkType>;
273
+ ```
274
+
275
+ Массив → все метки `BASIC`. Объект → тип метки по дате. Внутренне
276
+ `CalendarViewDays` нормализует оба варианта в `Record` и достаёт тип по
277
+ строковому ключу даты.
278
+
279
+ ### `dayHtmlAttributes` как функция
280
+
281
+ ```ts
282
+ type TDayHtmlAttributesFunction = (params: {marked: boolean}) => React.TdHTMLAttributes<...>;
283
+ ```
284
+
285
+ Если передать функцию — получает `marked` для каждого дня, возвращает атрибуты.
286
+ Позволяет делать `data-marked="true"` атрибут без ручной проверки. Для месяцев
287
+ и годов функционального варианта нет (нет `marked`-логики).
288
+
289
+ ---
290
+
291
+ ## Инварианты
292
+
293
+ - **`React.PureComponent` class** — не превращать в функцию без масштабного
294
+ рефакторинга state-машины. Перезапись изменит поведение `componentDidUpdate`.
295
+ - **Нет `forwardRef`** — класс не форвардит ref. Не добавлять (осознанное
296
+ решение, есть в ROADMAP).
297
+ - **`defaultProps` на классе** — не удалять, не переносить в деструктуризацию.
298
+ Используется в `this.context`-типизации и вычислениях конструктора.
299
+ - **`periodId` на инстансе** (`this.periodId =`) — не static, иначе два
300
+ Calendar'а на странице получат одинаковый id и сломают a11y weekday-ссылок.
301
+ - **`moment.locale("ru")` — ответственность потребителя/stories.**
302
+ Calendar НЕ устанавливает локаль сам. Если забыть — заголовок и дни недели
303
+ будут на английском.
304
+ - **`pickedDate` — controlled**, `viewDate` / `viewMode` — internal state.
305
+ Не делать viewDate controlled без согласования: изменит API.
306
+ - **`onDateChange` — обязателен**. Нет default'а, без него выбор даты не
307
+ работает.
308
+ - **`todayButtonProps` — только гейт для футера**. Не рендерить футер без
309
+ него.
310
+ - **`data-tx={process.env.npm_package_version}`** на root — не удалять.
311
+ - **`CalendarContext.Provider` значение** передаётся через `pickType!` и
312
+ `limitRange!` (non-null assertion). Вся логика опирается на наличие
313
+ defaults — не убирать `defaultProps`.
314
+ - **`TButtonHTMLAttributesWithData` / `TTdHTMLAttributesWithData`** требуют
315
+ хотя бы один `data-*` атрибут (intersection). Не упрощать до
316
+ `ButtonHTMLAttributes` — это публичное обязательство контрактов для тестов.
317
+ - **Weekday-шапка, селектед-день и выключенный день — все проверяются через
318
+ `moment.isSame(..., unit)`**, не строковыми сравнениями. Не переписывать на
319
+ `===` по строкам: формат может отличаться.
320
+
321
+ ---
322
+
323
+ ## Accessibility
324
+
325
+ - **`periodId` + `headers`** на `<td>`-ячейках — озвучивает день недели для
326
+ screen reader'а ("Понедельник, 15 января"). Не убирать.
327
+ - **Фокус-менеджмент** — `CalendarViewContext.viewItemFocusedRef` хранит
328
+ последнюю сфокусированную ячейку, чтобы при смене viewMode (MONTHS → DAYS)
329
+ фокус возвращался на соответствующую ячейку. Не сломать при рефакторинге
330
+ CalendarViewItem.
331
+ - **Клавиатура** — arrow keys навигация реализована в `CalendarViewItem`
332
+ через внутренний handler (смотри компонент при изменениях).
333
+ - **`aria-label` на кнопках** — задаётся потребителем через
334
+ `prevButtonProps`/`nextButtonProps`/`viewButtonProps`. Нет default'ов,
335
+ потому что локализация — на стороне потребителя.
336
+ - **`data-*` атрибуты обязательны** через типы — обеспечивает testability и
337
+ часто используется как hook для analytics.
338
+ - **`disabledDays` и `limitRange`** — визуальное отключение + `disabled` на
339
+ `<button>` внутри ячейки. Screen reader озвучивает как "недоступно".
340
+ - **`role="status"` на весь Calendar?** — нет. Calendar — grid of interactive
341
+ cells, не статус. Внутри используется семантика `<table>` → `<td>` с
342
+ кнопками.
343
+
344
+ ---
345
+
346
+ ## Дизайн-токены
347
+
348
+ **Root:**
349
+ ```
350
+ --triplex-next-Calendar-Background # Фон календаря
351
+ ```
352
+
353
+ **View — заголовок и обычные ячейки:**
354
+ ```
355
+ --triplex-next-Calendar-View_Header_Color # Дни недели в шапке
356
+ --triplex-next-Calendar-View_Item_Color_Default
357
+ --triplex-next-Calendar-View_Item_Background_Default
358
+ --triplex-next-Calendar-View_Item_Background_Hover
359
+ --triplex-next-Calendar-View_Item_BorderColor_Default
360
+ --triplex-next-Calendar-View_Item_BorderColor_Focus # Keyboard-фокус
361
+ ```
362
+
363
+ **View — выбранная ячейка:**
364
+ ```
365
+ --triplex-next-Calendar-View_Item_Color_Selected
366
+ --triplex-next-Calendar-View_Item_Background_Selected_Default
367
+ --triplex-next-Calendar-View_Item_Background_Selected_Hover
368
+ ```
369
+
370
+ **View — "приглушённый" выбранный (muted, для days вне текущего месяца):**
371
+ ```
372
+ --triplex-next-Calendar-View_Item_Color_Selected_Muted_Default
373
+ --triplex-next-Calendar-View_Item_Color_Selected_Muted_Hover
374
+ --triplex-next-Calendar-View_Item_Background_Selected_Muted_Default
375
+ --triplex-next-Calendar-View_Item_Background_Selected_Muted_Hover
376
+ --triplex-next-Calendar-View_Item_Color_Muted # Days из соседних месяцев
377
+ ```
378
+
379
+ **View — отключённые ячейки:**
380
+ ```
381
+ --triplex-next-Calendar-View_Item_Color_Disabled # disabledDays + за limitRange
382
+ ```
383
+
384
+ **Метки (по 3 токена на каждый из 4 типов):**
385
+ ```
386
+ --triplex-next-Calendar-View_Item_Mark_Basic_Background_Default
387
+ --triplex-next-Calendar-View_Item_Mark_Basic_Background_Selected_Default
388
+ --triplex-next-Calendar-View_Item_Mark_Basic_Background_Selected_Hover
389
+ --triplex-next-Calendar-View_Item_Mark_Standard_Background_Default
390
+ --triplex-next-Calendar-View_Item_Mark_Standard_Background_Selected_Default
391
+ --triplex-next-Calendar-View_Item_Mark_Standard_Background_Selected_Hover
392
+ --triplex-next-Calendar-View_Item_Mark_Attention_Background_Default
393
+ --triplex-next-Calendar-View_Item_Mark_Attention_Background_Selected_Default
394
+ --triplex-next-Calendar-View_Item_Mark_Attention_Background_Selected_Hover
395
+ --triplex-next-Calendar-View_Item_Mark_Critical_Background_Default
396
+ --triplex-next-Calendar-View_Item_Mark_Critical_Background_Selected_Default
397
+ --triplex-next-Calendar-View_Item_Mark_Critical_Background_Selected_Hover
398
+ ```
399
+
400
+ Всего **28 токенов** — самое большое количество среди компонентов библиотеки.
401
+ При добавлении новой метки (`ECalendarDateMarkType.X`) нужно **четыре**
402
+ изменения: enum, 3 новых токена, обновление LESS с `.mark.x` классом, и
403
+ обновление `CalendarViewItem` с веткой `switch`.
404
+
405
+ ---
406
+
407
+ ## Связанные компоненты
408
+
409
+ - `DateField` (`src/components/DateField`) — input с календарным попапом,
410
+ оборачивающий Calendar через DateFieldPicker.
411
+ - `DateRange` (`src/components/DateRange`) — двойной Calendar для выбора
412
+ периода (from/to).
413
+ - `DatePickerExtended` (`src/components/DatePickerExtended`) — расширенный
414
+ picker с пресетами (сегодня, неделя, месяц) + Calendar в overlay.
415
+ - `MonthYearField` (`src/components/MonthYearField`) — input с Calendar в
416
+ режиме `monthYearPick`.
417
+ - `DateConst` (`src/consts/DateConst`) — `dateFormatYYYYMMDD`, `globalLimitRange`,
418
+ `headerDateFormat`. Используются как дефолты.
419
+ - `IDateLimitRange` (`src/types/DateTypes`) — тип `{dateFrom?, dateTo?}`
420
+ на базе Moment.
421
+
422
+ ---
423
+
424
+ ## Stories
425
+
426
+ `stories/Calendar/Calendar.stories.tsx`
427
+ Файлы примеров: `stories/Calendar/examples/`
428
+
429
+ | Story | Example file | Что демонстрирует |
430
+ |---|---|---|
431
+ | `Playground` | `PlaygroundExample.tsx` | Интерактивный выбор `pickType`, `defaultViewDate`, `format`, `reversedPick` |
432
+ | `Default` | `DefaultExample.tsx` | Базовое использование с controlled `pickedDate` |
433
+ | `PickTypes` | `PickTypesExample.tsx` | datePick vs monthYearPick бок о бок |
434
+ | `VisualTests` | `VisualTestsExample.tsx` | Снимки всех состояний для visual regression |
435
+
436
+ Stories обязательно содержат `moment.locale("ru")` — без этого заголовок/
437
+ weekday на английском.
438
+
439
+ ---
440
+
441
+ ## История изменений
442
+
443
+ | Дата | Изменение |
444
+ |---|---|
445
+ | 2026-04-18 | Создан документ |