@sberbusiness/triplex-next-mcp-server 0.24.0-beta1 → 0.36.0-beta0

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 (66) hide show
  1. package/README.md +10 -0
  2. package/bundle/components/Alert.md +272 -0
  3. package/bundle/components/Amount.md +138 -0
  4. package/bundle/components/AmountField.md +174 -0
  5. package/bundle/components/Avatar.md +72 -0
  6. package/bundle/components/Badge.md +203 -0
  7. package/bundle/components/BodyPage.md +186 -0
  8. package/bundle/components/Button.md +370 -85
  9. package/bundle/components/ButtonDropdown.md +328 -70
  10. package/bundle/components/ButtonIcon.md +98 -42
  11. package/bundle/components/Calendar.md +58 -0
  12. package/bundle/components/Checkbox.md +77 -44
  13. package/bundle/components/CheckboxTree.md +61 -0
  14. package/bundle/components/CheckboxTreeExtended.md +114 -0
  15. package/bundle/components/CheckboxXGroup.md +120 -16
  16. package/bundle/components/CheckboxYGroup.md +88 -15
  17. package/bundle/components/CollapsibleTree.md +581 -0
  18. package/bundle/components/CollapsibleTreeExtended.md +418 -0
  19. package/bundle/components/EmptyView.md +133 -15
  20. package/bundle/components/FooterPage.md +203 -0
  21. package/bundle/components/Gap.md +115 -57
  22. package/bundle/components/HeaderPage.md +226 -0
  23. package/bundle/components/HelpBox.md +231 -72
  24. package/bundle/components/ImageGallery.md +423 -0
  25. package/bundle/components/ImageGalleryExtended.md +606 -0
  26. package/bundle/components/List.md +194 -186
  27. package/bundle/components/ListItem.md +251 -0
  28. package/bundle/components/ListItemControlsButton.md +103 -0
  29. package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
  30. package/bundle/components/ListItemSelectable.md +99 -0
  31. package/bundle/components/ListItemTable.md +390 -0
  32. package/bundle/components/ListMaster.md +877 -156
  33. package/bundle/components/ListMasterFooter.md +80 -0
  34. package/bundle/components/ListMasterHeader.md +86 -0
  35. package/bundle/components/ListSortable.md +153 -0
  36. package/bundle/components/ListSortableItem.md +175 -0
  37. package/bundle/components/ModalWindow.md +427 -237
  38. package/bundle/components/MonthYearField.md +145 -109
  39. package/bundle/components/Notification.md +625 -155
  40. package/bundle/components/Overlay.md +271 -170
  41. package/bundle/components/Page.md +283 -186
  42. package/bundle/components/Pagination.md +206 -229
  43. package/bundle/components/SliderExtended.md +285 -0
  44. package/bundle/guides/codestyle.md +38 -11
  45. package/bundle/guides/commits.md +1 -2
  46. package/bundle/guides/context.md +34 -30
  47. package/bundle/guides/stories.md +110 -40
  48. package/bundle/guides/template.md +3 -7
  49. package/bundle/guides/tests.md +6 -2
  50. package/bundle/manifest.json +194 -24
  51. package/bundle/release-notes/1.26.0.mdx +33 -2
  52. package/bundle/release-notes/1.27.0.mdx +43 -0
  53. package/bundle/release-notes/1.28.0.mdx +25 -0
  54. package/bundle/release-notes/1.29.0.mdx +47 -0
  55. package/bundle/release-notes/1.30.0.mdx +56 -0
  56. package/bundle/release-notes/1.31.0.mdx +52 -0
  57. package/bundle/release-notes/1.32.0.mdx +35 -0
  58. package/bundle/release-notes/1.33.0.mdx +61 -0
  59. package/bundle/release-notes/1.34.0.mdx +35 -0
  60. package/bundle/release-notes/1.35.0.mdx +21 -0
  61. package/bundle/release-notes/1.35.1.mdx +11 -0
  62. package/bundle/release-notes/1.36.0.mdx +21 -0
  63. package/bundle/release-notes/1.37.0.mdx +30 -0
  64. package/dist/index.js +2 -0
  65. package/dist/index.js.map +1 -1
  66. package/package.json +1 -1
@@ -1,8 +1,6 @@
1
1
  ---
2
2
  component: ButtonDropdown
3
3
  category: Buttons
4
- figma-node: ""
5
- figma-file: ""
6
4
  related: [Button, ButtonDropdownExtended, Dropdown]
7
5
  tokens: []
8
6
  stories: stories/Buttons/ButtonDropdown.stories.tsx
@@ -13,25 +11,10 @@ version: "1.0"
13
11
 
14
12
  ## Назначение
15
13
 
16
- Кнопка-триггер с выпадающим списком действий.
17
- Поддерживает два визуальных режима: обычная кнопка (`EButtonTheme`) и dots-вариант (`EButtonDotsTheme`).
14
+ Кнопка-триггер с выпадающим списком действий. Поддерживает два визуальных режима: обычная кнопка (`EButtonTheme`) и dots-вариант (`EButtonDotsTheme`).
18
15
 
19
16
  Используй когда: нужно сгруппировать несколько действий под один триггер и дать выбор опции из списка.
20
- Не используй когда: нужна одиночная кнопка без списка - используй `Button`.
21
-
22
- ---
23
-
24
- ## Файловая структура
25
-
26
- ```text
27
- src/components/Button/
28
- ├── ButtonDropdown.tsx # Основной компонент (forwardRef, рендер button + dropdown)
29
- ├── ButtonDropdownExtended.tsx # Базовый контейнер с контролем opened/close и outside click
30
- ├── styles/
31
- │ ├── ButtonDropdown.module.less # Стили caret, active-состояния, block-режима
32
- │ └── ButtonDropdownExtended.module.less
33
- └── index.ts # Публичный экспорт ButtonDropdown
34
- ```
17
+ Не используй когда: нужна одиночная кнопка без списка — используй `Button`.
35
18
 
36
19
  ---
37
20
 
@@ -49,18 +32,13 @@ src/components/Button/
49
32
 
50
33
  | Prop | Тип | По умолчанию | Описание |
51
34
  |---|---|---|---|
52
- | `children` | `React.ReactNode` | `undefined` | Текст/контент кнопки (используется также в mobile header) |
53
- | `selected` | `IButtonDropdownOption` | `undefined` | Предвыбранная опция для подсветки в списке |
35
+ | `children` | `React.ReactNode` | — | Текст/контент кнопки (используется также в mobile header) |
36
+ | `selected` | `IButtonDropdownOption` | — | Предвыбранная опция для подсветки в списке |
54
37
  | `disabled` | `boolean` | `false` | Блокирует кнопку и открытие списка |
55
- | `buttonAttributes` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | `undefined` | Дополнительные HTML-атрибуты нативной кнопки |
56
- | `block` | `boolean` | `false` | Доступен только для non-dots тем |
38
+ | `buttonAttributes` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | — | Дополнительные HTML-атрибуты нативной кнопки (включая `aria-label`) |
39
+ | `block` | `boolean` | `false` | Полноширинный режим (только для non-dots тем) |
57
40
  | `className` | `string` | — | Дополнительный CSS-класс контейнера |
58
- | `...rest` | `React.HTMLAttributes<HTMLDivElement>` | — | Атрибуты корневого `div` компонента |
59
-
60
- ### Ограничения по темам
61
-
62
- - Для `EButtonDotsTheme` prop `block` запрещен типизацией (`never`).
63
- - Dots-режим использует иконку `Dotshorizontal*` вместо текстового контента кнопки.
41
+ | `...rest` | `React.HTMLAttributes<HTMLDivElement>` | — | Атрибуты корневого `<div>` компонента |
64
42
 
65
43
  ### Структура опции (`IButtonDropdownOption`)
66
44
 
@@ -69,50 +47,19 @@ src/components/Button/
69
47
  | `id` | `string` | Уникальный идентификатор опции |
70
48
  | `label` | `React.ReactNode` | Видимый контент пункта меню |
71
49
  | `onSelect` | `() => void` | Callback выбора опции |
72
- | `...rest` | `IDropdownListItemProps` (без ряда запрещенных полей) | Остальные настройки `DropdownList.Item` |
73
-
74
- ---
75
-
76
- ## Ключевые особенности реализации
77
-
78
- ### Композиция через `ButtonDropdownExtended`
50
+ | `...rest` | `IDropdownListItemProps` (без ряда запрещённых полей) | Остальные настройки `DropdownList.Item` |
79
51
 
80
- - `ButtonDropdown` делегирует управление opened-state и close-on-outside в `ButtonDropdownExtended`.
81
- - Передает две render-функции: `renderButton` и `renderDropdown`.
82
-
83
- ### Desktop + mobile dropdown
84
-
85
- - Desktop: рендерится `DropdownList` с `DropdownList.Item`.
86
- - Mobile: через `mobileViewProps` рендерится `DropdownMobileHeader` + `DropdownMobileList`.
87
- - После выбора любого пункта вызывается `option.onSelect?.()` и dropdown закрывается.
88
-
89
- ### Управление клавиатурой
90
-
91
- - На кнопке перехватываются `Space`, `ArrowUp`, `ArrowDown` с `preventDefault`.
92
- - `ArrowUp/ArrowDown` открывают dropdown, если он закрыт.
93
- - В `ButtonDropdownExtended` dropdown закрывается по `Escape` и (из-за `closeOnTab`) по `Tab`.
94
-
95
- ### ARIA-связка trigger/list
96
-
97
- - Кнопка получает `aria-haspopup="menu"`, `aria-expanded`, `aria-controls`.
98
- - `aria-controls` и `DropdownList` связываются через `instanceId` (`uniqueId()`).
99
- - `aria-activedescendant` синхронизируется через `DropdownListContext`.
100
-
101
- ---
102
-
103
- ## Accessibility
52
+ ### Ограничения по темам
104
53
 
105
- - Триггер строится на `Button` (нативный `button`), базовая keyboard-навигация сохраняется.
106
- - Компонент не хардкодит aria-тексты: при необходимости `aria-label` нужно передавать через `buttonAttributes`.
107
- - На mobile-заголовке dropdown отображается `children` триггера; если в продукте нужен локализованный отдельный заголовок, его нужно задавать на уровне композиции (через `ButtonDropdownExtended`).
108
- - Для корректной доступности меню потребитель должен передавать понятные `label` для `options`.
54
+ - Для `EButtonDotsTheme` prop `block` запрещён типизацией (`never`).
55
+ - Dots-режим использует иконку `Dotshorizontal*` вместо текстового контента кнопки.
56
+ - Desktop рендерит `DropdownList` с `DropdownList.Item`; mobile через `mobileViewProps` рендерит `DropdownMobileHeader` + `DropdownMobileList`.
109
57
 
110
58
  ---
111
59
 
112
60
  ## Дизайн-токены
113
61
 
114
- `ButtonDropdown` не использует собственных CSS color-токенов в `ButtonDropdown.module.less`.
115
- Визуальные токены берутся из `Button` и `Dropdown`, которые рендерятся внутри.
62
+ `ButtonDropdown` не использует собственных CSS color-токенов. Визуальные токены берутся из `Button` и `Dropdown`, которые рендерятся внутри.
116
63
 
117
64
  ---
118
65
 
@@ -126,17 +73,27 @@ src/components/Button/
126
73
 
127
74
  ---
128
75
 
76
+ ## Accessibility
77
+
78
+ - Триггер строится на `Button` (нативный `<button>`), базовая keyboard-навигация сохраняется.
79
+ - Кнопка получает `aria-haspopup="menu"`, `aria-expanded`, `aria-controls`. Связка trigger/list осуществляется через `instanceId` (`uniqueId()`); `aria-activedescendant` синхронизируется через `DropdownListContext`.
80
+ - На кнопке перехватываются `Space`, `ArrowUp`, `ArrowDown` с `preventDefault`. `ArrowUp` / `ArrowDown` открывают dropdown, если он закрыт. Dropdown закрывается по `Escape` и (из-за `closeOnTab`) по `Tab`.
81
+ - Компонент **не хардкодит** aria-тексты: при необходимости `aria-label` нужно передавать через `buttonAttributes`. Для корректной доступности меню потребитель должен передавать понятные `label` для `options`.
82
+ - На mobile-заголовке dropdown отображается `children` триггера; если в продукте нужен локализованный отдельный заголовок, его нужно задавать на уровне композиции (через `ButtonDropdownExtended`).
83
+
84
+ ---
85
+
129
86
  ## Связанные компоненты
130
87
 
131
- - `Button` (`src/components/Button/Button.tsx`) - базовый триггер, на котором построен `ButtonDropdown`.
132
- - `ButtonDropdownExtended` (`src/components/Button/ButtonDropdownExtended.tsx`) - управляет открытием/закрытием dropdown.
133
- - `Dropdown` (`src/components/Dropdown`) - контейнер и пункты списка для desktop/mobile представления.
88
+ - `Button` (`src/components/Button/Button.tsx`) — базовый триггер, на котором построен `ButtonDropdown`.
89
+ - `ButtonDropdownExtended` (`src/components/Button/ButtonDropdownExtended.tsx`) — управляет открытием/закрытием dropdown через render-функции `renderButton` и `renderDropdown`.
90
+ - `Dropdown` (`src/components/Dropdown`) — контейнер и пункты списка для desktop/mobile представления.
134
91
 
135
92
  ---
136
93
 
137
94
  ## Stories
138
95
 
139
- `stories/Buttons/ButtonDropdown.stories.tsx`
96
+ Основные истории: `stories/Buttons/ButtonDropdown.stories.tsx`
140
97
  Файлы примеров: `stories/Buttons/examples/ButtonDropdown/`
141
98
 
142
99
  | Story | Example file | Что демонстрирует |
@@ -157,3 +114,304 @@ src/components/Button/
157
114
  | Дата | Изменение |
158
115
  |---|---|
159
116
  | 2026-04-15 | Создан документ AI-ready для `ButtonDropdown`. |
117
+ | 2026-04-27 | Приведён в соответствие с `docs/ai/template-ai.md`: убраны секции «Файловая структура» и «Ключевые особенности реализации», их содержимое перенесено в `Ограничения по темам` и `Accessibility`, добавлена колонка `Example file`. |
118
+
119
+ ---
120
+
121
+ ## Примеры использования
122
+
123
+ ### Default
124
+
125
+ `stories/Buttons/examples/ButtonDropdown/DefaultExample.tsx`
126
+
127
+ ```tsx
128
+ import React from "react";
129
+ import { ButtonDropdown, EButtonTheme, EComponentSize, IButtonDropdownOption } from "@sberbusiness/triplex-next";
130
+
131
+ const OPTIONS: IButtonDropdownOption[] = [
132
+ { id: "opt-1", label: "Действие 1", onSelect: () => undefined },
133
+ { id: "opt-2", label: "Действие 2", onSelect: () => undefined },
134
+ { id: "opt-3", label: "Действие 3", onSelect: () => undefined },
135
+ ];
136
+
137
+ export const DefaultExample = () => (
138
+ <div style={{ width: 280 }}>
139
+ <ButtonDropdown theme={EButtonTheme.GENERAL} size={EComponentSize.MD} options={OPTIONS}>
140
+ Button text
141
+ </ButtonDropdown>
142
+ </div>
143
+ );
144
+ ```
145
+
146
+ ### Sizes
147
+
148
+ `stories/Buttons/examples/ButtonDropdown/SizesExample.tsx`
149
+
150
+ ```tsx
151
+ import React from "react";
152
+ import {
153
+ ButtonDropdown,
154
+ EButtonDotsTheme,
155
+ EButtonTheme,
156
+ EComponentSize,
157
+ IButtonDropdownOption,
158
+ } from "@sberbusiness/triplex-next";
159
+
160
+ const OPTIONS: IButtonDropdownOption[] = [
161
+ { id: "opt-1", label: "Действие 1", onSelect: () => undefined },
162
+ { id: "opt-2", label: "Действие 2", onSelect: () => undefined },
163
+ { id: "opt-3", label: "Действие 3", onSelect: () => undefined },
164
+ ];
165
+
166
+ export const SizesExample = () => (
167
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
168
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
169
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>SM</div>
170
+ <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 16 }}>
171
+ <ButtonDropdown size={EComponentSize.SM} theme={EButtonTheme.GENERAL} options={OPTIONS}>
172
+ Button text
173
+ </ButtonDropdown>
174
+ <ButtonDropdown size={EComponentSize.SM} theme={EButtonTheme.SECONDARY} options={OPTIONS}>
175
+ Button text
176
+ </ButtonDropdown>
177
+ <ButtonDropdown size={EComponentSize.SM} theme={EButtonTheme.SECONDARY_LIGHT} options={OPTIONS}>
178
+ Button text
179
+ </ButtonDropdown>
180
+ <ButtonDropdown size={EComponentSize.SM} theme={EButtonTheme.DANGER} options={OPTIONS}>
181
+ Button text
182
+ </ButtonDropdown>
183
+ <ButtonDropdown size={EComponentSize.SM} theme={EButtonDotsTheme.DOTS_SECONDARY} options={OPTIONS}>
184
+ Button text
185
+ </ButtonDropdown>
186
+ <ButtonDropdown
187
+ size={EComponentSize.SM}
188
+ theme={EButtonDotsTheme.DOTS_SECONDARY_LIGHT}
189
+ options={OPTIONS}
190
+ >
191
+ Button text
192
+ </ButtonDropdown>
193
+ </div>
194
+ </div>
195
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
196
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>MD</div>
197
+ <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 16 }}>
198
+ <ButtonDropdown size={EComponentSize.MD} theme={EButtonTheme.GENERAL} options={OPTIONS}>
199
+ Button text
200
+ </ButtonDropdown>
201
+ <ButtonDropdown size={EComponentSize.MD} theme={EButtonTheme.SECONDARY} options={OPTIONS}>
202
+ Button text
203
+ </ButtonDropdown>
204
+ <ButtonDropdown size={EComponentSize.MD} theme={EButtonTheme.SECONDARY_LIGHT} options={OPTIONS}>
205
+ Button text
206
+ </ButtonDropdown>
207
+ <ButtonDropdown size={EComponentSize.MD} theme={EButtonTheme.DANGER} options={OPTIONS}>
208
+ Button text
209
+ </ButtonDropdown>
210
+ <ButtonDropdown size={EComponentSize.MD} theme={EButtonDotsTheme.DOTS_SECONDARY} options={OPTIONS}>
211
+ Button text
212
+ </ButtonDropdown>
213
+ <ButtonDropdown
214
+ size={EComponentSize.MD}
215
+ theme={EButtonDotsTheme.DOTS_SECONDARY_LIGHT}
216
+ options={OPTIONS}
217
+ >
218
+ Button text
219
+ </ButtonDropdown>
220
+ </div>
221
+ </div>
222
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
223
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>LG</div>
224
+ <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 16 }}>
225
+ <ButtonDropdown size={EComponentSize.LG} theme={EButtonTheme.GENERAL} options={OPTIONS}>
226
+ Button text
227
+ </ButtonDropdown>
228
+ <ButtonDropdown size={EComponentSize.LG} theme={EButtonTheme.SECONDARY} options={OPTIONS}>
229
+ Button text
230
+ </ButtonDropdown>
231
+ <ButtonDropdown size={EComponentSize.LG} theme={EButtonTheme.SECONDARY_LIGHT} options={OPTIONS}>
232
+ Button text
233
+ </ButtonDropdown>
234
+ <ButtonDropdown size={EComponentSize.LG} theme={EButtonTheme.DANGER} options={OPTIONS}>
235
+ Button text
236
+ </ButtonDropdown>
237
+ <ButtonDropdown size={EComponentSize.LG} theme={EButtonDotsTheme.DOTS_SECONDARY} options={OPTIONS}>
238
+ Button text
239
+ </ButtonDropdown>
240
+ <ButtonDropdown
241
+ size={EComponentSize.LG}
242
+ theme={EButtonDotsTheme.DOTS_SECONDARY_LIGHT}
243
+ options={OPTIONS}
244
+ >
245
+ Button text
246
+ </ButtonDropdown>
247
+ </div>
248
+ </div>
249
+ </div>
250
+ );
251
+ ```
252
+
253
+ ### Themes
254
+
255
+ `stories/Buttons/examples/ButtonDropdown/ThemesExample.tsx`
256
+
257
+ ```tsx
258
+ import React from "react";
259
+ import {
260
+ ButtonDropdown,
261
+ EButtonDotsTheme,
262
+ EButtonTheme,
263
+ EComponentSize,
264
+ IButtonDropdownOption,
265
+ } from "@sberbusiness/triplex-next";
266
+
267
+ const OPTIONS: IButtonDropdownOption[] = [
268
+ { id: "opt-1", label: "Действие 1", onSelect: () => undefined },
269
+ { id: "opt-2", label: "Действие 2", onSelect: () => undefined },
270
+ { id: "opt-3", label: "Действие 3", onSelect: () => undefined },
271
+ ];
272
+
273
+ export const ThemesExample = () => (
274
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
275
+ <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 16 }}>
276
+ <ButtonDropdown theme={EButtonTheme.GENERAL} size={EComponentSize.MD} options={OPTIONS}>
277
+ General
278
+ </ButtonDropdown>
279
+ <ButtonDropdown theme={EButtonTheme.SECONDARY} size={EComponentSize.MD} options={OPTIONS}>
280
+ Secondary
281
+ </ButtonDropdown>
282
+ <ButtonDropdown theme={EButtonTheme.SECONDARY_LIGHT} size={EComponentSize.MD} options={OPTIONS}>
283
+ Secondary Light
284
+ </ButtonDropdown>
285
+ <ButtonDropdown theme={EButtonTheme.DANGER} size={EComponentSize.MD} options={OPTIONS}>
286
+ Danger
287
+ </ButtonDropdown>
288
+ </div>
289
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
290
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>DOTS_SECONDARY</div>
291
+ <ButtonDropdown theme={EButtonDotsTheme.DOTS_SECONDARY} size={EComponentSize.MD} options={OPTIONS}>
292
+ Dots Secondary
293
+ </ButtonDropdown>
294
+ </div>
295
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
296
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>DOTS_SECONDARY_LIGHT</div>
297
+ <ButtonDropdown theme={EButtonDotsTheme.DOTS_SECONDARY_LIGHT} size={EComponentSize.MD} options={OPTIONS}>
298
+ Dots Secondary Light
299
+ </ButtonDropdown>
300
+ </div>
301
+ </div>
302
+ );
303
+ ```
304
+
305
+ ### BlockMode
306
+
307
+ `stories/Buttons/examples/ButtonDropdown/BlockModeExample.tsx`
308
+
309
+ ```tsx
310
+ import React from "react";
311
+ import { ButtonDropdown, EButtonTheme, EComponentSize, Gap, IButtonDropdownOption } from "@sberbusiness/triplex-next";
312
+
313
+ const OPTIONS: IButtonDropdownOption[] = [
314
+ { id: "opt-1", label: "Действие 1", onSelect: () => undefined },
315
+ { id: "opt-2", label: "Действие 2", onSelect: () => undefined },
316
+ { id: "opt-3", label: "Действие 3", onSelect: () => undefined },
317
+ ];
318
+
319
+ export const BlockModeExample = () => (
320
+ <div style={{ maxWidth: 280 }}>
321
+ <ButtonDropdown block theme={EButtonTheme.GENERAL} size={EComponentSize.MD} options={OPTIONS}>
322
+ Button text
323
+ </ButtonDropdown>
324
+ <Gap size={16} />
325
+ <ButtonDropdown block theme={EButtonTheme.SECONDARY} size={EComponentSize.MD} options={OPTIONS}>
326
+ Button text
327
+ </ButtonDropdown>
328
+ <Gap size={16} />
329
+ <ButtonDropdown block theme={EButtonTheme.SECONDARY_LIGHT} size={EComponentSize.MD} options={OPTIONS}>
330
+ Button text
331
+ </ButtonDropdown>
332
+ <Gap size={16} />
333
+ <ButtonDropdown block theme={EButtonTheme.DANGER} size={EComponentSize.MD} options={OPTIONS}>
334
+ Button text
335
+ </ButtonDropdown>
336
+ </div>
337
+ );
338
+ ```
339
+
340
+ ### Disabled
341
+
342
+ `stories/Buttons/examples/ButtonDropdown/DisabledExample.tsx`
343
+
344
+ ```tsx
345
+ import React from "react";
346
+ import {
347
+ ButtonDropdown,
348
+ EButtonDotsTheme,
349
+ EButtonTheme,
350
+ EComponentSize,
351
+ IButtonDropdownOption,
352
+ } from "@sberbusiness/triplex-next";
353
+
354
+ const OPTIONS: IButtonDropdownOption[] = [
355
+ { id: "opt-1", label: "Действие 1", onSelect: () => undefined },
356
+ { id: "opt-2", label: "Действие 2", onSelect: () => undefined },
357
+ { id: "opt-3", label: "Действие 3", onSelect: () => undefined },
358
+ ];
359
+
360
+ export const DisabledExample = () => (
361
+ <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 16 }}>
362
+ <ButtonDropdown disabled theme={EButtonTheme.GENERAL} size={EComponentSize.MD} options={OPTIONS}>
363
+ Button text
364
+ </ButtonDropdown>
365
+ <ButtonDropdown disabled theme={EButtonTheme.SECONDARY} size={EComponentSize.MD} options={OPTIONS}>
366
+ Button text
367
+ </ButtonDropdown>
368
+ <ButtonDropdown disabled theme={EButtonTheme.SECONDARY_LIGHT} size={EComponentSize.MD} options={OPTIONS}>
369
+ Button text
370
+ </ButtonDropdown>
371
+ <ButtonDropdown disabled theme={EButtonTheme.DANGER} size={EComponentSize.MD} options={OPTIONS}>
372
+ Button text
373
+ </ButtonDropdown>
374
+ <ButtonDropdown disabled theme={EButtonDotsTheme.DOTS_SECONDARY} size={EComponentSize.MD} options={OPTIONS}>
375
+ Button text
376
+ </ButtonDropdown>
377
+ <ButtonDropdown
378
+ disabled
379
+ theme={EButtonDotsTheme.DOTS_SECONDARY_LIGHT}
380
+ size={EComponentSize.MD}
381
+ options={OPTIONS}
382
+ >
383
+ Button text
384
+ </ButtonDropdown>
385
+ </div>
386
+ );
387
+ ```
388
+
389
+ ### WithSelectedOption
390
+
391
+ `stories/Buttons/examples/ButtonDropdown/WithSelectedOptionExample.tsx`
392
+
393
+ ```tsx
394
+ import React, { useMemo, useState } from "react";
395
+ import { ButtonDropdown, EButtonTheme, EComponentSize, IButtonDropdownOption } from "@sberbusiness/triplex-next";
396
+
397
+ const createOptions = (onItemSelect?: (id: string) => void): IButtonDropdownOption[] => [
398
+ { id: "opt-1", label: "Действие 1", onSelect: () => onItemSelect?.("opt-1") },
399
+ { id: "opt-2", label: "Действие 2", onSelect: () => onItemSelect?.("opt-2") },
400
+ { id: "opt-3", label: "Действие 3", onSelect: () => onItemSelect?.("opt-3") },
401
+ ];
402
+
403
+ export const WithSelectedOptionExample = () => {
404
+ const [selectedId, setSelectedId] = useState<string | undefined>("opt-2");
405
+ const options = useMemo(() => createOptions(setSelectedId), []);
406
+ const selected = options.find((o) => o.id === selectedId);
407
+
408
+ return (
409
+ <div style={{ maxWidth: 280 }}>
410
+ <ButtonDropdown theme={EButtonTheme.GENERAL} size={EComponentSize.MD} options={options} selected={selected}>
411
+ Button text
412
+ </ButtonDropdown>
413
+ </div>
414
+ );
415
+ };
416
+ ```
417
+
@@ -1,8 +1,6 @@
1
1
  ---
2
2
  component: ButtonIcon
3
3
  category: Buttons
4
- figma-node: ""
5
- figma-file: ""
6
4
  related: [Button]
7
5
  tokens:
8
6
  - --triplex-next-Button-Icon_Shadow_Focus
@@ -17,19 +15,7 @@ version: "1.0"
17
15
  Кнопка только с иконкой без текстового контента. Используется как компактный trigger для локальных действий (например, открыть меню, удалить, закрыть).
18
16
 
19
17
  Используй когда: действие можно однозначно распознать по иконке и есть корректный `aria-label`.
20
- Не используй когда: нужен текстовый CTA или несколько визуальных тем с размерами как у `Button` - используй `Button`.
21
-
22
- ---
23
-
24
- ## Файловая структура
25
-
26
- ```text
27
- src/components/Button/
28
- ├── ButtonIcon.tsx # Компонент (forwardRef, native button)
29
- ├── enums.ts # EButtonIconShape (SQUIRCLE / CIRCLE)
30
- └── styles/
31
- └── ButtonIcon.module.less # Геометрия, focus-visible, базовые состояния
32
- ```
18
+ Не используй когда: нужен текстовый CTA или несколько визуальных тем с размерами как у `Button` — используй `Button`.
33
19
 
34
20
  ---
35
21
 
@@ -51,29 +37,8 @@ src/components/Button/
51
37
  ### Ограничения использования
52
38
 
53
39
  - Размер `ButtonIcon` задаётся размером переданной иконки; у компонента нет собственного prop `size`.
54
- - Корневой DOM-элемент всегда `button`, `type` по умолчанию принудительно установлен в `button`.
55
-
56
- ---
57
-
58
- ## Ключевые особенности реализации
59
-
60
- ### Маппинг формы через enum
61
-
62
- - `shape` маппится в CSS-класс через `Record<EButtonIconShape, string>`.
63
- - При расширении `EButtonIconShape` нужно добавить класс в маппинг и в `ButtonIcon.module.less`.
64
-
65
- ### Визуальные состояния
66
-
67
- - `active` и `disabled` добавляются как глобальные CSS-классы (`active`, `disabled`) для совместимости с иконками.
68
- - Дополнительно всегда добавляется класс `hoverable`.
69
-
70
- ---
71
-
72
- ## Accessibility
73
-
74
- - Компонент рендерит нативный `<button>`, поэтому базовая keyboard-навигация доступна из коробки.
75
- - Компонент **не хардкодит** `aria-label` (библиотека мультиязычная). Для иконки без текста потребитель обязан передать `aria-label` через `...rest`.
76
- - Фокусное состояние реализовано через `:focus-visible` и токен `--triplex-next-Button-Icon_Shadow_Focus`.
40
+ - Корневой DOM-элемент всегда `<button>`, `type` по умолчанию принудительно установлен в `button`.
41
+ - При расширении `EButtonIconShape` необходимо добавить класс в маппинг `Record<EButtonIconShape, string>` и в `ButtonIcon.module.less`.
77
42
 
78
43
  ---
79
44
 
@@ -94,16 +59,24 @@ src/components/Button/
94
59
 
95
60
  ---
96
61
 
62
+ ## Accessibility
63
+
64
+ - Компонент рендерит нативный `<button>`, поэтому базовая keyboard-навигация доступна из коробки.
65
+ - Компонент **не хардкодит** `aria-label` (библиотека мультиязычная). Для иконки без текста потребитель **обязан** передать `aria-label` через `...rest`.
66
+ - Фокусное состояние реализовано через `:focus-visible` и токен `--triplex-next-Button-Icon_Shadow_Focus`.
67
+
68
+ ---
69
+
97
70
  ## Связанные компоненты
98
71
 
99
- - `Button` (`src/components/Button/Button.tsx`) - текстовая/универсальная кнопка, используемая вместо `ButtonIcon` когда нужен label.
100
- - `ButtonDropdown` (`src/components/Button/ButtonDropdown.tsx`) - использует иконочный паттерн для dots-варианта trigger.
72
+ - `Button` (`src/components/Button/Button.tsx`) — текстовая/универсальная кнопка, используемая вместо `ButtonIcon` когда нужен label.
73
+ - `ButtonDropdown` (`src/components/Button/ButtonDropdown.tsx`) — использует иконочный паттерн для dots-варианта trigger.
101
74
 
102
75
  ---
103
76
 
104
77
  ## Stories
105
78
 
106
- `stories/Buttons/ButtonIcon.stories.tsx`
79
+ Основные истории: `stories/Buttons/ButtonIcon.stories.tsx`
107
80
  Файлы примеров: `stories/Buttons/examples/ButtonIcon/`
108
81
 
109
82
  | Story | Example file | Что демонстрирует |
@@ -111,7 +84,7 @@ src/components/Button/
111
84
  | `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль `shape`, `active`, `disabled` |
112
85
  | `Default` | `DefaultExample.tsx` | Базовый сценарий использования |
113
86
  | `Sizes` | `SizesExample.tsx` | Разные размеры через размер иконки (16/20/24/32) |
114
- | `Disabled` | `DisabledExample.tsx` | Неактивное состояние |
87
+ | `States` | `StatesExample.tsx` | Состояния `active` и `disabled` |
115
88
 
116
89
  ---
117
90
 
@@ -120,3 +93,86 @@ src/components/Button/
120
93
  | Дата | Изменение |
121
94
  |---|---|
122
95
  | 2026-04-15 | Создан документ AI-ready для `ButtonIcon`. |
96
+ | 2026-04-27 | Приведён в соответствие с `docs/ai/template-ai.md`: убрана секция «Файловая структура», содержимое «Ключевых особенностей реализации» перенесено в `Ограничения использования`, добавлена колонка `Example file`. |
97
+ | 2026-07-08 | Актуализирована таблица Stories: story `Disabled` заменена на `States` (`StatesExample.tsx`). |
98
+
99
+ ---
100
+
101
+ ## Примеры использования
102
+
103
+ ### Default
104
+
105
+ `stories/Buttons/examples/ButtonIcon/DefaultExample.tsx`
106
+
107
+ ```tsx
108
+ import React from "react";
109
+ import { DefaulticonStrokePrdIcon32 } from "@sberbusiness/icons-next";
110
+ import { ButtonIcon, EButtonIconShape } from "@sberbusiness/triplex-next";
111
+
112
+ export const DefaultExample = () => (
113
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE}>
114
+ <DefaulticonStrokePrdIcon32 paletteIndex={5} />
115
+ </ButtonIcon>
116
+ );
117
+ ```
118
+
119
+ ### Sizes
120
+
121
+ `stories/Buttons/examples/ButtonIcon/SizesExample.tsx`
122
+
123
+ ```tsx
124
+ import React from "react";
125
+ import {
126
+ DefaulticonStrokePrdIcon16,
127
+ DefaulticonStrokePrdIcon20,
128
+ DefaulticonStrokePrdIcon24,
129
+ DefaulticonStrokePrdIcon32,
130
+ } from "@sberbusiness/icons-next";
131
+ import { ButtonIcon, EButtonIconShape } from "@sberbusiness/triplex-next";
132
+
133
+ export const SizesExample = () => (
134
+ <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
135
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE}>
136
+ <DefaulticonStrokePrdIcon16 paletteIndex={5} />
137
+ </ButtonIcon>
138
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE}>
139
+ <DefaulticonStrokePrdIcon20 paletteIndex={5} />
140
+ </ButtonIcon>
141
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE}>
142
+ <DefaulticonStrokePrdIcon24 paletteIndex={5} />
143
+ </ButtonIcon>
144
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE}>
145
+ <DefaulticonStrokePrdIcon32 paletteIndex={5} />
146
+ </ButtonIcon>
147
+ </div>
148
+ );
149
+ ```
150
+
151
+ ### States
152
+
153
+ `stories/Buttons/examples/ButtonIcon/StatesExample.tsx`
154
+
155
+ ```tsx
156
+ import React from "react";
157
+ import { DefaulticonStrokePrdIcon32 } from "@sberbusiness/icons-next";
158
+ import { ButtonIcon, EButtonIconShape } from "@sberbusiness/triplex-next";
159
+
160
+ export const StatesExample = () => (
161
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
162
+ <div style={{ display: "flex", flexDirection: "column", alignItems: "start", gap: "8px" }}>
163
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>Active</div>
164
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE} active>
165
+ <DefaulticonStrokePrdIcon32 paletteIndex={5} />
166
+ </ButtonIcon>
167
+ </div>
168
+
169
+ <div style={{ display: "flex", flexDirection: "column", alignItems: "start", gap: "8px" }}>
170
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>Disabled</div>
171
+ <ButtonIcon shape={EButtonIconShape.SQUIRCLE} disabled>
172
+ <DefaulticonStrokePrdIcon32 paletteIndex={5} />
173
+ </ButtonIcon>
174
+ </div>
175
+ </div>
176
+ );
177
+ ```
178
+