@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.
- package/README.md +124 -0
- package/bundle/.gitkeep +0 -0
- package/bundle/components/AbstractTree.md +198 -0
- package/bundle/components/AccordionBase.md +227 -0
- package/bundle/components/Alert.md +317 -0
- package/bundle/components/Amount.md +225 -0
- package/bundle/components/AmountField.md +289 -0
- package/bundle/components/Avatar.md +209 -0
- package/bundle/components/Badge.md +277 -0
- package/bundle/components/Body.md +167 -0
- package/bundle/components/Button.md +230 -0
- package/bundle/components/ButtonDropdown.md +159 -0
- package/bundle/components/ButtonIcon.md +122 -0
- package/bundle/components/Calendar.md +445 -0
- package/bundle/components/Card.md +374 -0
- package/bundle/components/CarouselExtended.md +250 -0
- package/bundle/components/Checkbox.md +126 -0
- package/bundle/components/CheckboxTree.md +280 -0
- package/bundle/components/CheckboxTreeExtended.md +321 -0
- package/bundle/components/CheckboxXGroup.md +68 -0
- package/bundle/components/CheckboxYGroup.md +67 -0
- package/bundle/components/Chip.md +404 -0
- package/bundle/components/ChipGroup.md +179 -0
- package/bundle/components/Col.md +221 -0
- package/bundle/components/CollapsableTree.md +255 -0
- package/bundle/components/Confirm.md +343 -0
- package/bundle/components/DateField.md +371 -0
- package/bundle/components/DatePickerExtended.md +342 -0
- package/bundle/components/DateRange.md +275 -0
- package/bundle/components/DesignTokens.md +385 -0
- package/bundle/components/Divider.md +196 -0
- package/bundle/components/DocumentNumberEdit.md +280 -0
- package/bundle/components/Dropdown.md +433 -0
- package/bundle/components/Ellipsis.md +208 -0
- package/bundle/components/EmptyView.md +99 -0
- package/bundle/components/ExpandAnimation.md +281 -0
- package/bundle/components/Footer.md +339 -0
- package/bundle/components/FormField.md +326 -0
- package/bundle/components/FormGroup.md +99 -0
- package/bundle/components/Gap.md +113 -0
- package/bundle/components/Header.md +280 -0
- package/bundle/components/HelpBox.md +154 -0
- package/bundle/components/IconWrapper.md +145 -0
- package/bundle/components/Island.md +197 -0
- package/bundle/components/IslandAccordion.md +230 -0
- package/bundle/components/IslandWidget.md +233 -0
- package/bundle/components/KeyDownListener.md +157 -0
- package/bundle/components/LightBox.md +322 -0
- package/bundle/components/Link.md +161 -0
- package/bundle/components/List.md +247 -0
- package/bundle/components/ListMaster.md +204 -0
- package/bundle/components/Loader.md +161 -0
- package/bundle/components/LoaderScreen.md +134 -0
- package/bundle/components/Marker.md +127 -0
- package/bundle/components/MarkerStatus.md +148 -0
- package/bundle/components/MediaWidth.md +169 -0
- package/bundle/components/MobileView.md +120 -0
- package/bundle/components/ModalWindow.md +308 -0
- package/bundle/components/MonthYearField.md +168 -0
- package/bundle/components/MultiselectField.md +213 -0
- package/bundle/components/Notification.md +233 -0
- package/bundle/components/NumberField.md +178 -0
- package/bundle/components/OrderedList.md +169 -0
- package/bundle/components/Overlay.md +237 -0
- package/bundle/components/Page.md +246 -0
- package/bundle/components/Pagination.md +298 -0
- package/bundle/components/Portal.md +119 -0
- package/bundle/components/Radio.md +174 -0
- package/bundle/components/Row.md +125 -0
- package/bundle/components/SMSField.md +160 -0
- package/bundle/components/SegmentedControl.md +235 -0
- package/bundle/components/SelectExtendedField.md +322 -0
- package/bundle/components/SelectField.md +213 -0
- package/bundle/components/Skeleton.md +129 -0
- package/bundle/components/Slider.md +157 -0
- package/bundle/components/SliderExtended.md +210 -0
- package/bundle/components/SliderRange.md +160 -0
- package/bundle/components/SmallInput.md +101 -0
- package/bundle/components/Spoiler.md +121 -0
- package/bundle/components/StatusTracker.md +151 -0
- package/bundle/components/Step.md +121 -0
- package/bundle/components/Stepper.md +163 -0
- package/bundle/components/Suggest.md +160 -0
- package/bundle/components/SuggestField.md +157 -0
- package/bundle/components/SwipeableArea.md +144 -0
- package/bundle/components/Table.md +199 -0
- package/bundle/components/Tabs.md +152 -0
- package/bundle/components/TabsExtended.md +273 -0
- package/bundle/components/TabsLine.md +189 -0
- package/bundle/components/Tag.md +135 -0
- package/bundle/components/TagColor.md +121 -0
- package/bundle/components/TagGroup.md +100 -0
- package/bundle/components/TextField.md +152 -0
- package/bundle/components/TextareaField.md +124 -0
- package/bundle/components/ThemeProvider.md +181 -0
- package/bundle/components/Tooltip.md +254 -0
- package/bundle/components/TopOverlay.md +145 -0
- package/bundle/components/TreeView.md +224 -0
- package/bundle/components/Triggers.md +121 -0
- package/bundle/guides/codestyle.md +205 -0
- package/bundle/guides/commits.md +166 -0
- package/bundle/guides/context.md +277 -0
- package/bundle/guides/stories.md +618 -0
- package/bundle/guides/template.md +154 -0
- package/bundle/guides/tests.md +301 -0
- package/bundle/icons.json +4156 -0
- package/bundle/manifest.json +796 -0
- package/bundle/release-notes/1.1.0.mdx +26 -0
- package/bundle/release-notes/1.1.1.mdx +14 -0
- package/bundle/release-notes/1.10.0.mdx +43 -0
- package/bundle/release-notes/1.11.0.mdx +19 -0
- package/bundle/release-notes/1.12.0.mdx +21 -0
- package/bundle/release-notes/1.13.0.mdx +43 -0
- package/bundle/release-notes/1.14.0.mdx +29 -0
- package/bundle/release-notes/1.15.0.mdx +56 -0
- package/bundle/release-notes/1.16.0.mdx +55 -0
- package/bundle/release-notes/1.17.0.mdx +15 -0
- package/bundle/release-notes/1.18.0.mdx +24 -0
- package/bundle/release-notes/1.19.0.mdx +48 -0
- package/bundle/release-notes/1.19.1.mdx +9 -0
- package/bundle/release-notes/1.2.0.mdx +80 -0
- package/bundle/release-notes/1.20.0.mdx +48 -0
- package/bundle/release-notes/1.21.0.mdx +66 -0
- package/bundle/release-notes/1.22.0.mdx +75 -0
- package/bundle/release-notes/1.23.0.mdx +50 -0
- package/bundle/release-notes/1.24.0.mdx +59 -0
- package/bundle/release-notes/1.25.0.mdx +52 -0
- package/bundle/release-notes/1.26.0.mdx +11 -0
- package/bundle/release-notes/1.3.0.mdx +21 -0
- package/bundle/release-notes/1.4.0.mdx +37 -0
- package/bundle/release-notes/1.5.0.mdx +24 -0
- package/bundle/release-notes/1.6.0.mdx +37 -0
- package/bundle/release-notes/1.6.1.mdx +11 -0
- package/bundle/release-notes/1.7.0.mdx +29 -0
- package/bundle/release-notes/1.8.0.mdx +38 -0
- package/bundle/release-notes/1.9.0.mdx +28 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- 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 | Создан документ |
|