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

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 (77) hide show
  1. package/bundle/components/Amount.md +2 -1
  2. package/bundle/components/Badge.md +2 -1
  3. package/bundle/components/BodyPage.md +2 -1
  4. package/bundle/components/Button.md +5 -1
  5. package/bundle/components/ButtonDropdownExtended.md +3 -1
  6. package/bundle/components/ButtonIcon.md +3 -1
  7. package/bundle/components/Calendar.md +3 -1
  8. package/bundle/components/CardAction.md +1 -0
  9. package/bundle/components/CheckboxXGroup.md +2 -1
  10. package/bundle/components/Chip.md +2 -1
  11. package/bundle/components/ChipMonthYearPicker.md +2 -1
  12. package/bundle/components/ChipMultiselect.md +4 -1
  13. package/bundle/components/ChipOptions.md +2 -1
  14. package/bundle/components/ChipSort.md +4 -1
  15. package/bundle/components/CollapsibleTree.md +2 -1
  16. package/bundle/components/ComposedKeyDownListener.md +4 -3
  17. package/bundle/components/DateField.md +7 -1
  18. package/bundle/components/Divider.md +85 -138
  19. package/bundle/components/DocumentNumberEdit.md +173 -214
  20. package/bundle/components/Dropdown.md +11 -1
  21. package/bundle/components/Ellipsis.md +131 -147
  22. package/bundle/components/FooterPage.md +3 -1
  23. package/bundle/components/FormField.md +2 -1
  24. package/bundle/components/Gap.md +1 -1
  25. package/bundle/components/Header.md +1 -0
  26. package/bundle/components/HeaderPage.md +3 -1
  27. package/bundle/components/HelpBox.md +2 -1
  28. package/bundle/components/IconWrapper.md +10 -6
  29. package/bundle/components/ImageGallery.md +2 -1
  30. package/bundle/components/ImageGalleryExtended.md +2 -1
  31. package/bundle/components/IslandAccordion.md +6 -1
  32. package/bundle/components/KeyDownListener.md +3 -2
  33. package/bundle/components/LightBox.md +7 -1
  34. package/bundle/components/List.md +2 -1
  35. package/bundle/components/ListActionItem.md +2 -1
  36. package/bundle/components/ListItem.md +3 -1
  37. package/bundle/components/ListItemControlsButton.md +2 -1
  38. package/bundle/components/ListItemSelectable.md +2 -1
  39. package/bundle/components/ListMasterFooter.md +2 -1
  40. package/bundle/components/ListMasterHeader.md +2 -1
  41. package/bundle/components/ListSortable.md +2 -1
  42. package/bundle/components/ListSortableItem.md +2 -1
  43. package/bundle/components/ListTableItem.md +4 -1
  44. package/bundle/components/LoaderMiddle.md +5 -1
  45. package/bundle/components/LoaderScreen.md +7 -1
  46. package/bundle/components/LoaderSmall.md +10 -4
  47. package/bundle/components/MaskedField.md +3 -1
  48. package/bundle/components/MediaWidth.md +2 -1
  49. package/bundle/components/MobileView.md +2 -1
  50. package/bundle/components/ModalWindow.md +4 -1
  51. package/bundle/components/MonthYearField.md +4 -1
  52. package/bundle/components/Notification.md +1 -0
  53. package/bundle/components/Overlay.md +7 -2
  54. package/bundle/components/Pagination.md +1 -7
  55. package/bundle/components/Radio.md +238 -115
  56. package/bundle/components/RadioXGroup.md +259 -0
  57. package/bundle/components/RadioYGroup.md +266 -0
  58. package/bundle/components/SegmentedControl.md +505 -158
  59. package/bundle/components/SelectExtendedField.md +2 -1
  60. package/bundle/components/SelectField.md +4 -1
  61. package/bundle/components/Skeleton.md +140 -69
  62. package/bundle/components/Spoiler.md +245 -63
  63. package/bundle/components/Step.md +257 -68
  64. package/bundle/components/SuggestField.md +30 -18
  65. package/bundle/components/Tabs.md +2 -1
  66. package/bundle/components/TabsLine.md +2 -1
  67. package/bundle/components/TextField.md +8 -4
  68. package/bundle/components/TextareaField.md +2 -1
  69. package/bundle/components/ThemeProvider.md +2 -1
  70. package/bundle/components/Tooltip.md +6 -3
  71. package/bundle/guides/context.md +4 -1
  72. package/bundle/manifest.json +32 -10
  73. package/bundle/release-notes/1.49.0.mdx +78 -0
  74. package/bundle/release-notes/1.50.0.mdx +35 -0
  75. package/bundle/release-notes/1.51.0.mdx +7 -0
  76. package/bundle/tokens.json +161 -11
  77. package/package.json +1 -1
@@ -0,0 +1,259 @@
1
+ ---
2
+ component: RadioXGroup
3
+ category: Inputs
4
+ related: [Radio, RadioYGroup]
5
+ tokens: []
6
+ stories: stories/RadioXGroup/RadioXGroup.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # RadioXGroup
11
+
12
+ ## Назначение
13
+
14
+ Контейнер для горизонтального расположения связанных `Radio` с переносом на следующую строку и настраиваемым отступом между вариантами. Сам контейнер не хранит выбранное значение и не управляет дочерними радио-кнопками.
15
+
16
+ Используй когда: варианты одного выбора нужно разместить в строку с переносами.
17
+ Не используй когда: варианты должны идти вертикально — используй `RadioYGroup`.
18
+
19
+ ---
20
+
21
+ ## Варианты и props
22
+
23
+ ### Обязательные props
24
+
25
+ Обязательных custom-props нет. Для содержательной группы передай дочерние `Radio` и доступное имя группы.
26
+
27
+ ### Опциональные props
28
+
29
+ | Prop | Тип | По умолчанию | Описание |
30
+ |---|---|---|---|
31
+ | `indent` | `TIndentSize` | `12` | Горизонтальный отступ между Radio в пикселях: `12`, `16`, `20`, `24`, `28`, `32`. |
32
+ | `children` | `React.ReactNode` | — | Содержимое группы, обычно непосредственные дочерние `Radio`. |
33
+ | `className`, `...rest` | `React.HTMLAttributes<HTMLDivElement>` | — | Пользовательский класс, HTML-атрибуты, ARIA-атрибуты и обработчики корневого `div`. |
34
+
35
+ ### Ограничения использования
36
+
37
+ - Размер, выбранное и отключённое состояния задаются каждому `Radio`: у группы нет собственных `size`, `checked`, `disabled` или `onChange` для выбранного значения.
38
+ - Все `Radio` одного выбора должны иметь общий `name`. Разные группы должны использовать разные `name`: роль `radiogroup` сама по себе не связывает нативные input.
39
+ - Группа использует `inline-flex` и `flex-flow: row wrap`. Ширину и внешние отступы определяет окружающая разметка; отдельного вертикального зазора между строками нет.
40
+ - `indent` задаёт отрицательные горизонтальные маргины контейнера и положительные маргины по половине отступа у потомков с классом `.label` из `Radio`. Это не универсальный `gap`: для произвольных children без этого класса внутренние маргины не появятся, а отрицательные маргины контейнера останутся.
41
+ - `onChange`, унаследованный от HTML-атрибутов, получает всплывающий `React.FormEvent<HTMLDivElement>` от дочернего input. Значение читается из input-источника события; собственного callback-контракта выбора у группы нет.
42
+
43
+ ---
44
+
45
+ ## Дизайн-токены
46
+
47
+ Собственных дизайн-токенов нет: стили `RadioXGroup` задают только раскладку и отступы. Цвета и состояния дочерних радио-кнопок определяются компонентом `Radio`.
48
+
49
+ ---
50
+
51
+ ## Инварианты
52
+
53
+ - `forwardRef` обязателен; ref указывает на корневой `HTMLDivElement`.
54
+ - Корневой DOM-элемент — `div`, роль по умолчанию — `radiogroup`.
55
+ - `IRadioXGroupProps`, `indent`, значения `TIndentSize`, дефолт `12` и публичные barrel-экспорты сохраняются.
56
+ - Порядок `role="radiogroup"` перед `...rest` сохраняет существующий контракт: переданный `role` может переопределить роль по умолчанию.
57
+ - `className` объединяется через `clsx`, остальные HTML-атрибуты приходят на корневой элемент, `indent` в DOM не передаётся.
58
+ - LESS-классы `radioXGroup` и `indent-{n}`, геометрия маргинов и связь с `.label` из `Radio` должны сохраняться при рефакторинге.
59
+ - `displayName` — `RadioXGroup`. Компонент не добавляет state, контекст или клавиатурные обработчики.
60
+
61
+ ---
62
+
63
+ ## Accessibility
64
+
65
+ - Доступное имя группы задаёт потребитель через `aria-label` или `aria-labelledby` со ссылкой на существующий заголовок.
66
+ - По умолчанию `role="radiogroup"` обозначает группу радио-кнопок; при переопределении `role` ответственность за семантику остаётся у потребителя.
67
+ - `Radio` внутри группы сохраняют нативную семантику `input type="radio"`. Общий `name` обеспечивает единственный выбор и нативную клавиатурную навигацию между вариантами.
68
+ - Подписи и `disabled` передаются дочерним `Radio`. Контейнер не перемещает фокус и по умолчанию не добавляет `tabIndex`.
69
+
70
+ ---
71
+
72
+ ## Связанные компоненты
73
+
74
+ - `Radio` — часть семейства, рендерится потребителем внутри группы; его корневой `.label` участвует в горизонтальных отступах.
75
+ - `RadioYGroup` — альтернативная компоновка того же набора радио-кнопок по вертикали.
76
+
77
+ ---
78
+
79
+ ## Stories
80
+
81
+ Основные истории: `stories/RadioXGroup/RadioXGroup.stories.tsx`
82
+ Файлы примеров: `stories/RadioXGroup/examples/`
83
+
84
+ | Story | Example file | Что демонстрирует |
85
+ |---|---|---|
86
+ | `Playground` | `Playground.tsx` | Controls для `indent` и настройки размера/disabled дочерних Radio; исключена из скриншот-тестов. |
87
+ | `Default` | `Default.tsx` | Группа с дефолтным отступом, общим `name` и доступным именем. |
88
+ | `Indents` | `Indents.tsx` | Все шесть значений горизонтального отступа. |
89
+ | `Sizes` | `Sizes.tsx` | Дочерние Radio размеров SM, MD и LG. |
90
+ | `States` | `States.tsx` | Controlled-выбор через `checked` и `onChange`; выбранный и невыбранный отключённые Radio. |
91
+ | `VisualTests` | `VisualTests.tsx` | Клавиатурный focus через `play`, CSS hover через реальную мышь test-runner (`parameters.testRunner.hoverSelector`); скрыта из autodocs. |
92
+
93
+ Legacy stories `stories/Radio.stories.tsx` и их ID сохраняются; новый набор имеет собственный title `Components/RadioXGroup`.
94
+
95
+ ---
96
+
97
+ ## История изменений
98
+
99
+ | Дата | Изменение |
100
+ |---|---|
101
+ | 2026-10-07 | Создан документ для TRI-69: добавлен forwardRef на корневой div, уточнён JSDoc; контракты indent, HTML-атрибутов и ref покрыты unit-тестами, добавлены современные stories. |
102
+ | 2026-10-07 | Исправлено визуальное покрытие CSS hover: test-runner перемещает реальную мышь по opt-in селектору и возвращает её после снимка. |
103
+ | 2026-10-07 | По замечаниям ревью удалены история Wrapping и пример пустой группы из VisualTests. |
104
+ | 2026-10-08 | Story `RadioSizes` переименована в `Sizes`; подписи вариантов приведены к общему формату, States разбита на подписанные секции Selected и Disabled, VisualTests скрыта из сайдбара (`!dev`). |
105
+
106
+ ---
107
+
108
+ ## Примеры использования
109
+
110
+ ### Default
111
+
112
+ `stories/RadioXGroup/examples/Default.tsx`
113
+
114
+ ```tsx
115
+ import React from "react";
116
+ import { Radio, RadioXGroup } from "@sberbusiness/triplex-next";
117
+
118
+ export const Default = () => {
119
+ const name = React.useId();
120
+
121
+ return (
122
+ <RadioXGroup aria-label="Способ доставки">
123
+ <Radio name={name} value="courier" defaultChecked>
124
+ Radio text
125
+ </Radio>
126
+ <Radio name={name} value="pickup">
127
+ Radio text
128
+ </Radio>
129
+ <Radio name={name} value="post">
130
+ Radio text
131
+ </Radio>
132
+ </RadioXGroup>
133
+ );
134
+ };
135
+ ```
136
+
137
+ ### Indents
138
+
139
+ `stories/RadioXGroup/examples/Indents.tsx`
140
+
141
+ ```tsx
142
+ import React from "react";
143
+ import { Radio, RadioXGroup, TIndentSize } from "@sberbusiness/triplex-next";
144
+
145
+ const INDENTS = [12, 16, 20, 24, 28, 32] satisfies TIndentSize[];
146
+
147
+ export const Indents = () => {
148
+ const name = React.useId();
149
+
150
+ return (
151
+ <div style={{ display: "flex", flexDirection: "column", gap: 24, width: 480, maxWidth: "100%" }}>
152
+ {INDENTS.map((indent) => (
153
+ <div key={indent}>
154
+ <div style={{ marginBottom: 8, fontWeight: 700 }}>indent = {indent}</div>
155
+ <RadioXGroup indent={indent} aria-label={`Способ доставки, отступ ${indent}`}>
156
+ <Radio name={`${name}-${indent}`} value="courier" defaultChecked>
157
+ Radio text
158
+ </Radio>
159
+ <Radio name={`${name}-${indent}`} value="pickup">
160
+ Radio text
161
+ </Radio>
162
+ <Radio name={`${name}-${indent}`} value="post">
163
+ Radio text
164
+ </Radio>
165
+ </RadioXGroup>
166
+ </div>
167
+ ))}
168
+ </div>
169
+ );
170
+ };
171
+ ```
172
+
173
+ ### Sizes
174
+
175
+ `stories/RadioXGroup/examples/Sizes.tsx`
176
+
177
+ ```tsx
178
+ import React from "react";
179
+ import { Radio, RadioXGroup, EComponentSize } from "@sberbusiness/triplex-next";
180
+
181
+ const SIZES = [EComponentSize.SM, EComponentSize.MD, EComponentSize.LG];
182
+
183
+ export const Sizes = () => {
184
+ const name = React.useId();
185
+
186
+ return (
187
+ <div style={{ display: "flex", flexDirection: "column", gap: 24, width: 480, maxWidth: "100%" }}>
188
+ {SIZES.map((size) => (
189
+ <div key={size}>
190
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{size.toUpperCase()}</div>
191
+ <RadioXGroup aria-label={`Способ доставки, размер Radio ${size}`}>
192
+ <Radio name={`${name}-${size}`} value="courier" size={size} defaultChecked>
193
+ Radio text
194
+ </Radio>
195
+ <Radio name={`${name}-${size}`} value="pickup" size={size}>
196
+ Radio text
197
+ </Radio>
198
+ <Radio name={`${name}-${size}`} value="post" size={size}>
199
+ Radio text
200
+ </Radio>
201
+ </RadioXGroup>
202
+ </div>
203
+ ))}
204
+ </div>
205
+ );
206
+ };
207
+ ```
208
+
209
+ ### States
210
+
211
+ `stories/RadioXGroup/examples/States.tsx`
212
+
213
+ ```tsx
214
+ import React from "react";
215
+ import { Radio, RadioXGroup } from "@sberbusiness/triplex-next";
216
+
217
+ export const States = () => {
218
+ const name = React.useId();
219
+ const [value, setValue] = React.useState("second");
220
+
221
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
222
+
223
+ return (
224
+ <div style={{ display: "flex", flexDirection: "column", gap: 24, width: 480, maxWidth: "100%" }}>
225
+ <div>
226
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>Selected</div>
227
+ <RadioXGroup aria-label="Выбранный вариант">
228
+ <Radio name={`${name}-selected`} value="first" checked={value === "first"} onChange={handleChange}>
229
+ Radio text
230
+ </Radio>
231
+ <Radio
232
+ name={`${name}-selected`}
233
+ value="second"
234
+ checked={value === "second"}
235
+ onChange={handleChange}
236
+ >
237
+ Radio text
238
+ </Radio>
239
+ <Radio name={`${name}-selected`} value="third" checked={value === "third"} onChange={handleChange}>
240
+ Radio text
241
+ </Radio>
242
+ </RadioXGroup>
243
+ </div>
244
+ <div>
245
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>Disabled</div>
246
+ <RadioXGroup aria-label="Отключённые варианты">
247
+ <Radio name={`${name}-disabled`} value="checked" disabled defaultChecked>
248
+ Radio text
249
+ </Radio>
250
+ <Radio name={`${name}-disabled`} value="unchecked" disabled>
251
+ Radio text
252
+ </Radio>
253
+ </RadioXGroup>
254
+ </div>
255
+ </div>
256
+ );
257
+ };
258
+ ```
259
+
@@ -0,0 +1,266 @@
1
+ ---
2
+ component: RadioYGroup
3
+ category: Inputs
4
+ related: [Radio, RadioXGroup]
5
+ tokens: []
6
+ stories: stories/RadioYGroup/RadioYGroup.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # RadioYGroup
11
+
12
+ ## Назначение
13
+
14
+ Вертикальный контейнер для связанных радио-кнопок с ролью `radiogroup` по умолчанию.
15
+ Компонент задаёт раскладку и семантику группы; выбор остаётся на уровне вложенных
16
+ `Radio` и приложения.
17
+
18
+ Используй когда: нужно разместить варианты одного выбора друг под другом.
19
+ Не используй когда: варианты должны идти в строку — используй `RadioXGroup`;
20
+ для независимых множественных вариантов подходит семейство `Checkbox`.
21
+
22
+ ---
23
+
24
+ ## Варианты и props
25
+
26
+ ### Обязательные props
27
+
28
+ Обязательных props нет.
29
+
30
+ ### Опциональные props
31
+
32
+ | Prop | Тип | По умолчанию | Описание |
33
+ |---|---|---|---|
34
+ | `children` | `React.ReactNode` | — | Обычно несколько `Radio` с общим `name` и разными `value` |
35
+ | `className` | `string` | — | Добавляется к классу корневого контейнера через `clsx` |
36
+ | `role` | `React.AriaRole` | `radiogroup` | Стандартный HTML-prop; позволяет переопределить роль |
37
+ | `aria-label` / `aria-labelledby` | HTML/ARIA-атрибуты | — | Доступное имя группы задаёт потребитель |
38
+ | `...divAttributes` | `React.HTMLAttributes<HTMLDivElement>` | — | Остальные атрибуты и обработчики событий корневого `<div>` |
39
+
40
+ ### Ограничения использования
41
+
42
+ - Собственных `size`, `checked`, `defaultChecked`, `disabled`, `name` и `value`
43
+ у группы нет: их передают каждому дочернему `Radio`. Группа не клонирует children
44
+ и не передаёт им props через контекст.
45
+ - Одинаковый `name` связывает нативные радио-кнопки в один выбор. Независимым
46
+ наборам в одной форме нужны разные `name`; сами контейнеры их не изолируют.
47
+ - В controlled-режиме приложение хранит выбранное значение, передаёт `checked`
48
+ каждому `Radio` и обновляет значение через его `onChange`. В uncontrolled-режиме
49
+ начальный выбор задаётся `defaultChecked` одного `Radio`.
50
+ - Раскладка корня — `display: inline-flex` и `flex-flow: column wrap`. Ширина
51
+ и внешние отступы не задаются.
52
+ - Смежные `Radio` одного размера получают вертикальный отступ: SM — 8px,
53
+ MD — 16px, LG — 20px. Правила `.label.sm + .label.sm`, `.label.md + .label.md`
54
+ и `.label.lg + .label.lg` из `styles/RadioYGroup.module.less` используют общие
55
+ классы семейства `Radio`: `scripts/generate-scoped-name.ts` формирует имя класса
56
+ из семейства, локального имени и версии библиотеки. Между соседями разных размеров
57
+ и между произвольными children эти отступы не назначаются; отдельная обёртка
58
+ вокруг каждого `Radio` разрывает соседство `label`-элементов.
59
+ - `aria-disabled` на контейнере не отключает дочерние контролы: для блокировки
60
+ взаимодействия нужен `disabled` у каждого `Radio`.
61
+
62
+ ---
63
+
64
+ ## Дизайн-токены
65
+
66
+ Собственных дизайн-токенов у `RadioYGroup` нет: его LESS задаёт только раскладку.
67
+ Цвета, hover, focus и disabled вложенных радио-кнопок используют токены группы
68
+ `Radio` из `src/components/DesignTokens/components/Radio.ts`; их переопределяют
69
+ через `ThemeProvider` по общим правилам темизации.
70
+
71
+ ---
72
+
73
+ ## Инварианты
74
+
75
+ - `forwardRef<HTMLDivElement>` обязателен; объектный и callback ref указывают
76
+ на корневой `<div>`, а при размонтировании callback получает `null`.
77
+ - `className`, `ref` и HTML-атрибуты относятся к одному корневому `<div>`.
78
+ - Роль по умолчанию — `radiogroup`; `{...rest}` идёт после роли, поэтому переданный
79
+ `role` её переопределяет. Не фиксировать роль и не исключать `role` из интерфейса
80
+ без согласования изменения публичного поведения.
81
+ - `RadioYGroup` и `IRadioYGroupProps` экспортируются через
82
+ `src/components/Radio/index.ts`; `displayName` — `RadioYGroup`.
83
+ - Селекторы отступов связаны с классами `label`, `sm`, `md`, `lg` из
84
+ `Radio.module.less` через общий генератор имён в Vite и Storybook. Учитывать эту
85
+ связь при изменении классов, расположения модулей или генератора.
86
+ - Компонент не хранит выбор, не управляет фокусом и не перехватывает клавиатуру.
87
+ - Story IDs `components-radioygroup--*` связаны с visual baselines;
88
+ legacy IDs из `stories/Radio.stories.tsx` также сохраняются.
89
+
90
+ ---
91
+
92
+ ## Accessibility
93
+
94
+ - `role="radiogroup"` описывает набор вариантов одного выбора. Потребитель
95
+ передаёт `aria-label` либо `aria-labelledby`, ссылающийся на существующую
96
+ подпись группы. Текст внутри компонента не задаётся.
97
+ - Каждый `Radio` остаётся нативным `<input type="radio">` внутри `<label>`;
98
+ его children задают подпись конкретного варианта. Для варианта без текста
99
+ потребитель должен передать доступное имя самому `Radio`.
100
+ - Клавиатура и выбор работают через нативные radio inputs с общим `name`.
101
+ Контейнер не реализует отдельную стрелочную навигацию и не переносит фокус.
102
+ - Корневой `<div>` по умолчанию не фокусируется. `ref` не вызывает фокусировку;
103
+ потребитель может передать `tabIndex`, если сценарий требует фокуса контейнера.
104
+ - Disabled и `:focus-visible` отображаются на дочернем `Radio`.
105
+
106
+ ---
107
+
108
+ ## Связанные компоненты
109
+
110
+ - `Radio` — базовый элемент семейства; задаёт размер, значение, выбор,
111
+ disabled и обработчики отдельных вариантов.
112
+ - `RadioXGroup` — альтернативная горизонтальная раскладка с собственным `indent`.
113
+
114
+ ---
115
+
116
+ ## Stories
117
+
118
+ Основные истории: `stories/RadioYGroup/RadioYGroup.stories.tsx`
119
+ Файлы примеров: `stories/RadioYGroup/examples/`
120
+
121
+ | Story | Example file | Что демонстрирует |
122
+ |---|---|---|
123
+ | `Default` | `Default.tsx` | Минимальная группа с доступным именем и общим `name` дочерних Radio |
124
+ | `Sizes` | `Sizes.tsx` | Размеры SM / MD / LG на дочерних Radio, выбранные и невыбранные варианты |
125
+ | `States` | `States.tsx` | Controlled-выбор через `checked` и `onChange`; выбранный и невыбранный disabled-варианты |
126
+ | `VisualTests` | `VisualTests.tsx` | Фокус с клавиатуры и hover невыбранного варианта |
127
+ | `VisualTestsCheckedHover` | — | Фокус выбранного варианта и hover выбранного варианта, тот же renderer |
128
+
129
+ Playground не создаётся: у группы нет собственных настраиваемых props.
130
+ Обе VisualTests-истории скрыты из меню и autodocs тегами `!dev` и `!autodocs`.
131
+ Они используют `play`; настоящий CSS hover перед снимком
132
+ устанавливает test-runner через opt-in параметр `visualTests.hoverTarget`.
133
+ Baseline-файлы создаются только CI/Docker на viewport xs и xl.
134
+
135
+ ---
136
+
137
+ ## История изменений
138
+
139
+ | Дата | Изменение |
140
+ |---|---|
141
+ | 2026-10-05 | Создан документ (TRI-70): добавлен forwardRef на корневой div, описаны accessibility и HTML-контракты, unit-тесты и modern stories |
142
+ | 2026-10-05 | Уточнены отступы между смежными Radio одного размера и связь CSS-классов внутри семейства через общий генератор имён |
143
+ | 2026-10-05 | VisualTests-истории скрыты из меню Storybook, пример Disabled упрощён до размера MD |
144
+ | 2026-10-08 | Stories `Selected` и `Disabled` объединены в `States` с подписанными секциями |
145
+
146
+ ---
147
+
148
+ ## Примеры использования
149
+
150
+ ### Default
151
+
152
+ `stories/RadioYGroup/examples/Default.tsx`
153
+
154
+ ```tsx
155
+ import React, { useState } from "react";
156
+ import { uniqueId } from "lodash-es";
157
+ import { Radio, RadioYGroup } from "@sberbusiness/triplex-next";
158
+
159
+ export const Default = () => {
160
+ const [name] = useState(() => uniqueId("radio-y-group-default-"));
161
+
162
+ return (
163
+ <RadioYGroup aria-label="Выберите вариант">
164
+ <Radio name={name} value="first">
165
+ Radio text
166
+ </Radio>
167
+ <Radio name={name} value="second">
168
+ Radio text
169
+ </Radio>
170
+ <Radio name={name} value="third">
171
+ Radio text
172
+ </Radio>
173
+ </RadioYGroup>
174
+ );
175
+ };
176
+ ```
177
+
178
+ ### Sizes
179
+
180
+ `stories/RadioYGroup/examples/Sizes.tsx`
181
+
182
+ ```tsx
183
+ import React, { useState } from "react";
184
+ import { uniqueId } from "lodash-es";
185
+ import { EComponentSize, Radio, RadioYGroup } from "@sberbusiness/triplex-next";
186
+
187
+ const SIZES = [EComponentSize.SM, EComponentSize.MD, EComponentSize.LG];
188
+
189
+ export const Sizes = () => {
190
+ const [name] = useState(() => uniqueId("radio-y-group-sizes-"));
191
+
192
+ return (
193
+ <div style={{ display: "flex", alignItems: "flex-start", flexWrap: "wrap", gap: 32 }}>
194
+ {SIZES.map((size) => (
195
+ <div key={size} style={{ width: 180 }}>
196
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{size.toUpperCase()}</div>
197
+ <RadioYGroup aria-label={`Варианты размера ${size.toUpperCase()}`}>
198
+ <Radio name={`${name}-${size}`} value="first" size={size}>
199
+ Radio text
200
+ </Radio>
201
+ <Radio name={`${name}-${size}`} value="second" size={size} defaultChecked>
202
+ Radio text
203
+ </Radio>
204
+ <Radio name={`${name}-${size}`} value="third" size={size}>
205
+ Radio text
206
+ </Radio>
207
+ </RadioYGroup>
208
+ </div>
209
+ ))}
210
+ </div>
211
+ );
212
+ };
213
+ ```
214
+
215
+ ### States
216
+
217
+ `stories/RadioYGroup/examples/States.tsx`
218
+
219
+ ```tsx
220
+ import React, { useState } from "react";
221
+ import { uniqueId } from "lodash-es";
222
+ import { Radio, RadioYGroup } from "@sberbusiness/triplex-next";
223
+
224
+ export const States = () => {
225
+ const [name] = useState(() => uniqueId("radio-y-group-states-"));
226
+ const [value, setValue] = useState("second");
227
+
228
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
229
+
230
+ return (
231
+ <div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
232
+ <div>
233
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>Selected</div>
234
+ <RadioYGroup aria-label="Выбранный вариант">
235
+ <Radio name={`${name}-selected`} value="first" checked={value === "first"} onChange={handleChange}>
236
+ Radio text
237
+ </Radio>
238
+ <Radio
239
+ name={`${name}-selected`}
240
+ value="second"
241
+ checked={value === "second"}
242
+ onChange={handleChange}
243
+ >
244
+ Radio text
245
+ </Radio>
246
+ <Radio name={`${name}-selected`} value="third" checked={value === "third"} onChange={handleChange}>
247
+ Radio text
248
+ </Radio>
249
+ </RadioYGroup>
250
+ </div>
251
+ <div>
252
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>Disabled</div>
253
+ <RadioYGroup aria-label="Отключённые варианты">
254
+ <Radio name={`${name}-disabled`} value="first" disabled>
255
+ Radio text
256
+ </Radio>
257
+ <Radio name={`${name}-disabled`} value="second" disabled defaultChecked>
258
+ Radio text
259
+ </Radio>
260
+ </RadioYGroup>
261
+ </div>
262
+ </div>
263
+ );
264
+ };
265
+ ```
266
+