@sberbusiness/triplex-next-mcp-server 1.46.0-beta → 1.48.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 (48) hide show
  1. package/README.md +7 -7
  2. package/bundle/components/AmountField.md +222 -323
  3. package/bundle/components/Avatar.md +138 -146
  4. package/bundle/components/CardStatic.md +402 -0
  5. package/bundle/components/CheckboxTree.md +157 -215
  6. package/bundle/components/CheckboxTreeExtended.md +7 -7
  7. package/bundle/components/ChipGroup.md +1 -1
  8. package/bundle/components/ChipMonthYearPicker.md +4 -4
  9. package/bundle/components/ChipSuggest.md +7 -6
  10. package/bundle/components/CollapsibleTree.md +8 -4
  11. package/bundle/components/CollapsibleTreeExtended.md +8 -6
  12. package/bundle/components/Confirm.md +346 -281
  13. package/bundle/components/DateRange.md +351 -210
  14. package/bundle/components/FooterPage.md +1 -0
  15. package/bundle/components/FormField.md +11 -4
  16. package/bundle/components/FormGroup.md +3 -2
  17. package/bundle/components/LightBox.md +8 -0
  18. package/bundle/components/ListMaster.md +2 -2
  19. package/bundle/components/ListTableItem.md +6 -6
  20. package/bundle/components/MonthYearField.md +15 -4
  21. package/bundle/components/Slider.md +389 -97
  22. package/bundle/components/SliderRange.md +486 -105
  23. package/bundle/components/StatusTracker.md +386 -94
  24. package/bundle/components/Stepper.md +355 -102
  25. package/bundle/components/StepperExtended.md +633 -0
  26. package/bundle/components/SuggestField.md +1049 -96
  27. package/bundle/components/SwipeableArea.md +7 -7
  28. package/bundle/components/Tabs.md +265 -92
  29. package/bundle/components/TabsExtended.md +18 -18
  30. package/bundle/components/TabsLine.md +301 -127
  31. package/bundle/components/TagColor.md +187 -66
  32. package/bundle/components/TagGroup.md +184 -48
  33. package/bundle/components/TextareaField.md +278 -70
  34. package/bundle/components/TopOverlay.md +17 -1
  35. package/bundle/components/TreeView.md +16 -7
  36. package/bundle/components/TriggerClickOnKeyDownEvent.md +277 -0
  37. package/bundle/components/UploadZone.md +318 -0
  38. package/bundle/guides/codestyle.md +16 -1
  39. package/bundle/guides/commits.md +47 -1
  40. package/bundle/guides/tests.md +23 -2
  41. package/bundle/manifest.json +48 -21
  42. package/bundle/release-notes/1.47.0.mdx +115 -0
  43. package/bundle/release-notes/1.48.0.mdx +68 -0
  44. package/bundle/release-notes/1.49.0.mdx +7 -0
  45. package/bundle/tokens.json +3 -3
  46. package/dist/index.js +220 -6
  47. package/dist/index.js.map +1 -1
  48. package/package.json +1 -1
@@ -1,10 +1,14 @@
1
1
  ---
2
2
  component: TagColor
3
- category: Data Display
4
- figma-node: ""
5
- figma-file: ""
6
- related: [Tag, TagGroup]
7
- tokens: []
3
+ category: Tag
4
+ related: [Tag, MarkerStatus]
5
+ tokens:
6
+ - TagColor.Background_Default
7
+ - TagColor.Background_Error
8
+ - TagColor.Background_Info
9
+ - TagColor.Background_Success
10
+ - TagColor.Background_Warning
11
+ - TagColor.Text_Color_Default
8
12
  stories: stories/TagColor/TagColor.stories.tsx
9
13
  version: "1.0"
10
14
  ---
@@ -13,104 +17,140 @@ version: "1.0"
13
17
 
14
18
  ## Назначение
15
19
 
16
- Цветной маркировочный тег: `<span>` с фоном/обводкой по статусу
17
- (`DEFAULT`/`SUCCESS`/`INFO`/`WARNING`/`ERROR`). Без интерактивности —
18
- только визуальная классификация (категории, статусы операций, лейблы).
20
+ Неинтерактивная цветная плашка с текстом — метка для маркировки и классификации. Цвет фона
21
+ кодирует статус (`DEFAULT` / `SUCCESS` / `INFO` / `WARNING` / `ERROR`), содержимое произвольное.
22
+ Типичное место — статус заявки в строке таблицы, тип документа в списке, признак записи рядом
23
+ с заголовком.
19
24
 
20
- Используй когда: нужно подсветить состояние/категорию (например, статус
21
- заявки, тип сообщения). Для интерактивного тега с кнопками edit/remove —
22
- `Tag`.
25
+ Используй когда: нужно показать состояние или категорию объекта короткой цветной меткой,
26
+ и пользователь с ней не взаимодействует.
23
27
 
24
- ---
28
+ Не используй когда:
25
29
 
26
- ## Файловая структура
27
-
28
- ```text
29
- src/components/TagColor/
30
- ├── TagColor.tsx # forwardRef<HTMLSpanElement, ITagColorProps>
31
- ├── enums.ts # ETagColorStatus
32
- ├── types.ts # ITagColorProps
33
- ├── styles/TagColor.module.less
34
- ├── __tests__/
35
- └── index.ts
36
- ```
30
+ - Метку нужно снимать или редактировать — возьми `Tag`: у него есть кнопки удаления
31
+ и редактирования, но нет `status`.
32
+ - Статус достаточно показать точкой без текста — возьми `Marker`, а с подписью и описанием —
33
+ `MarkerStatus`.
34
+ - Нужен интерактивный элемент (выбор фильтра, выпадающий список) — это семейство `Chip`.
35
+ `TagColor` рендерит `<span>` без роли, фокуса, обработчиков и клавиатуры.
37
36
 
38
37
  ---
39
38
 
40
- ## Публичный API
39
+ ## Варианты и props
41
40
 
42
- ### `ITagColorProps`
41
+ ### Обязательные props
43
42
 
44
- ```ts
45
- extends HTMLAttributes<HTMLSpanElement>
46
- ```
43
+ | Prop | Тип | Описание |
44
+ |---|---|---|
45
+ | `size` | `EComponentSize` | Размер: SM (высота 16px) / MD (20px) / LG (28px). Задаёт высоту, внутренние отступы, `border-radius` (4 / 4 / 8px) и размер текста (10 / 12 / 14px) |
47
46
 
48
- | Prop | Тип | Default | Описание |
47
+ ### Опциональные props
48
+
49
+ | Prop | Тип | По умолчанию | Описание |
49
50
  |---|---|---|---|
50
- | `size` | `EComponentSize` | — | **Обязателен** — нет default'а. Маппится в CSS-класс через `createSizeToClassNameMap`. |
51
- | `status?` | `ETagColorStatus` | `DEFAULT` | Цветовой статус. |
52
- | `children` | `ReactNode` | — | Содержимое (текст). Оборачивается в `<span class="content">`. |
53
- | `...HTMLAttributes<HTMLSpanElement>` | — | — | На корневой `<span>`. |
54
-
55
- ### `ETagColorStatus`
56
-
57
- ```ts
58
- enum ETagColorStatus {
59
- DEFAULT = "default",
60
- SUCCESS = "success",
61
- INFO = "info",
62
- WARNING = "warning",
63
- ERROR = "error",
64
- }
65
- ```
51
+ | `status` | `ETagColorStatus` | `ETagColorStatus.DEFAULT` | Определяет **только** цвет фона. На размер, типографику и цвет текста не влияет |
52
+ | `children` | `React.ReactNode` | — | Содержимое метки. Рендерится во вложенном `<span>`, длинный текст обрезается многоточием |
53
+
54
+ Остальные props — стандартные атрибуты `span`
55
+ (`ITagColorProps extends React.HTMLAttributes<HTMLSpanElement>`), уходят на корневой элемент
56
+ через `...restProps`.
66
57
 
67
- Маппинг в CSS-классы — `STATUS_TO_CLASS_NAME_MAP` внутри компонента.
58
+ ### Размер и статус независимы
59
+
60
+ Две оси не пересекаются: `size` отвечает за геометрию и типографику, `status` — за один
61
+ `background`. Любая комбинация допустима, поэтому матрицу 3×5 целиком покрывает story
62
+ `VisualTests`, а документационные stories показывают оси по отдельности.
68
63
 
69
64
  ---
70
65
 
71
- ## Структура DOM
66
+ ## Дизайн-токены
67
+
68
+ Переопределяются через `ThemeProvider` (prop `tokens`) — см. `ThemeProvider-ai.md` →
69
+ «Как переопределять токены». Значения по умолчанию — `src/components/DesignTokens/components/TagColor.ts`.
72
70
 
73
- ```html
74
- <span class="tagColor {size} {status} {className}">
75
- <span class="content">{children}</span>
76
- </span>
71
+ ```text
72
+ TagColor.Background_Default
73
+ TagColor.Background_Success
74
+ TagColor.Background_Info
75
+ TagColor.Background_Warning
76
+ TagColor.Background_Error
77
+ TagColor.Text_Color_Default
77
78
  ```
78
79
 
79
- Внешний `<span>` несёт фон/обводку, внутренний — паддинги контента
80
- (вынесено для управления line-height независимо от рамки).
80
+ Пять фоновых токенов — по одному на значение `ETagColorStatus`; добавление статуса означает
81
+ и новый токен. Цвет текста один на все статусы (`Text_Color_Default`, тёмный нейтральный
82
+ в обеих темах): фоны подобраны так, чтобы контраст держался без переключения цвета текста.
83
+
84
+ Размерные значения (высоты 16/20/28px, отступы, `border-radius`, `font-size` / `line-height`)
85
+ заданы литералами в `styles/TagColor.module.less` — они специфичны для компонента.
81
86
 
82
87
  ---
83
88
 
84
89
  ## Инварианты
85
90
 
86
- - **`forwardRef<HTMLSpanElement>`** — не убирать.
87
- - **`size` обязателен** (нет default'а в типе и в компоненте).
88
- - **`status` default = `DEFAULT`** — допускается опускать.
89
- - **Корень — `<span>`**, inline-friendly.
90
- - **Двойной `<span>` обязателен** — внутренний `.content` нужен для корректного отображения паддингов вместе с фоном внешнего span'а; не сокращать.
91
- - **`ETagColorStatus` экспортируется** — часть публичного API; не переименовывать значения.
92
- - **Нет интерактивности** — никаких кнопок, hover-эффектов, click-handler'ов в реализации. Если нужна интерактивность — оборачивать снаружи (но обычно это означает, что нужен `Tag`, а не `TagColor`).
91
+ - `forwardRef<HTMLSpanElement>` — не убирать. Ref всегда указывает на корневой `<span>`.
92
+ - Корневой элемент — `<span>` (метка инлайновая, встаёт в строку текста и в ячейку таблицы).
93
+ Менять на `div` нельзя.
94
+ - `displayName` — `"TagColor"`. Не менять.
95
+ - Двухуровневая разметка обязательна: корневой `<span class="tagColor">` держит фон, размеры
96
+ и `display: inline-flex`, вложенный `<span class="content">` — обрезку текста
97
+ (`min-width: 0`, `overflow: hidden`, `text-overflow: ellipsis`, `white-space: nowrap`)
98
+ и цвет текста. Схлопывать в один элемент нельзя: обрезка перестанет работать, а `max-width: 100%`
99
+ на корне — ограничивать ширину.
100
+ - `status` имеет значение по умолчанию `ETagColorStatus.DEFAULT` — оно проставляется
101
+ в деструктуризации props, а не в `defaultProps`. Класс статуса на корне есть всегда.
102
+ - Значения `ETagColorStatus` (`"default"` / `"success"` / `"info"` / `"warning"` / `"error"`)
103
+ совпадают с именами CSS-классов в `TagColor.module.less` и с суффиксами токенов
104
+ `TagColor.Background_*`. Переименование значения enum — ломающее изменение сразу в трёх местах.
105
+ - `className` деструктурируется из props и мерджится через `clsx`, поэтому в `...restProps`
106
+ его нет и перезатереть базовые классы он не может.
107
+ - Экспорты `TagColor`, `ITagColorProps` и `ETagColorStatus` идут в barrel
108
+ `src/components/TagColor/index.ts` — сохранять.
93
109
 
94
110
  ---
95
111
 
96
112
  ## Accessibility
97
113
 
98
- - Нет специальной ARIA — это визуальный маркер.
99
- - Цвет статуса **не должен** быть единственным носителем смысла. Текст внутри (`children`) — основной канал для screen-reader.
100
- - При необходимости потребитель может добавить `role="status"` или `aria-label` через restProps.
114
+ - Собственной ARIA-роли нет: корневой `<span>` — неинтерактивный контейнер, в порядок фокуса
115
+ не попадает, обработчиков клавиатуры у компонента нет.
116
+ - Цвет — единственный визуальный носитель статуса, поэтому **смысл обязан быть в тексте
117
+ метки**. Не полагайся на один цвет: `<TagColor status={ETagColorStatus.ERROR}>Отклонено</TagColor>`,
118
+ а не пустая красная плашка.
119
+ - Если метка расшифровывает соседний элемент (статус строки таблицы), связывай их через
120
+ `aria-describedby` / `aria-labelledby` на стороне потребителя — компонент никаких
121
+ ARIA-атрибутов сам не проставляет, но пробрасывает любые через `...restProps`.
122
+ - Компонент не хардкодит текстовые строки: содержимое и любые `aria-label` / `title` задаёт
123
+ потребитель. Библиотека мультиязычная.
101
124
 
102
125
  ---
103
126
 
104
127
  ## Связанные компоненты
105
128
 
106
- - `Tag` — тег с edit/remove кнопками.
107
- - `TagGroup` — контейнер для коллекции тегов с overflow.
129
+ - `Tag` — визуально похожая плашка, но интерактивная: с кнопками удаления и редактирования
130
+ и без `status`. Берётся, когда значение можно снять; `TagColor` — когда метку только показывают.
131
+ - `Marker` — цветная точка-индикатор статуса без текста. Тот же набор смыслов, минимальная форма:
132
+ берётся, когда на подпись нет места.
133
+ - `MarkerStatus` — точка с подписью и описанием. Альтернатива, когда статусу нужен не компактный
134
+ бейдж, а строка с пояснением.
108
135
 
109
136
  ---
110
137
 
111
138
  ## Stories
112
139
 
113
140
  Основные истории: `stories/TagColor/TagColor.stories.tsx`
141
+ Файлы примеров: `stories/TagColor/examples/`
142
+
143
+ | Story | Example file | Что демонстрирует |
144
+ |---|---|---|
145
+ | `Playground` | `Playground.tsx` | Интерактивный контроль `children`, `size` и `status` |
146
+ | `Default` | `Default.tsx` | Минимальная метка: обязателен только `size`, статус по умолчанию |
147
+ | `Sizes` | `Sizes.tsx` | Размеры SM / MD / LG при одном статусе |
148
+ | `Statuses` | `Statuses.tsx` | Все пять значений `ETagColorStatus` при одном размере |
149
+ | `WithOverflow` | `WithOverflow.tsx` | Обрезка длинного контента многоточием по ширине контейнера |
150
+ | `VisualTests` | `VisualTests.tsx` | Матрица размеров × статусов плюс пустая метка и обрезка — для скриншот-тестов |
151
+
152
+ Story ID участвуют в именах baseline-скриншотов (`tagcolor--sizes--xs.png` и т.п.), поэтому
153
+ переименование story требует перегенерации baseline и удаления осиротевших файлов.
114
154
 
115
155
  ---
116
156
 
@@ -118,4 +158,85 @@ enum ETagColorStatus {
118
158
 
119
159
  | Дата | Изменение |
120
160
  |---|---|
121
- | 2026-04-18 | Создан документ |
161
+ | 2026-09-22 | Создан документ. AI-рефакторинг (JSDoc на props, enum и map'ах класса, типизация `STATUS_TO_CLASS_NAME_MAP`, исправлен JSDoc `ITagColorProps`), расширены unit-тесты, stories переведены на modern pattern и дополнены `VisualTests`. |
162
+ | 2026-09-22 | По ревью: `children` объявлен в `ITagColorProps` явно (тип прежний, приходил из `React.HTMLAttributes`) — попадает в таблицу Props в Storybook. JSDoc компонента сокращён, детали разметки остались здесь. |
163
+ | 2026-09-22 | По решению ревьюера stories `DifferentSizes` / `DifferentStatuses` переименованы в `Sizes` / `Statuses` — единообразно с `Tag`, `Marker`, `NumberField`. Baseline перегенерированы, старые удалены. |
164
+
165
+ ---
166
+
167
+ ## Примеры использования
168
+
169
+ ### Default
170
+
171
+ `stories/TagColor/examples/Default.tsx`
172
+
173
+ ```tsx
174
+ import React from "react";
175
+ import { TagColor, EComponentSize } from "@sberbusiness/triplex-next";
176
+
177
+ export const Default = () => <TagColor size={EComponentSize.MD}>Tag text</TagColor>;
178
+ ```
179
+
180
+ ### Sizes
181
+
182
+ `stories/TagColor/examples/Sizes.tsx`
183
+
184
+ ```tsx
185
+ import React from "react";
186
+ import { TagColor, EComponentSize, ETagColorStatus } from "@sberbusiness/triplex-next";
187
+
188
+ const SIZES = Object.values(EComponentSize);
189
+
190
+ export const Sizes = () => (
191
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
192
+ {SIZES.map((size) => (
193
+ <div key={size}>
194
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{size.toUpperCase()}</div>
195
+ <TagColor size={size} status={ETagColorStatus.INFO}>
196
+ Tag text
197
+ </TagColor>
198
+ </div>
199
+ ))}
200
+ </div>
201
+ );
202
+ ```
203
+
204
+ ### Statuses
205
+
206
+ `stories/TagColor/examples/Statuses.tsx`
207
+
208
+ ```tsx
209
+ import React from "react";
210
+ import { TagColor, EComponentSize, ETagColorStatus } from "@sberbusiness/triplex-next";
211
+
212
+ const STATUSES = Object.values(ETagColorStatus);
213
+
214
+ export const Statuses = () => (
215
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
216
+ {STATUSES.map((status) => (
217
+ <div key={status}>
218
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{status.toUpperCase()}</div>
219
+ <TagColor size={EComponentSize.MD} status={status}>
220
+ Tag text
221
+ </TagColor>
222
+ </div>
223
+ ))}
224
+ </div>
225
+ );
226
+ ```
227
+
228
+ ### WithOverflow
229
+
230
+ `stories/TagColor/examples/WithOverflow.tsx`
231
+
232
+ ```tsx
233
+ import React from "react";
234
+ import { TagColor, EComponentSize } from "@sberbusiness/triplex-next";
235
+
236
+ export const WithOverflow = () => (
237
+ <div style={{ maxWidth: 400 }}>
238
+ <TagColor size={EComponentSize.LG}>Very long tag text that should be truncated with ellipsis</TagColor>
239
+ </div>
240
+ );
241
+ ```
242
+
@@ -1,9 +1,7 @@
1
1
  ---
2
2
  component: TagGroup
3
- category: Data Display
4
- figma-node: ""
5
- figma-file: ""
6
- related: [Tag, TagColor]
3
+ category: TagGroup
4
+ related: [Tag, ChipGroup]
7
5
  tokens: []
8
6
  stories: stories/TagGroup/TagGroup.stories.tsx
9
7
  version: "1.0"
@@ -13,83 +11,121 @@ version: "1.0"
13
11
 
14
12
  ## Назначение
15
13
 
16
- Контейнер для коллекции `Tag` / `TagColor`: задаёт общий
17
- горизонтальный/вертикальный gap по `size` и `role="group"`. Не управляет
18
- overflow или выбором — чистая разметка.
14
+ Контейнер-раскладка для тегов: выстраивает `Tag` в общем потоке с одинаковым отступом,
15
+ переносит их на новые строки, когда ширины контейнера не хватает, и помечает набор
16
+ как группу (`role="group"`).
19
17
 
20
- Используй когда: нужно сгруппировать несколько тегов с одинаковым размером
21
- и стандартным отступом. Сами теги передаются как children — потребитель
22
- решает, что внутри (`Tag`, `TagColor`, миксы).
18
+ Используй когда: на экране идёт ряд снимаемых значений — применённые фильтры, выбранные
19
+ в форме опции — и им нужен единый отступ и общая семантика группы.
20
+ Не используй когда: группируются чипсы семейства `Chip*` — для них есть `ChipGroup`
21
+ (flex + `gap`, опциональный режим одной строки с прокруткой). Нужен контейнер общего
22
+ назначения с отступами — бери собственную вёрстку.
23
23
 
24
24
  ---
25
25
 
26
- ## Файловая структура
26
+ ## Варианты и props
27
27
 
28
- ```text
29
- src/components/TagGroup/
30
- ├── TagGroup.tsx # forwardRef<HTMLDivElement, ITagGroupProps>
31
- ├── types.ts # ITagGroupProps
32
- ├── styles/TagGroup.module.less
33
- ├── __tests__/
34
- └── index.ts
35
- ```
36
-
37
- ---
38
-
39
- ## Публичный API
28
+ ### Обязательные props
40
29
 
41
- ### `ITagGroupProps`
30
+ | Prop | Тип | Описание |
31
+ |---|---|---|
32
+ | `size` | `EComponentSize` | Отступ между тегами: SM — 4px, MD — 8px, LG — 12px. Размер самих тегов не меняет |
42
33
 
43
- ```ts
44
- extends HTMLAttributes<HTMLDivElement>
45
- ```
34
+ ### Опциональные props
46
35
 
47
- | Prop | Тип | Default | Описание |
36
+ | Prop | Тип | По умолчанию | Описание |
48
37
  |---|---|---|---|
49
- | `size` | `EComponentSize` | — | **Обязателен**. Маппится на класс gap'а через `createSizeToClassNameMap`. |
50
- | `children` | `ReactNode` | — | Теги внутри. Размер тегов **не** прокидывается автоматически — выставлять у каждого `Tag`/`TagColor` отдельно. |
51
- | `...HTMLAttributes<HTMLDivElement>` | — | — | На корневой div (role=group). |
38
+ | `children` | `React.ReactNode` | — | Обычно набор `Tag`. Отступ получает **любой** прямой ребёнок — селектор в LESS-модуле `& > *` |
39
+ | `...HTMLDivAttributes` | `React.HTMLAttributes<HTMLDivElement>` | — | Все атрибуты `<div>`, включая `style`, `aria-*`, `data-*` и `role` |
40
+
41
+ ### Ограничения использования
42
+
43
+ - **`size` не пробрасывается в теги.** Он задаёт только отступ группы; `size` каждого `Tag`
44
+ потребитель выставляет сам. Рассинхрон размеров группы и тегов ничем не подсвечивается —
45
+ во всех stories они совпадают.
46
+ - **Отступ сделан на margin'ах, а не на `gap`.** Каждый прямой ребёнок получает
47
+ `margin: 2px / 4px / 6px`, а сам контейнер — такой же отрицательный margin. Следствия:
48
+ крайние теги прижаты к границам группы, но визуально группа «вылезает» за свой бокс
49
+ на эти 2/4/6px и может наехать на соседний контент, если у родителя нет отступа.
50
+ - **Собственного `display` у контейнера нет** — это обычный блок, теги переносятся
51
+ как инлайновые элементы. Если записать теги в одну строку JSX через пробел
52
+ (`<Tag/> <Tag/>`), между ними добавится пробельный текстовый узел и горизонтальный
53
+ зазор станет чуть больше вертикального. При переносе тегов по строкам или рендере
54
+ из `map()` такого узла не возникает и зазоры одинаковы.
55
+ - **Ширину контейнер не ограничивает.** Перенос по строкам появится только там, где
56
+ ширину задал родитель.
57
+ - **`role="group"` можно переопределить.** Атрибут выставляется **до** `{...restProps}`,
58
+ поэтому `role`, переданный потребителем, побеждает (в отличие от `data-tx` в `ChipGroup`,
59
+ который стоит после spread и переопределению не поддаётся).
52
60
 
53
61
  ---
54
62
 
55
- ## Структура DOM
63
+ ## Дизайн-токены
56
64
 
57
- ```html
58
- <div class="tagGroup {size} {className}" role="group">
59
- {children}
60
- </div>
61
- ```
65
+ Компонент не использует собственных CSS-переменных: в стилях только раскладка (margin'ы
66
+ по размерам). Цвета и размеры приходят от вложенных тегов — см. `Tag-ai.md`.
62
67
 
63
68
  ---
64
69
 
65
70
  ## Инварианты
66
71
 
67
- - **`forwardRef<HTMLDivElement>`** — не убирать.
68
- - **`size` обязателен**, без default'а — потребитель указывает явно.
69
- - **`size` НЕ прокидывается в children** — каждый `Tag`/`TagColor` принимает свой `size` независимо. `TagGroup.size` влияет только на gap между ними.
70
- - **`role="group"`** — фиксированно. Не переопределять без причины.
71
- - **Корень — `<div>`** (в отличие от `Tag`/`TagColor`, которые `<span>`).
72
- - **Нет overflow-логики** — все теги рендерятся inline; перенос строк регулируется CSS (`flex-wrap` в LESS).
72
+ - **`forwardRef<HTMLDivElement>`** — обязателен, `ref` указывает на корневой `<div>`. Не убирать.
73
+ - **Корневой элемент — `<div>` с `role="group"` по умолчанию.** Роль — часть наблюдаемого
74
+ контракта: на неё опираются unit-тесты (`screen.getByRole("group")`) и потребители.
75
+ - **`size` — обязательный prop без значения по умолчанию.** Делать его опциональным
76
+ или менять числа отступов нельзя без согласования: это изменит вёрстку у потребителей.
77
+ - **Порядок в JSX: `className` → `role` → `{...restProps}` → `ref`.** Перестановка `role`
78
+ за spread отнимет у потребителя возможность переопределить роль.
79
+ - **`className` добавляется последним аргументом `clsx`** и собственные классы не затирает.
80
+ - **Классы `.sm` / `.md` / `.lg` берутся из общего хелпера** `createSizeToClassNameMap`
81
+ (`src/utils/classNameMaps.ts`) — локальный маппинг не заводить.
82
+ - **`displayName`** — `"TagGroup"`. Не менять.
83
+ - **Публичный API** — `TagGroup` и `ITagGroupProps` через `src/components/TagGroup/index.ts`
84
+ (`export * from "./types"` + `export * from "./TagGroup"`) и общий barrel
85
+ `src/components/index.ts`. Сохранять.
86
+ - **Story ids `taggroup--*`** завязаны на baseline-скриншоты в `__screenshots__/` —
87
+ переименование story требует синхронного обновления baseline.
73
88
 
74
89
  ---
75
90
 
76
91
  ## Accessibility
77
92
 
78
- - `role="group"` — семантическая группа; рекомендуется добавить `aria-label` или `aria-labelledby` через restProps для описания назначения группы (например, "Активные фильтры").
79
- - Каждый тег внутри отвечает за свою ARIA сам.
93
+ - Корневой `<div>` несёт `role="group"` — набор тегов объявляется скринридеру как группа.
94
+ - **Доступное имя группе задаёт потребитель**: `aria-label` или `aria-labelledby` через
95
+ `...restProps`. Компонент строку не подставляет — библиотека мультиязычная. Без имени
96
+ роль `group` остаётся безымянной и пользы от неё немного.
97
+ - Если набор тегов по смыслу не группа контролов, а список, роль переопределяется снаружи:
98
+ `role="list"` (тогда детям нужен `role="listitem"`).
99
+ - Клавиатуру и фокус компонент не трогает: порядок фокуса задаётся порядком тегов в DOM,
100
+ а кнопки внутри — это `ButtonIcon` внутри `Tag`, `aria-label` для них передаётся
101
+ на самих тегах (`editButtonProps` / `removeButtonProps`).
80
102
 
81
103
  ---
82
104
 
83
105
  ## Связанные компоненты
84
106
 
85
- - `Tag` — интерактивные теги (edit/remove).
86
- - `TagColor` — цветные маркеры.
107
+ - `Tag` — основной ребёнок группы: плашка с выбранным значением, кнопкой удаления и,
108
+ при переданном `onEdit`, кнопкой редактирования. Свой `size` получает отдельно от группы.
109
+ - `ChipGroup` — аналогичный контейнер для семейства `Chip*`. Отличия: раскладка на
110
+ `display: flex` + `gap`, `size` опционален, роли по умолчанию нет, зато есть режим
111
+ `oneLine` с горизонтальной прокруткой.
112
+ - `TagColor` — неинтерактивная цветная метка статуса. В группу её класть можно (отступ
113
+ получает любой прямой ребёнок), но типовой ребёнок `TagGroup` — именно `Tag`.
87
114
 
88
115
  ---
89
116
 
90
117
  ## Stories
91
118
 
92
119
  Основные истории: `stories/TagGroup/TagGroup.stories.tsx`
120
+ Файлы примеров: `stories/TagGroup/examples/`
121
+
122
+ | Story | Example file | Что демонстрирует |
123
+ |---|---|---|
124
+ | `Playground` | `Playground.tsx` | Интерактивный контроль `size` и наличия кнопки редактирования у тегов |
125
+ | `Default` | `Default.tsx` | Минимальная группа тегов с отступом `LG` |
126
+ | `Sizes` | `Sizes.tsx` | Отступы для размеров SM / MD / LG |
127
+ | `WithOverflow` | `WithOverflow.tsx` | Перенос тегов по строкам в контейнере фиксированной ширины |
128
+ | `VisualTests` | `VisualTests.tsx` | Матрица размеров с переносом строк и группа из одного длинного тега — для скриншот-тестов |
93
129
 
94
130
  ---
95
131
 
@@ -97,4 +133,104 @@ extends HTMLAttributes<HTMLDivElement>
97
133
 
98
134
  | Дата | Изменение |
99
135
  |---|---|
100
- | 2026-04-18 | Создан документ |
136
+ | 2026-09-18 | Создан документ. AI-рефакторинг (TRI-95): `displayName`, маппинг размеров в UPPER_SNAKE_CASE, JSDoc на props и компоненте, явный `children` в `ITagGroupProps`; расширены unit-тесты, stories переведены на modern pattern. Публичный API, DOM и внешний вид не изменены |
137
+
138
+ ---
139
+
140
+ ## Примеры использования
141
+
142
+ ### Default
143
+
144
+ `stories/TagGroup/examples/Default.tsx`
145
+
146
+ ```tsx
147
+ import React from "react";
148
+ import { Tag, TagGroup, EComponentSize } from "@sberbusiness/triplex-next";
149
+
150
+ const TAGS = ["Selected value", "Another value", "One more value"];
151
+
152
+ export const Default = () => (
153
+ <TagGroup size={EComponentSize.LG} aria-label="Применённые фильтры">
154
+ {TAGS.map((label, index) => (
155
+ <Tag
156
+ key={label}
157
+ id={`default-tag-${index}`}
158
+ size={EComponentSize.LG}
159
+ onRemove={() => {}}
160
+ removeButtonProps={{ "aria-label": "Удалить" }}
161
+ >
162
+ {label}
163
+ </Tag>
164
+ ))}
165
+ </TagGroup>
166
+ );
167
+ ```
168
+
169
+ ### Sizes
170
+
171
+ `stories/TagGroup/examples/Sizes.tsx`
172
+
173
+ ```tsx
174
+ import React from "react";
175
+ import { Tag, TagGroup, EComponentSize } from "@sberbusiness/triplex-next";
176
+
177
+ const SIZES = Object.values(EComponentSize);
178
+ const TAGS = ["Selected value", "Another value", "One more value"];
179
+
180
+ export const Sizes = () => (
181
+ <div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
182
+ {SIZES.map((size) => (
183
+ <div key={size}>
184
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{size.toUpperCase()}</div>
185
+ <TagGroup size={size} aria-label={`Применённые фильтры, размер ${size}`}>
186
+ {TAGS.map((label, index) => (
187
+ <Tag
188
+ key={label}
189
+ id={`${size}-tag-${index}`}
190
+ size={size}
191
+ onEdit={() => {}}
192
+ onRemove={() => {}}
193
+ editButtonProps={{ "aria-label": "Редактировать" }}
194
+ removeButtonProps={{ "aria-label": "Удалить" }}
195
+ >
196
+ {label}
197
+ </Tag>
198
+ ))}
199
+ </TagGroup>
200
+ </div>
201
+ ))}
202
+ </div>
203
+ );
204
+ ```
205
+
206
+ ### WithOverflow
207
+
208
+ `stories/TagGroup/examples/WithOverflow.tsx`
209
+
210
+ ```tsx
211
+ import React from "react";
212
+ import { Tag, TagGroup, EComponentSize } from "@sberbusiness/triplex-next";
213
+
214
+ const TAGS = Array.from({ length: 6 }, (_, index) => `Selected value ${index + 1}`);
215
+
216
+ export const WithOverflow = () => (
217
+ // maxWidth, а не width: на широком экране в строку помещается четыре тега,
218
+ // на узком контейнер сжимается по месту и теги переносятся раньше.
219
+ <div style={{ maxWidth: 760, border: "1px dashed #D0D4D9" }}>
220
+ <TagGroup size={EComponentSize.LG} aria-label="Применённые фильтры">
221
+ {TAGS.map((label, index) => (
222
+ <Tag
223
+ key={label}
224
+ id={`overflow-tag-${index}`}
225
+ size={EComponentSize.LG}
226
+ onRemove={() => {}}
227
+ removeButtonProps={{ "aria-label": "Удалить" }}
228
+ >
229
+ {label}
230
+ </Tag>
231
+ ))}
232
+ </TagGroup>
233
+ </div>
234
+ );
235
+ ```
236
+