@sberbusiness/triplex-next-mcp-server 1.50.0-beta → 1.53.1

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 (74) hide show
  1. package/README.md +1 -0
  2. package/bundle/components/AlertProcess.md +6 -3
  3. package/bundle/components/AlertProcessSpoiler.md +216 -0
  4. package/bundle/components/Badge.md +4 -3
  5. package/bundle/components/ButtonDropdown.md +5 -3
  6. package/bundle/components/Carousel.md +671 -0
  7. package/bundle/components/CarouselExtended.md +7 -5
  8. package/bundle/components/CarouselIndicators.md +666 -0
  9. package/bundle/components/CarouselItem.md +579 -0
  10. package/bundle/components/CarouselNextButton.md +633 -0
  11. package/bundle/components/CarouselPrevButton.md +633 -0
  12. package/bundle/components/CarouselViewport.md +631 -0
  13. package/bundle/components/CheckboxTreeExtended.md +21 -7
  14. package/bundle/components/CheckboxTreeExtendedCheckbox.md +591 -0
  15. package/bundle/components/CheckboxTreeExtendedNode.md +577 -0
  16. package/bundle/components/Chip.md +1 -0
  17. package/bundle/components/ChipDatePicker.md +332 -0
  18. package/bundle/components/ChipDatePickerTarget.md +316 -0
  19. package/bundle/components/ChipMonthYearPicker.md +4 -3
  20. package/bundle/components/ChipMonthYearPickerTarget.md +318 -0
  21. package/bundle/components/ChipMultiselect.md +63 -73
  22. package/bundle/components/ChipSelect.md +385 -0
  23. package/bundle/components/ChipSelectTarget.md +388 -0
  24. package/bundle/components/ChipSuggest.md +10 -16
  25. package/bundle/components/ChipSuggestTarget.md +506 -0
  26. package/bundle/components/CollapsibleTree.md +2 -1
  27. package/bundle/components/CollapsibleTreeExtended.md +2 -1
  28. package/bundle/components/DateField.md +4 -2
  29. package/bundle/components/DatePickerExtended.md +16 -14
  30. package/bundle/components/DateRange.md +17 -10
  31. package/bundle/components/Dropdown.md +36 -63
  32. package/bundle/components/EmptyView.md +9 -4
  33. package/bundle/components/ExpandAnimation.md +9 -5
  34. package/bundle/components/FormField.md +1 -1
  35. package/bundle/components/ImageGallery.md +19 -52
  36. package/bundle/components/ImageGalleryExtended.md +123 -139
  37. package/bundle/components/ListItemControlsButtonDropdown.md +3 -2
  38. package/bundle/components/LoaderSmall.md +5 -4
  39. package/bundle/components/MonthYearRange.md +334 -0
  40. package/bundle/components/MultiselectField.md +81 -143
  41. package/bundle/components/Notification.md +2 -1
  42. package/bundle/components/NotificationGrouped.md +174 -0
  43. package/bundle/components/NumberField.md +259 -116
  44. package/bundle/components/OrderedList.md +149 -112
  45. package/bundle/components/Overlay.md +3 -2
  46. package/bundle/components/PageIndicators.md +306 -0
  47. package/bundle/components/Pagination.md +81 -3
  48. package/bundle/components/PaginationExtended.md +160 -0
  49. package/bundle/components/Portal.md +5 -2
  50. package/bundle/components/Puller.md +375 -0
  51. package/bundle/components/SMSField.md +277 -102
  52. package/bundle/components/SelectExtendedField.md +11 -7
  53. package/bundle/components/SelectField.md +7 -4
  54. package/bundle/components/SmartSpot.md +259 -0
  55. package/bundle/components/Step.md +2 -1
  56. package/bundle/components/Stepper.md +7 -7
  57. package/bundle/components/Suggest.md +7 -6
  58. package/bundle/components/SuggestField.md +8 -6
  59. package/bundle/components/TableBasic.md +12 -14
  60. package/bundle/components/Tooltip.md +9 -8
  61. package/bundle/guides/commits.md +4 -1
  62. package/bundle/guides/context.md +5 -5
  63. package/bundle/guides/stories.md +29 -21
  64. package/bundle/manifest.json +145 -13
  65. package/bundle/release-notes/1.50.0.mdx +4 -0
  66. package/bundle/release-notes/1.51.0.mdx +57 -0
  67. package/bundle/release-notes/1.52.0.mdx +55 -0
  68. package/bundle/release-notes/1.53.0.mdx +60 -0
  69. package/bundle/release-notes/1.54.0.mdx +45 -0
  70. package/bundle/release-notes/1.55.0.mdx +7 -0
  71. package/bundle/tokens.json +377 -222
  72. package/dist/index.js +39 -1
  73. package/dist/index.js.map +1 -1
  74. package/package.json +1 -1
@@ -0,0 +1,332 @@
1
+ ---
2
+ component: ChipDatePicker
3
+ category: Chips
4
+ related: [Chip, ChipDatePickerTarget, ChipMonthYearPicker, DateField, DatePickerExtended, Puller]
5
+ tokens: []
6
+ stories: stories/Chips/ChipDatePicker.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # ChipDatePicker
11
+
12
+ ## Назначение
13
+
14
+ Управляемый выбор даты в виде чипса-фильтра. Показывает название фильтра либо
15
+ выбранную дату, открывает календарь и позволяет очистить выбор. В мобильном
16
+ дропдауне дополнительно доступен ручной ввод даты с маской.
17
+
18
+ Используй когда: в панели фильтров нужна конкретная дата, а выбранное значение
19
+ должно читаться прямо на чипсе. Размещай в `ChipGroup` для общих отступов и переноса.
20
+ Не используй когда: нужен месяц без дня (`ChipMonthYearPicker`), диапазон дат
21
+ (`DateRange`) или поле формы со статусом валидации (`DateField`).
22
+
23
+ Публичное подключение: `import { ChipDatePicker } from "@sberbusiness/triplex-next"`.
24
+ Потребитель хранит `value` и обновляет его в `onChange`.
25
+
26
+ ---
27
+
28
+ ## Варианты и props
29
+
30
+ `IChipDatePickerProps` наследует `IDateFieldProps` без `status` и `invalidDateHint`,
31
+ добавляет `type` / `disabled` от `IChipProps` и обязательный `label`.
32
+ Точные типы и полный список календарных props находятся в исходниках этих интерфейсов.
33
+
34
+ ### Значение и отображение
35
+
36
+ | Prop | По умолчанию | Назначение и ограничения |
37
+ |---|---|---|
38
+ | `value` | Обязателен | Строка в формате `format`; `""` означает отсутствие выбора |
39
+ | `onChange` | Обязателен | Получает дату в формате `format` или `""` при очистке. Выбор календаря вызывает его сразу, ручной ввод — при закрытии дропдауна |
40
+ | `label` | Обязателен | `React.ReactNode` в невыбранном состоянии |
41
+ | `displayedValue` | — | Заменяет текст выбранной даты. При пустом или недоступном `value` игнорируется; `0` и `""` сохраняются, так как используется `??` |
42
+ | `format` | `"YYYYMMDD"` | Транспортный формат `value` и аргумента `onChange`. Отображение и мобильный ввод используют `"DD.MM.YYYY"` (`inputDateFormat`) |
43
+ | `placeholderMask` | — | Заполнение пустых позиций маски мобильного поля; не является подписью чипса |
44
+
45
+ Значение разбирается строго: невозможная дата, несовпадение с `format`, выход за
46
+ `limitRange` или попадание в `disabledDays` превращают его в невыбранное состояние.
47
+ Вместо ошибки показывается `label`, а справа — стрелка раскрытия. При выбранной
48
+ дате справа отображается кнопка очистки.
49
+
50
+ ### Внешний вид и календарь
51
+
52
+ | Prop или группа | По умолчанию | Назначение и ограничения |
53
+ |---|---|---|
54
+ | `size` | `EComponentSize.MD` | SM / MD / LG; размер чипса, стрелки и кнопки очистки |
55
+ | `type` | `EChipType.TYPE_1` | TYPE_1 / TYPE_2; фон чипса |
56
+ | `disabled` | `false` | Визуальное отключение чипса и исключение его из tab-порядка; ограничения описаны в Accessibility |
57
+ | `limitRange` | `globalLimitRange` | Границы выбора: 1900-01-01 … 2199-12-31 по умолчанию |
58
+ | `disabledDays` | — | Недоступные дни в транспортном формате, проверяются и для `value`, и для ручного ввода |
59
+ | `alignment` | `EDropdownAlignment.LEFT` | Выравнивание дропдауна |
60
+ | `defaultViewDate`, `markedDays`, `reversedPick`, `pickType` | От `Calendar` | Настройка календаря через `DatePickerExtended`. `pickType` по умолчанию `DATE`, в отличие от `ChipMonthYearPicker` не зафиксирован |
61
+ | `onViewChange`, `onPageChange`, `dayHtmlAttributes`, `monthHtmlAttributes`, `yearHtmlAttributes` | — | События навигации и атрибуты ячеек календаря |
62
+ | `prevButtonProps`, `nextButtonProps`, `viewButtonProps`, `yesterdayButtonProps`, `todayButtonProps`, `tomorrowButtonProps` | — | Кнопки управления и футер календаря |
63
+ | `onDropdownOpen`, `onDropdownClose` | — | Уведомления о переходах открытости; при закрытии сначала обрабатывается мобильный ввод, затем вызывается `onDropdownClose` |
64
+ | `focusTrapProps` | От `DatePickerExtended` | Настройка десктопной ловушки фокуса |
65
+
66
+ ### Передача атрибутов
67
+
68
+ `className`, `id`, `data-*`, `aria-*` и обработчики `<div>` из `...rest` уходят
69
+ на корневой `<div>` `DatePickerExtended`, а не на чипс-таргет и не на мобильное поле.
70
+ В текущей реализации пользовательский `className` переопределяет `.chipGroupItem`
71
+ корня из-за порядка spread; его слияние изменило бы существующее поведение.
72
+
73
+ Унаследованные `onClear` и `targetProps` присутствуют в типе, но не подключены к
74
+ `ChipDatePickerTarget`: они не настраивают очистку и внутренний таргет.
75
+ Очистка всегда сообщает `onChange("")`. Удалять эти props при рефакторинге нельзя.
76
+
77
+ ### Незавершённый мобильный ввод
78
+
79
+ - Открытый чипс сохраняет последнее значение из внешних props; промежуточный
80
+ ввод меняет мобильное поле и выбранный день календаря, а не подпись чипса.
81
+ - При закрытии полная допустимая дата коммитится через `onChange`; пустой ввод
82
+ очищает ранее выбранную дату. Повторная передача того же значения не нужна.
83
+ - Неполная, невозможная, запрещённая или выходящая за границы дата откатывается
84
+ к последнему значению из props без вызова `onChange`.
85
+ - Выбор в календаре закрывает дропдаун и сообщает дату один раз: флаг
86
+ `dropdownClosedByCalendarRef` предотвращает дополнительный коммит ручного ввода.
87
+ - Изменение `value`, `format`, `limitRange` или `disabledDays` синхронизирует поле
88
+ с внешними props. Эффект намеренно не зависит от промежуточного `pickerValues`,
89
+ иначе каждый введённый символ затирался бы прежним `value`.
90
+
91
+ ---
92
+
93
+ ## Дизайн-токены
94
+
95
+ Собственных токенов нет: используемый самим компонентом `.chipGroupItem` из
96
+ `styles/Chip.module.less` задаёт только `display: inline-block`, поэтому
97
+ frontmatter содержит `tokens: []`.
98
+
99
+ Внешний вид композиции задают зависимости: `Chip` (фон, цвет, фокус, selected и
100
+ disabled), `Calendar` (календарь) и `Dropdown` (выпадающий блок). Их токены описаны
101
+ в соответствующих AI.md; например, фон обычного чипса — `Chip.Background_Type1_Default`,
102
+ фокус — `Chip.Shadow_Focus`, фон календаря — `Calendar.Background`.
103
+
104
+ Порядок переопределения токенов описан в
105
+ [ThemeProvider-ai.md](../ThemeProvider/ThemeProvider-ai.md#как-переопределять-токены).
106
+
107
+ ---
108
+
109
+ ## Инварианты
110
+
111
+ - `forwardRef<HTMLDivElement>` сохраняется: ссылка указывает на корневой
112
+ `<div>` `DatePickerExtended`, а не на `<span>` чипса или `<input>`.
113
+ - `value` / `onChange` — управляемый контракт, очистка передаёт пустую строку.
114
+ `format` не меняет `inputDateFormat` и видимую маску.
115
+ - Нельзя добавлять промежуточные значения поля в зависимости эффекта
116
+ синхронизации с props либо терять разграничение ввода и выбора календаря.
117
+ - `DateFieldUtils` и `inputDateFormat` импортируются из внутренних модулей
118
+ `DateField`; изменения их логики или сигнатур требуют проверки обоих компонентов.
119
+ - `IChipDatePickerProps`, `ChipDatePicker`, `ChipDatePickerTarget` и его props
120
+ экспортируются через `src/components/Chip/index.ts` и вложенный barrel; сохранять
121
+ имена, типы и экспорты. Контракт таргета описан в [ChipDatePickerTarget-ai.md](./ChipDatePickerTarget-ai.md).
122
+ - Story ids `chips-chipdatepicker--*` используются существующими baseline-файлами
123
+ xs / xl, поэтому их нельзя переименовывать без обновления visual-проверок.
124
+
125
+ ---
126
+
127
+ ## Accessibility
128
+
129
+ - Таргет — `Chip` с `<span role="button">`, фокусируемый через `tabIndex={0}`.
130
+ Доступное имя берётся из `label` или отображаемого значения; `aria-expanded`
131
+ отражает состояние календаря. Enter / Space переключают дропдаун с
132
+ `preventDefault()`, Escape из корня или портала закрывает его.
133
+ - Десктопный календарь находится в `role="dialog"` с `aria-modal` и `FocusTrap`.
134
+ При открытии с клавиатуры фокус переходит внутрь и возвращается на таргет при
135
+ закрытии; открытие мышью не перехватывает фокус. Настройки делегированы
136
+ `DatePickerExtended`.
137
+ - В мобильном режиме шапка содержит редактируемое маскированное поле с
138
+ `autoFocus`, изменение коммитится при закрытии. `aria-label` корня не
139
+ пробрасывается этому полю: отдельного prop для его настройки сейчас нет.
140
+ - `disabled` даёт классу `Chip` `pointer-events: none` и `tabIndex={-1}`,
141
+ но не является нативным `disabled`. `ChipDatePickerTarget` пока не блокирует
142
+ программно отправленные клики и клавиши, а кнопка очистки не получает
143
+ `disabled`; на такое отключение нельзя полагаться как на защиту обработчиков.
144
+ - Кнопка очистки останавливает всплытие клика, чтобы не открывать календарь.
145
+ Доступное имя ей пока нельзя передать через `ChipDatePicker`: собственного
146
+ `clearButtonProps` нет, а `targetProps` не подключён. Это существующее ограничение,
147
+ связанное с задачами `ChipClearButton` / `ChipDatePickerTarget`, а не требование
148
+ добавлять локализованную строку внутрь библиотеки.
149
+
150
+ ---
151
+
152
+ ## Связанные компоненты
153
+
154
+ - `Chip` — база таргета и источник визуальных состояний; родитель семейства.
155
+ - [ChipDatePickerTarget](./ChipDatePickerTarget-ai.md) — публичный таргет со своим контекстным и клавиатурным
156
+ контрактом: читает `DatePickerExtendedContext`, переключает дропдаун, выбирает
157
+ между `ChipClearButton` и `ChipDropdownArrow`.
158
+ - `ChipMonthYearPicker` — альтернатива для выбора месяца без дня и ручного ввода.
159
+ - `DateField` — альтернатива в форме; источник унаследованного интерфейса,
160
+ `DateFieldUtils` и `inputDateFormat`.
161
+ - `DatePickerExtended` — рендерится внутри, владеет календарём, дропдауном,
162
+ открытостью и корневым DOM-элементом.
163
+ - `Puller` — мобильная шторка календаря; в её шапке рендерится `PullerMaskedInput` —
164
+ обёртка над `FormFieldMaskedInput`, общие props поля и маски описаны в `FormField`.
165
+ - `ChipGroup` — рекомендуемый контейнер для ряда фильтров.
166
+
167
+ ---
168
+
169
+ ## Stories
170
+
171
+ Основные истории: `stories/Chips/ChipDatePicker.stories.tsx`
172
+ Файлы примеров: `stories/Chips/examples/ChipDatePicker/`
173
+
174
+ | Story | Example file | Что демонстрирует |
175
+ |---|---|---|
176
+ | `Playground` | `PlaygroundExample.tsx` | Управляемый выбор с контролами type, size, label, displayedValue, disabled |
177
+ | `Default` | `DefaultExample.tsx` | Минимальный управляемый фильтр value / onChange |
178
+ | `Types` | `TypesExample.tsx` | TYPE_1 / TYPE_2 |
179
+ | `Sizes` | `SizesExample.tsx` | SM / MD / LG |
180
+ | `WithCustomDisplayedValue` | `WithCustomDisplayedValueExample.tsx` | Подмена текста выбранного значения |
181
+ | `VisualTests` | `VisualTestsExample.tsx` | Три размера с фиксированной датой 19700101; play открывает последний календарь |
182
+
183
+ Для всех пяти не-Playground историй существуют baseline-скриншоты xs / xl в
184
+ `__screenshots__/`. Stories и их идентификаторы в TRI-136 сохранены.
185
+
186
+ ---
187
+
188
+ ## История изменений
189
+
190
+ | Дата | Изменение |
191
+ |---|---|
192
+ | 2026-10-19 | Создан документ; подтверждены контракт управляемой даты, мобильного ввода и существующие ограничения. Лениво инициализировано состояние и дополнены unit-тесты (TRI-136) |
193
+ | 2026-10-21 | Добавлена ссылка на отдельную AI-документацию ChipDatePickerTarget |
194
+ | 2026-10-21 | Переход на `Puller` (TRIPLEX-961): мобильный ввод даты — `PullerMaskedInput` (бывший `DropdownMobileMaskedInput`). |
195
+
196
+ ---
197
+
198
+ ## Примеры использования
199
+
200
+ ### Default
201
+
202
+ `stories/Chips/examples/ChipDatePicker/DefaultExample.tsx`
203
+
204
+ ```tsx
205
+ import React, { useState } from "react";
206
+ import { ChipDatePicker, EComponentSize, EDropdownAlignment } from "@sberbusiness/triplex-next";
207
+
208
+ export const DefaultExample = () => {
209
+ const [value, setValue] = useState("");
210
+ return (
211
+ <ChipDatePicker
212
+ value={value}
213
+ label="Date label"
214
+ onChange={setValue}
215
+ alignment={EDropdownAlignment.LEFT}
216
+ size={EComponentSize.MD}
217
+ />
218
+ );
219
+ };
220
+ ```
221
+
222
+ ### Types
223
+
224
+ `stories/Chips/examples/ChipDatePicker/TypesExample.tsx`
225
+
226
+ ```tsx
227
+ import React, { useState } from "react";
228
+ import { ChipDatePicker, EChipType, EDropdownAlignment } from "@sberbusiness/triplex-next";
229
+
230
+ type TypeItemProps = {
231
+ type: EChipType;
232
+ label: string;
233
+ };
234
+
235
+ const TypeItem = ({ type, label }: TypeItemProps) => {
236
+ const [value, setValue] = useState("");
237
+
238
+ return (
239
+ <div>
240
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{label}</div>
241
+ <ChipDatePicker
242
+ value={value}
243
+ label="Date label"
244
+ type={type}
245
+ alignment={EDropdownAlignment.LEFT}
246
+ onChange={setValue}
247
+ />
248
+ </div>
249
+ );
250
+ };
251
+
252
+ const typeOptions = Object.values(EChipType).map((type) => ({
253
+ value: type,
254
+ label: type.toUpperCase(),
255
+ }));
256
+
257
+ export const TypesExample = () => (
258
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
259
+ {typeOptions.map(({ value, label }) => (
260
+ <TypeItem key={value} type={value} label={label} />
261
+ ))}
262
+ </div>
263
+ );
264
+ ```
265
+
266
+ ### Sizes
267
+
268
+ `stories/Chips/examples/ChipDatePicker/SizesExample.tsx`
269
+
270
+ ```tsx
271
+ import React, { useState } from "react";
272
+ import { ChipDatePicker, EComponentSize, EDropdownAlignment } from "@sberbusiness/triplex-next";
273
+
274
+ type SizeItemProps = {
275
+ size: EComponentSize;
276
+ label: string;
277
+ };
278
+
279
+ const SizeItem = ({ size, label }: SizeItemProps) => {
280
+ const [value, setValue] = useState("");
281
+
282
+ return (
283
+ <div>
284
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{label}</div>
285
+ <ChipDatePicker
286
+ size={size}
287
+ alignment={EDropdownAlignment.LEFT}
288
+ value={value}
289
+ label="Date label"
290
+ onChange={setValue}
291
+ />
292
+ </div>
293
+ );
294
+ };
295
+
296
+ const sizeOptions = Object.values(EComponentSize).map((size) => ({
297
+ value: size,
298
+ label: size.toUpperCase(),
299
+ }));
300
+
301
+ export const SizesExample = () => (
302
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
303
+ {sizeOptions.map(({ value, label }) => (
304
+ <SizeItem key={value} size={value} label={label} />
305
+ ))}
306
+ </div>
307
+ );
308
+ ```
309
+
310
+ ### WithCustomDisplayedValue
311
+
312
+ `stories/Chips/examples/ChipDatePicker/WithCustomDisplayedValueExample.tsx`
313
+
314
+ ```tsx
315
+ import React, { useState } from "react";
316
+ import { ChipDatePicker, EComponentSize, EDropdownAlignment } from "@sberbusiness/triplex-next";
317
+
318
+ export const WithCustomDisplayedValueExample = () => {
319
+ const [value, setValue] = useState("");
320
+ return (
321
+ <ChipDatePicker
322
+ value={value}
323
+ label="Date label"
324
+ onChange={setValue}
325
+ alignment={EDropdownAlignment.LEFT}
326
+ size={EComponentSize.MD}
327
+ displayedValue="Date value"
328
+ />
329
+ );
330
+ };
331
+ ```
332
+
@@ -0,0 +1,316 @@
1
+ ---
2
+ component: ChipDatePickerTarget
3
+ category: Chips
4
+ related: [ChipDatePicker, Chip, DatePickerExtended]
5
+ tokens: []
6
+ stories: stories/Chips/ChipDatePicker.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # ChipDatePickerTarget
11
+
12
+ ## Назначение
13
+
14
+ Публичный target для выбора даты в виде `Chip`: переключает выпадающий календарь
15
+ через `DatePickerExtendedContext`, показывает стрелку либо кнопку очистки.
16
+ Сам не хранит дату и не форматирует `children`.
17
+
18
+ Используй когда: нужна своя композиция `DatePickerExtended.renderTarget`
19
+ с чипсом, собственным контентом, `prefix` или `postfix`.
20
+ Не используй когда: достаточно готового управляемого фильтра `ChipDatePicker`
21
+ с `value`, `onChange` и мобильным вводом даты.
22
+
23
+ Публичное подключение:
24
+
25
+ ```tsx
26
+ import { ChipDatePickerTarget, type IChipDatePickerTargetProps } from "@sberbusiness/triplex-next";
27
+ ```
28
+
29
+ Возвращай target из `DatePickerExtended.renderTarget`: там он получает рабочий
30
+ контекст. Вне provider используется значение контекста по умолчанию
31
+ (`dropdownOpen: false`, пустой setter), поэтому самостоятельный target не открывает
32
+ календарь. Создавать свой `Context.Provider` для обычной композиции не требуется.
33
+
34
+ Минимальная управляемая композиция:
35
+
36
+ ```tsx
37
+ const [pickedDate, setPickedDate] = useState<string | null>(null);
38
+
39
+ <DatePickerExtended
40
+ pickedDate={pickedDate}
41
+ onDateChange={(date) => setPickedDate(date.format("YYYYMMDD"))}
42
+ renderTarget={() => (
43
+ <ChipDatePickerTarget selected={pickedDate !== null} onClear={() => setPickedDate(null)}>
44
+ {pickedDate ? moment(pickedDate, "YYYYMMDD").format("DD.MM.YYYY") : "Выберите дату"}
45
+ </ChipDatePickerTarget>
46
+ )}
47
+ renderDropdownHeaderTarget={() => <span>Выберите дату</span>}
48
+ />;
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Варианты и props
54
+
55
+ `IChipDatePickerTargetProps` наследует `IChipProps` целиком и добавляет обязательный
56
+ `onClear`. Точные типы унаследованных атрибутов находятся в исходниках `Chip`.
57
+
58
+ ### Значение и callbacks
59
+
60
+ | Prop | По умолчанию | Назначение и ограничения |
61
+ |---|---|---|
62
+ | `onClear` | Обязателен | Вызывается без аргументов по клику встроенной кнопки очистки; потребитель сбрасывает свою дату и `selected` |
63
+ | `selected` | `false` | Управляемое визуальное состояние; при `true` вместо стрелки рендерится `ChipClearButton` |
64
+ | `children` | — | Подпись фильтра или выбранная дата; форматирует потребитель |
65
+ | `onClick` | — | Получает исходное событие после вызова `setDropdownOpen(!dropdownOpen)` |
66
+ | `onKeyDown` | — | Получает событие только для `event.code` Enter / Space, после `preventDefault()` и переключения контекста; для остальных клавиш не вызывается |
67
+
68
+ `onClear` не закрывает открытый календарь и не меняет `selected` автоматически.
69
+ Клик встроенной кнопки вызывает `stopPropagation()`, поэтому не переключает
70
+ календарь и не вызывает `onClick` target.
71
+
72
+ ### Внешний вид и унаследованные атрибуты
73
+
74
+ | Prop или группа | По умолчанию | Назначение и ограничения |
75
+ |---|---|---|
76
+ | `size` | `EComponentSize.MD` | SM / MD / LG; передаётся в `Chip`, стрелку и встроенную кнопку очистки |
77
+ | `type` | `EChipType.TYPE_1` | TYPE_1 / TYPE_2; визуальная тема `Chip` |
78
+ | `disabled` | `false` | CSS-блокировка указателя и `tabIndex={-1}` у `Chip`; ограничения ниже |
79
+ | `prefix` | — | Контент перед подписью через слот `Chip` |
80
+ | `postfix` | Автоматическая стрелка или очистка | Переданное значение переопределяет автоматический postfix, включая явно переданный `undefined`; обработчики пользовательского слота задаёт потребитель |
81
+ | `showNotificationIcon` | `false` | Значок `Badge.Dot` через `Chip` |
82
+ | `className`, `style`, `id`, `data-*`, `aria-*`, прочие span-атрибуты | — | Передаются в корневой `<span>` `Chip`; `className` объединяется с его классами |
83
+
84
+ `...restProps` расположен после `postfix` и `aria-expanded`, поэтому потребитель
85
+ может переопределить их, а также унаследованные `role` и `tabIndex`. Сохраняй
86
+ согласованность ARIA с реальной открытостью календаря. Для необязательных слотов
87
+ учитывай правила `Chip`: явный `null` / `false` оставляет класс отступов без контента.
88
+
89
+ ---
90
+
91
+ ## Дизайн-токены
92
+
93
+ Собственных стилей и токенов нет: frontmatter содержит `tokens: []`.
94
+ Внешний вид задают зависимости: `Chip` (например, `Chip.Background_Type1_Default`,
95
+ `Chip.Background_Selected_Default`, `Chip.Color_Disabled`, `Chip.Shadow_Focus`)
96
+ и `ChipClearButton` (фокус использует `Chip.Shadow_Focus`). Стрелка использует
97
+ палитру иконок, отдельных токенов target не добавляет.
98
+
99
+ Полный набор — в [Chip-ai.md](./Chip-ai.md#дизайн-токены); значения по умолчанию —
100
+ `src/components/DesignTokens/components/Chip.ts`. Переопределение через
101
+ `ThemeProvider.tokens` описано в
102
+ [ThemeProvider-ai.md](../ThemeProvider/ThemeProvider-ai.md#как-переопределять-токены).
103
+
104
+ ---
105
+
106
+ ## Инварианты
107
+
108
+ - `forwardRef<HTMLSpanElement>` сохраняется: ref указывает на корневой `<span>`
109
+ `Chip`, а не на кнопку очистки, календарь или корень `DatePickerExtended`.
110
+ - `ChipDatePickerTarget` и `IChipDatePickerTargetProps` экспортируются именованно
111
+ через `src/components/Chip/ChipDatePicker/index.ts` и `src/components/Chip/index.ts`;
112
+ имена, типы props и barrel-экспорты сохраняются.
113
+ - Открытость читается из `DatePickerExtendedContext`; не добавлять локальную копию
114
+ состояния, иначе стрелка и `aria-expanded` разойдутся с календарём.
115
+ - `selected` приходит от потребителя, `onClear` получает ноль аргументов. Не
116
+ подменять его DOM-событием или изменением даты внутри target.
117
+ - Клик target сначала вызывает setter контекста, затем `onClick`. Enter / Space
118
+ сначала отменяют действие браузера, переключают контекст, затем вызывают
119
+ пользовательский `onKeyDown` внутри той же ветки.
120
+ - Порядок spread сохраняет переопределение `postfix` и `aria-expanded` через props.
121
+ - Корневой элемент, CSS-контракт `Chip` и ref-target не меняются при AI-рефакторинге.
122
+
123
+ ---
124
+
125
+ ## Accessibility
126
+
127
+ - По умолчанию это `<span role="button" tabIndex={0}>`; имя задаётся текстом
128
+ `children` или переданным `aria-label`. `selected` сам не добавляет `aria-pressed`.
129
+ - `aria-expanded` берётся из контекста. `aria-haspopup` и `aria-controls`
130
+ автоматически не задаются: нужные атрибуты и ID-связи передаёт потребитель.
131
+ - Enter / Space распознаются по `event.code`, переключают календарь и вызывают
132
+ `preventDefault()`. Остальные клавиши не передаются в пользовательский
133
+ `onKeyDown` target. Escape, ловушка фокуса и возврат фокуса принадлежат
134
+ `DatePickerExtended`, а навигация по датам — `Calendar`.
135
+ - `disabled` у `Chip` означает `pointer-events: none` и `tabIndex={-1}`,
136
+ а не нативное отключение `<span>`; программно отправленные события
137
+ обработчики не блокируют. Встроенная кнопка очистки не получает `disabled`.
138
+ - Встроенная очистка останавливает только всплытие клика. Её Enter / Space
139
+ всплывают в target: обработчик target вызывает `preventDefault()`, отменяя
140
+ нативную активацию кнопки, и переключает календарь. Поэтому встроенную
141
+ кнопку нельзя нажать с клавиатуры — `onClear` не вызывается. Доступное имя
142
+ из props target кнопке не передаётся, `clearButtonProps` у компонента нет.
143
+ Это существующие ограничения, а не желаемое поведение.
144
+ - Для клавиатурно доступной именованной очистки передай свою кнопку в `postfix`:
145
+ `aria-label`, остановка всплытия клика и Enter / Space; локализованный текст
146
+ остаётся у потребителя.
147
+
148
+ ```tsx
149
+ const handleClearClick = (event: React.MouseEvent<HTMLButtonElement>) => {
150
+ event.stopPropagation();
151
+ setPickedDate(null);
152
+ };
153
+
154
+ // Не даём Enter / Space дойти до target: нативная активация кнопки вызовет click.
155
+ const handleClearKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
156
+ if (event.code === "Enter" || event.code === "Space") {
157
+ event.stopPropagation();
158
+ }
159
+ };
160
+
161
+ // postfix передаётся только при выборе: явный postfix={undefined} убрал бы автоматическую стрелку.
162
+ const postfixProps =
163
+ pickedDate !== null
164
+ ? {
165
+ postfix: (
166
+ <ChipClearButton aria-label="Очистить дату" onClick={handleClearClick} onKeyDown={handleClearKeyDown} />
167
+ ),
168
+ }
169
+ : {};
170
+
171
+ <ChipDatePickerTarget selected={pickedDate !== null} onClear={() => setPickedDate(null)} {...postfixProps}>
172
+ {label}
173
+ </ChipDatePickerTarget>;
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Связанные компоненты
179
+
180
+ - [ChipDatePicker](./ChipDatePicker-ai.md) — готовый родитель: вычисляет `selected`
181
+ и подпись, передаёт `onClear`, рендерит target внутри `DatePickerExtended`.
182
+ - [Chip](./Chip-ai.md) — рендерится внутри target, источник унаследованных props,
183
+ визуальных состояний и span-семантики.
184
+ - [DatePickerExtended](../DatePickerExtended/DatePickerExtended-ai.md) — владеет
185
+ календарём и контекстом открытости; публичная точка композиции — `renderTarget`.
186
+ - `ChipClearButton` — встроенный postfix для `selected`; отдельная публичная
187
+ кнопка принимает `aria-label` и остальные props `ButtonIcon`.
188
+ - `ChipDropdownArrow` — встроенный postfix без выбора; `rotated` повторяет
189
+ открытость контекста.
190
+
191
+ ---
192
+
193
+ ## Stories
194
+
195
+ Основные истории: `stories/Chips/ChipDatePicker.stories.tsx`
196
+ Файлы примеров: `stories/Chips/examples/ChipDatePicker/`
197
+
198
+ Используются существующие истории родителя: `ChipDatePicker` рендерит этот target.
199
+ Отдельный stories-файл атому не требуется. Примеры ручной композиции через
200
+ `renderTarget` приведены выше в этом документе.
201
+
202
+ | Story | Example file | Что демонстрирует |
203
+ |---|---|---|
204
+ | `Playground` | `PlaygroundExample.tsx` | Target с контролами type, size, disabled; выбор даты включает `selected` и кнопку очистки |
205
+ | `Types` | `TypesExample.tsx` | TYPE_1 / TYPE_2 target без выбора, со стрелкой |
206
+ | `Sizes` | `SizesExample.tsx` | SM / MD / LG target без выбора, со стрелкой |
207
+ | `VisualTests` | `VisualTestsExample.tsx` | Selected target трёх размеров с кнопкой очистки; play раскрывает календарь последнего |
208
+
209
+ Состояния `disabled`, hover, focus и prefix/postfix-слоты отрисовывает `Chip`;
210
+ они покрыты stories `stories/Chips/Chip.stories.tsx`.
211
+
212
+ Контракт target покрывает `src/components/Chip/__tests__/ChipDatePickerTarget.test.tsx`;
213
+ календарный выбор и связь с датой — существующие тесты `ChipDatePicker` и
214
+ `DatePickerExtended`. Ограничения встроенной очистки и disabled не закрепляются
215
+ новыми тестами как желаемое поведение.
216
+
217
+ ---
218
+
219
+ ## История изменений
220
+
221
+ | Дата | Изменение |
222
+ |---|---|
223
+ | 2026-10-21 | Создан документ; добавлены JSDoc и focused тесты target без изменения API и поведения |
224
+
225
+ ---
226
+
227
+ ## Примеры использования
228
+
229
+ ### Types
230
+
231
+ `stories/Chips/examples/ChipDatePicker/TypesExample.tsx`
232
+
233
+ ```tsx
234
+ import React, { useState } from "react";
235
+ import { ChipDatePicker, EChipType, EDropdownAlignment } from "@sberbusiness/triplex-next";
236
+
237
+ type TypeItemProps = {
238
+ type: EChipType;
239
+ label: string;
240
+ };
241
+
242
+ const TypeItem = ({ type, label }: TypeItemProps) => {
243
+ const [value, setValue] = useState("");
244
+
245
+ return (
246
+ <div>
247
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{label}</div>
248
+ <ChipDatePicker
249
+ value={value}
250
+ label="Date label"
251
+ type={type}
252
+ alignment={EDropdownAlignment.LEFT}
253
+ onChange={setValue}
254
+ />
255
+ </div>
256
+ );
257
+ };
258
+
259
+ const typeOptions = Object.values(EChipType).map((type) => ({
260
+ value: type,
261
+ label: type.toUpperCase(),
262
+ }));
263
+
264
+ export const TypesExample = () => (
265
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
266
+ {typeOptions.map(({ value, label }) => (
267
+ <TypeItem key={value} type={value} label={label} />
268
+ ))}
269
+ </div>
270
+ );
271
+ ```
272
+
273
+ ### Sizes
274
+
275
+ `stories/Chips/examples/ChipDatePicker/SizesExample.tsx`
276
+
277
+ ```tsx
278
+ import React, { useState } from "react";
279
+ import { ChipDatePicker, EComponentSize, EDropdownAlignment } from "@sberbusiness/triplex-next";
280
+
281
+ type SizeItemProps = {
282
+ size: EComponentSize;
283
+ label: string;
284
+ };
285
+
286
+ const SizeItem = ({ size, label }: SizeItemProps) => {
287
+ const [value, setValue] = useState("");
288
+
289
+ return (
290
+ <div>
291
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{label}</div>
292
+ <ChipDatePicker
293
+ size={size}
294
+ alignment={EDropdownAlignment.LEFT}
295
+ value={value}
296
+ label="Date label"
297
+ onChange={setValue}
298
+ />
299
+ </div>
300
+ );
301
+ };
302
+
303
+ const sizeOptions = Object.values(EComponentSize).map((size) => ({
304
+ value: size,
305
+ label: size.toUpperCase(),
306
+ }));
307
+
308
+ export const SizesExample = () => (
309
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
310
+ {sizeOptions.map(({ value, label }) => (
311
+ <SizeItem key={value} size={value} label={label} />
312
+ ))}
313
+ </div>
314
+ );
315
+ ```
316
+