@sberbusiness/triplex-next-mcp-server 0.24.0-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +124 -0
  2. package/bundle/.gitkeep +0 -0
  3. package/bundle/components/AbstractTree.md +198 -0
  4. package/bundle/components/AccordionBase.md +227 -0
  5. package/bundle/components/Alert.md +317 -0
  6. package/bundle/components/Amount.md +225 -0
  7. package/bundle/components/AmountField.md +289 -0
  8. package/bundle/components/Avatar.md +209 -0
  9. package/bundle/components/Badge.md +277 -0
  10. package/bundle/components/Body.md +167 -0
  11. package/bundle/components/Button.md +230 -0
  12. package/bundle/components/ButtonDropdown.md +159 -0
  13. package/bundle/components/ButtonIcon.md +122 -0
  14. package/bundle/components/Calendar.md +445 -0
  15. package/bundle/components/Card.md +374 -0
  16. package/bundle/components/CarouselExtended.md +250 -0
  17. package/bundle/components/Checkbox.md +126 -0
  18. package/bundle/components/CheckboxTree.md +280 -0
  19. package/bundle/components/CheckboxTreeExtended.md +321 -0
  20. package/bundle/components/CheckboxXGroup.md +68 -0
  21. package/bundle/components/CheckboxYGroup.md +67 -0
  22. package/bundle/components/Chip.md +404 -0
  23. package/bundle/components/ChipGroup.md +179 -0
  24. package/bundle/components/Col.md +221 -0
  25. package/bundle/components/CollapsableTree.md +255 -0
  26. package/bundle/components/Confirm.md +343 -0
  27. package/bundle/components/DateField.md +371 -0
  28. package/bundle/components/DatePickerExtended.md +342 -0
  29. package/bundle/components/DateRange.md +275 -0
  30. package/bundle/components/DesignTokens.md +385 -0
  31. package/bundle/components/Divider.md +196 -0
  32. package/bundle/components/DocumentNumberEdit.md +280 -0
  33. package/bundle/components/Dropdown.md +433 -0
  34. package/bundle/components/Ellipsis.md +208 -0
  35. package/bundle/components/EmptyView.md +99 -0
  36. package/bundle/components/ExpandAnimation.md +281 -0
  37. package/bundle/components/Footer.md +339 -0
  38. package/bundle/components/FormField.md +326 -0
  39. package/bundle/components/FormGroup.md +99 -0
  40. package/bundle/components/Gap.md +113 -0
  41. package/bundle/components/Header.md +280 -0
  42. package/bundle/components/HelpBox.md +154 -0
  43. package/bundle/components/IconWrapper.md +145 -0
  44. package/bundle/components/Island.md +197 -0
  45. package/bundle/components/IslandAccordion.md +230 -0
  46. package/bundle/components/IslandWidget.md +233 -0
  47. package/bundle/components/KeyDownListener.md +157 -0
  48. package/bundle/components/LightBox.md +322 -0
  49. package/bundle/components/Link.md +161 -0
  50. package/bundle/components/List.md +247 -0
  51. package/bundle/components/ListMaster.md +204 -0
  52. package/bundle/components/Loader.md +161 -0
  53. package/bundle/components/LoaderScreen.md +134 -0
  54. package/bundle/components/Marker.md +127 -0
  55. package/bundle/components/MarkerStatus.md +148 -0
  56. package/bundle/components/MediaWidth.md +169 -0
  57. package/bundle/components/MobileView.md +120 -0
  58. package/bundle/components/ModalWindow.md +308 -0
  59. package/bundle/components/MonthYearField.md +168 -0
  60. package/bundle/components/MultiselectField.md +213 -0
  61. package/bundle/components/Notification.md +233 -0
  62. package/bundle/components/NumberField.md +178 -0
  63. package/bundle/components/OrderedList.md +169 -0
  64. package/bundle/components/Overlay.md +237 -0
  65. package/bundle/components/Page.md +246 -0
  66. package/bundle/components/Pagination.md +298 -0
  67. package/bundle/components/Portal.md +119 -0
  68. package/bundle/components/Radio.md +174 -0
  69. package/bundle/components/Row.md +125 -0
  70. package/bundle/components/SMSField.md +160 -0
  71. package/bundle/components/SegmentedControl.md +235 -0
  72. package/bundle/components/SelectExtendedField.md +322 -0
  73. package/bundle/components/SelectField.md +213 -0
  74. package/bundle/components/Skeleton.md +129 -0
  75. package/bundle/components/Slider.md +157 -0
  76. package/bundle/components/SliderExtended.md +210 -0
  77. package/bundle/components/SliderRange.md +160 -0
  78. package/bundle/components/SmallInput.md +101 -0
  79. package/bundle/components/Spoiler.md +121 -0
  80. package/bundle/components/StatusTracker.md +151 -0
  81. package/bundle/components/Step.md +121 -0
  82. package/bundle/components/Stepper.md +163 -0
  83. package/bundle/components/Suggest.md +160 -0
  84. package/bundle/components/SuggestField.md +157 -0
  85. package/bundle/components/SwipeableArea.md +144 -0
  86. package/bundle/components/Table.md +199 -0
  87. package/bundle/components/Tabs.md +152 -0
  88. package/bundle/components/TabsExtended.md +273 -0
  89. package/bundle/components/TabsLine.md +189 -0
  90. package/bundle/components/Tag.md +135 -0
  91. package/bundle/components/TagColor.md +121 -0
  92. package/bundle/components/TagGroup.md +100 -0
  93. package/bundle/components/TextField.md +152 -0
  94. package/bundle/components/TextareaField.md +124 -0
  95. package/bundle/components/ThemeProvider.md +181 -0
  96. package/bundle/components/Tooltip.md +254 -0
  97. package/bundle/components/TopOverlay.md +145 -0
  98. package/bundle/components/TreeView.md +224 -0
  99. package/bundle/components/Triggers.md +121 -0
  100. package/bundle/guides/codestyle.md +205 -0
  101. package/bundle/guides/commits.md +166 -0
  102. package/bundle/guides/context.md +277 -0
  103. package/bundle/guides/stories.md +618 -0
  104. package/bundle/guides/template.md +154 -0
  105. package/bundle/guides/tests.md +301 -0
  106. package/bundle/icons.json +4156 -0
  107. package/bundle/manifest.json +796 -0
  108. package/bundle/release-notes/1.1.0.mdx +26 -0
  109. package/bundle/release-notes/1.1.1.mdx +14 -0
  110. package/bundle/release-notes/1.10.0.mdx +43 -0
  111. package/bundle/release-notes/1.11.0.mdx +19 -0
  112. package/bundle/release-notes/1.12.0.mdx +21 -0
  113. package/bundle/release-notes/1.13.0.mdx +43 -0
  114. package/bundle/release-notes/1.14.0.mdx +29 -0
  115. package/bundle/release-notes/1.15.0.mdx +56 -0
  116. package/bundle/release-notes/1.16.0.mdx +55 -0
  117. package/bundle/release-notes/1.17.0.mdx +15 -0
  118. package/bundle/release-notes/1.18.0.mdx +24 -0
  119. package/bundle/release-notes/1.19.0.mdx +48 -0
  120. package/bundle/release-notes/1.19.1.mdx +9 -0
  121. package/bundle/release-notes/1.2.0.mdx +80 -0
  122. package/bundle/release-notes/1.20.0.mdx +48 -0
  123. package/bundle/release-notes/1.21.0.mdx +66 -0
  124. package/bundle/release-notes/1.22.0.mdx +75 -0
  125. package/bundle/release-notes/1.23.0.mdx +50 -0
  126. package/bundle/release-notes/1.24.0.mdx +59 -0
  127. package/bundle/release-notes/1.25.0.mdx +52 -0
  128. package/bundle/release-notes/1.26.0.mdx +11 -0
  129. package/bundle/release-notes/1.3.0.mdx +21 -0
  130. package/bundle/release-notes/1.4.0.mdx +37 -0
  131. package/bundle/release-notes/1.5.0.mdx +24 -0
  132. package/bundle/release-notes/1.6.0.mdx +37 -0
  133. package/bundle/release-notes/1.6.1.mdx +11 -0
  134. package/bundle/release-notes/1.7.0.mdx +29 -0
  135. package/bundle/release-notes/1.8.0.mdx +38 -0
  136. package/bundle/release-notes/1.9.0.mdx +28 -0
  137. package/dist/index.d.ts +2 -0
  138. package/dist/index.js +324 -0
  139. package/dist/index.js.map +1 -0
  140. package/package.json +51 -0
@@ -0,0 +1,277 @@
1
+ ---
2
+ component: Badge
3
+ category: Badges
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [Avatar, Chip, Tag, MarkerStatus]
7
+ tokens:
8
+ - --triplex-next-Badge-Background
9
+ stories: stories/Badge/Badge.stories.tsx
10
+ version: "1.0"
11
+ ---
12
+
13
+ # Badge
14
+
15
+ ## Назначение
16
+
17
+ Индикатор статуса или уведомления в виде горизонтальной "таблетки" с опциональным
18
+ префиксом, контентом и постфиксом. Имеет три размера (SM / MD / LG), которые
19
+ соответствуют общей шкале компонентов библиотеки (`EComponentSize`).
20
+
21
+ Сопутствующий `Badge.Dot` — точечный вариант (круг) для минималистичных
22
+ индикаторов (например, "есть непрочитанное"). Badge и BadgeDot — два независимых
23
+ компонента под одним barrel-экспортом.
24
+
25
+ Используй `Badge` когда: нужна краткая метка статуса/счётчика с текстом или
26
+ иконкой ("NEW", "12", "Beta").
27
+ Используй `Badge.Dot` когда: нужен просто цветной кружок без текста.
28
+ Не используй когда: нужен удаляемый тег с текстом (используй `Chip` или `Tag`);
29
+ нужен большой статус-блок с описанием (используй `MarkerStatus`).
30
+
31
+ ---
32
+
33
+ ## Файловая структура
34
+
35
+ ```text
36
+ src/components/Badge/
37
+ ├── Badge.tsx # React.forwardRef, compound: Badge + Badge.Dot
38
+ ├── BadgeDot.tsx # React.forwardRef, отдельный компонент (не subcomponent)
39
+ ├── types.ts # IBadgeProps, IBadgeDotProps, IBadgeContentProps
40
+ ├── index.ts # Barrel: types + Badge (+ Badge.Dot через compound)
41
+ ├── styles/
42
+ │ ├── Badge.module.less # Root .badge (SM/MD/LG: height + border-radius)
43
+ │ └── BadgeDot.module.less # Root .badgeDot (SM/MD/LG: width+height, border-radius 50%)
44
+ ├── components/ # Внутренние subcomponents (не экспортируются)
45
+ │ ├── BadgeContent.tsx # React.FC с паддингами по size
46
+ │ ├── BadgePrefix.tsx # React.FC, display: contents (не создаёт DOM-слоя)
47
+ │ ├── BadgePostfix.tsx # React.FC, display: contents
48
+ │ └── styles/
49
+ │ ├── BadgeContent.module.less # Паддинги SM=4px / MD=6px / LG=8px + noPaddingLeft/Right
50
+ │ ├── BadgePrefix.module.less # display: contents
51
+ │ └── BadgePostfix.module.less # display: contents
52
+ └── tests/Badge.test.tsx
53
+ ```
54
+
55
+ Особенности:
56
+ - **`Badge` + `Badge.Dot` через `Object.assign`** — compound-паттерн, как у
57
+ `AlertProcess`. BadgeDot также экспортирован из `index.ts` (через `./Badge`),
58
+ но рекомендуемый путь — через `Badge.Dot`.
59
+ - **`prefix`/`postfix` через `display: contents`** — обёртки не добавляют визуального
60
+ слоя, являются только семантическими якорями для DOM-тестов.
61
+ - **`components/` папка** — прямо не экспортируется, subcomponents видны только Badge.
62
+
63
+ ---
64
+
65
+ ## Варианты и props
66
+
67
+ ### `IBadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "prefix" | "postfix">`
68
+
69
+ **Важно:** `prefix` и `postfix` НЕ стандартные HTML-атрибуты — они переопределены
70
+ через `Omit` и изменяют семантику.
71
+
72
+ | Prop | Тип | Обязателен | Описание |
73
+ |---|---|---|---|
74
+ | `size` | `EComponentSize` (`SM`, `MD`, `LG`) | Да | Определяет высоту (16/20/24px), border-radius и внутренние паддинги. |
75
+ | `children` | `React.ReactNode` | Нет | Основной контент (текст/иконка/число). Если не передан — рендерится только prefix+postfix. |
76
+ | `prefix` | `React.ReactNode` | Нет | Обычно иконка слева. При наличии — у BadgeContent убирается `padding-left`. |
77
+ | `postfix` | `React.ReactNode` | Нет | Обычно иконка или мини-кнопка справа. При наличии — у BadgeContent убирается `padding-right`. |
78
+ | `className` | `string` | Нет | Объединяется с `styles.badge + sizeClass`. |
79
+ | `...HTMLSpanAttributes` | — | — | Всё остальное, кроме `prefix`/`postfix`. |
80
+
81
+ ### `IBadgeDotProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children">`
82
+
83
+ | Prop | Тип | Обязателен | Описание |
84
+ |---|---|---|---|
85
+ | `size` | `EComponentSize` | Да | Диаметр точки: SM=6px, MD=8px, LG=10px. |
86
+ | `children` | `never` | — | Явно запрещено через `never` — точка без контента. |
87
+ | `className` | `string` | Нет | Объединяется с `styles.badgeDot + sizeClass`. |
88
+ | `...HTMLSpanAttributes` | — | — | Стандартные атрибуты `<span>`. |
89
+
90
+ ### Размеры
91
+
92
+ **Badge (горизонтальная плашка):**
93
+
94
+ | size | Height | Border-radius | Content padding-x |
95
+ |---|---|---|---|
96
+ | `SM` | 16px | 4px | 4px |
97
+ | `MD` | 20px | 6px | 6px |
98
+ | `LG` | 24px | 8px | 8px |
99
+
100
+ **Badge.Dot (круг):**
101
+
102
+ | size | Diameter |
103
+ |---|---|
104
+ | `SM` | 6px |
105
+ | `MD` | 8px |
106
+ | `LG` | 10px |
107
+
108
+ ---
109
+
110
+ ## Ключевые особенности реализации
111
+
112
+ ### `createSizeToClassNameMap` вместо локального маппинга
113
+
114
+ ```ts
115
+ const SIZE_TO_CLASS_NAME_MAP = createSizeToClassNameMap(styles);
116
+ ```
117
+
118
+ Утилита `src/utils/classNameMaps.ts` возвращает `{ [SM]: styles.sm, [MD]: styles.md, [LG]: styles.lg }`.
119
+ Используется во всех Badge-файлах (`Badge.tsx`, `BadgeDot.tsx`, `BadgeContent.tsx`).
120
+ Это единый паттерн — не дублировать маппинг локально.
121
+
122
+ Если понадобится новый размер (XS, XL) — обновлять **и** `EComponentSize`, **и**
123
+ `createSizeToClassNameMap`, **и** LESS-файлы. Помни: `createSizeToClassNameMap`
124
+ типизирован как `Record<EComponentSize, string>` — TypeScript заставит добавить
125
+ ключ.
126
+
127
+ ### `Omit<HTMLAttributes, "prefix" | "postfix">` — реальная проблема
128
+
129
+ HTML-атрибут `prefix` (устаревший, для RDFa) существует на некоторых тегах.
130
+ TypeScript не распознаёт его на `<span>`, но React.HTMLAttributes включает его
131
+ через dom-типы. Без `Omit` prop `prefix` компонента конфликтует с HTML-атрибутом
132
+ в типах. Не удалять Omit.
133
+
134
+ ### `BadgePrefix` / `BadgePostfix` — `display: contents`
135
+
136
+ ```less
137
+ .badgePrefix { display: contents; }
138
+ .badgePostfix { display: contents; }
139
+ ```
140
+
141
+ Обёртка не создаёт box — её children рендерятся так, как будто `<span>`
142
+ вообще нет, но в DOM он есть. Это позволяет:
143
+ - Применять семантический класс для тестов.
144
+ - Не нарушать flex-лейаут родителя.
145
+ - Не добавлять лишних паддингов.
146
+
147
+ **`display: contents` имеет a11y-баг в Safari <14** — он убирает роль элемента
148
+ для screen reader. Для `<span>` без семантической роли это не проблема, но помни
149
+ при расширении (не добавлять `role="button"` на BadgePrefix без тестирования).
150
+
151
+ ### `BadgeContent` убирает паддинги при наличии prefix/postfix
152
+
153
+ ```tsx
154
+ <BadgeContent
155
+ size={size}
156
+ noPaddingLeft={Boolean(prefix)}
157
+ noPaddingRight={Boolean(postfix)}
158
+ >
159
+ ```
160
+
161
+ Это делает `prefix/postfix` "приклеенными" к контенту без двойного отступа. Если
162
+ пишешь новый subcomponent внутри Badge — следуй этому паттерну (не добавляй
163
+ горизонтальные паддинги на subcomponent-уровне, только на BadgeContent).
164
+
165
+ ### Compound `Badge.Dot`
166
+
167
+ ```ts
168
+ export const Badge = Object.assign(
169
+ React.forwardRef<HTMLSpanElement, IBadgeProps>(...),
170
+ { Dot: BadgeDot },
171
+ );
172
+ ```
173
+
174
+ Тот же паттерн, что у `AlertProcess.Spoiler`. Одновременно `BadgeDot` экспортируется
175
+ из `index.ts` через `./Badge` напрямую, но **рекомендуемое использование** —
176
+ через `Badge.Dot` (единый API).
177
+
178
+ ### Один цветовой токен на оба
179
+
180
+ `--triplex-next-Badge-Background` используется и для Badge, и для BadgeDot. Нет
181
+ отдельного токена для `BadgeDot-Background` — оба разделяют цвет. Если нужны
182
+ разные цвета (например, зелёная точка при сером Badge) — потребитель
183
+ переопределяет через `style`/`className`.
184
+
185
+ ---
186
+
187
+ ## Инварианты
188
+
189
+ - **`forwardRef`** — обязателен на Badge и BadgeDot. Не убирать.
190
+ - **`size` обязателен** — без default value, чтобы потребитель явно выбирал масштаб.
191
+ - **`EComponentSize`** — общий enum из `src/enums/EComponentSize`, не делай
192
+ локальный аналог. Badge входит в семейство компонентов, использующих единый
193
+ SM/MD/LG.
194
+ - **`BadgeDot.children: never`** — не превращать в обычный slot. Компонент
195
+ намеренно пустой.
196
+ - **`Omit<HTMLAttributes, "prefix" | "postfix">`** — не убирать, конфликт типов.
197
+ - **`display: contents` в BadgePrefix/BadgePostfix** — не менять на `inline-flex`.
198
+ Меняет лейаут и ломает `noPaddingLeft/Right` логику в BadgeContent.
199
+ - **`Badge.Dot` через Object.assign** — не убирать, потребители импортируют
200
+ через compound.
201
+ - **Background-токен един** для Badge и BadgeDot — не разделять без согласования
202
+ с дизайнером.
203
+ - **`white-space: nowrap`** на Badge — не убирать, иначе длинный контент ломается
204
+ на несколько строк и разваливает высоту.
205
+ - **BadgeContent/Prefix/Postfix — внутренние** — не экспортировать через barrel.
206
+ Потребители используют только `prefix`/`postfix` props.
207
+
208
+ ---
209
+
210
+ ## Accessibility
211
+
212
+ - **Никаких ARIA-ролей по умолчанию** — Badge семантически нейтрален. Если
213
+ Badge отображает число непрочитанных сообщений — потребитель обязан обеспечить
214
+ озвучку: `aria-label="5 непрочитанных сообщений"` или `role="status"`.
215
+ - **Для статусного Badge** (например, "Online") — потребитель должен добавить
216
+ `role="status"` и `aria-label` / `title`, иначе screen reader прочитает только
217
+ визуальный текст, без контекста.
218
+ - **BadgeDot** — чистая визуальная точка без текста. **Обязан** получать
219
+ `aria-label` от потребителя, иначе не воспринимается screen reader'ом. Или,
220
+ если это чисто декоративный индикатор рядом с другим текстом — `aria-hidden="true"`.
221
+ - **`display: contents`** на prefix/postfix — в современных браузерах не ломает
222
+ a11y, но в Safari <14 может. Если поддержка старого Safari критична, делай
223
+ тесты.
224
+
225
+ ---
226
+
227
+ ## Дизайн-токены
228
+
229
+ ```
230
+ --triplex-next-Badge-Background # Фон Badge и BadgeDot (единый токен)
231
+ ```
232
+
233
+ Цвет текста внутри Badge определяется `color: inherit` от родителя (нет явного
234
+ токена) — потребитель задаёт цвет через `Typography`-компоненты или `style`.
235
+
236
+ Высоты, радиусы, паддинги, размеры точки — жёсткие значения в LESS, не токенизированы.
237
+ Кандидат на рефакторинг при общей токенизации размеров.
238
+
239
+ ---
240
+
241
+ ## Связанные компоненты
242
+
243
+ - `Avatar` (`src/components/Avatar`) — часто комбинируется с Badge: Badge на углу
244
+ Avatar как индикатор статуса. Позиционирование — задача потребителя.
245
+ - `Chip` (`src/components/Chip`) — "большой Badge" с возможностью закрытия и
246
+ интерактивностью. Разная семантика: Badge = индикатор, Chip = тег.
247
+ - `Tag` / `TagColor` / `TagGroup` (`src/components/Tag`) — ещё больший уровень:
248
+ стилизованные метки категорий с цветами.
249
+ - `MarkerStatus` (`src/components/MarkerStatus`) — крупный блок статуса с иконкой
250
+ и текстом (тип сообщения).
251
+ - `EComponentSize` (`src/enums/EComponentSize`) — общий enum трёх размеров.
252
+ - `createSizeToClassNameMap` (`src/utils/classNameMaps.ts`) — утилита
253
+ размер → class.
254
+
255
+ ---
256
+
257
+ ## Stories
258
+
259
+ `stories/Badge/Badge.stories.tsx`
260
+ Файлы примеров: `stories/Badge/examples/`
261
+
262
+ | Story | Example file | Что демонстрирует |
263
+ |---|---|---|
264
+ | `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль `size` |
265
+ | `Default` | `DefaultExample.tsx` | Базовое использование |
266
+ | `Sizes` | `SizesExample.tsx` | Все три размера Badge |
267
+ | `WithPrefixAndPostfix` | `WithPrefixAndPostfixExample.tsx` | Badge с иконкой слева и/или справа |
268
+ | `DotSizes` | `DotSizesExample.tsx` | Три размера Badge.Dot |
269
+ | `Example` | `ProductionExample.tsx` | Реальные кейсы композиции |
270
+
271
+ ---
272
+
273
+ ## История изменений
274
+
275
+ | Дата | Изменение |
276
+ |---|---|
277
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,167 @@
1
+ ---
2
+ component: Body
3
+ category: Layout
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [Page, Header, Footer]
7
+ tokens: []
8
+ stories: ""
9
+ version: "1.0"
10
+ ---
11
+
12
+ # Body
13
+
14
+ ## Назначение
15
+
16
+ Минимальный layout-контейнер для содержимого страницы. Создаёт двухуровневую
17
+ структуру `<div>` (root + inner) с `display: flex` и `flex-grow: 1` на inner,
18
+ что позволяет контенту растягиваться на всю доступную высоту.
19
+
20
+ В текущей архитектуре `Body` — примитив, используемый внутри `BodyPage`
21
+ (экспортируется как `Page.Body` в stories). Как самостоятельный публичный
22
+ компонент применяется редко — чаще через `Page.Body` с дополнительными
23
+ props (`type`, `verticalMargin`).
24
+
25
+ Используй когда: собираешь кастомный layout страницы и хочешь переиспользовать
26
+ flex-обёртку без привязки к Page.
27
+ Не используй когда: строишь страницу по стандартному паттерну — бери `Page.Body`,
28
+ там уже есть Island, verticalMargin и поддержка типов.
29
+
30
+ ---
31
+
32
+ ## Файловая структура
33
+
34
+ ```text
35
+ src/components/Body/
36
+ ├── Body.tsx # React.forwardRef, thin wrapper
37
+ ├── index.ts # Barrel
38
+ ├── styles/Body.module.less # .body (flex) + .bodyInner (flex-grow: 1)
39
+ └── __tests__/Body.test.tsx
40
+ ```
41
+
42
+ Особенности:
43
+ - Нет LESS-токенов — компонент чисто структурный.
44
+ - **Нет собственных stories** — документируется косвенно через `Page.Body`
45
+ (stories/Page/BodyPage.stories.tsx).
46
+ - **Импорт через публичный путь, а не через `../Body`**: в `BodyPage.tsx` путь
47
+ `@sberbusiness/triplex-next/components/Body/Body` — это сохранено намеренно,
48
+ paths-alias для работы в монорепозитории потребителей.
49
+
50
+ ---
51
+
52
+ ## Варианты и props
53
+
54
+ ### `IBodyProps extends React.HTMLAttributes<HTMLDivElement>`
55
+
56
+ Интерфейс пустой — используется наследование от HTMLAttributes как есть.
57
+
58
+ | Prop | Тип | Описание |
59
+ |---|---|---|
60
+ | `children` | `React.ReactNode` | Контент, рендерится внутри inner-div. |
61
+ | `className` | `string` | Объединяется с `.body` через `clsx`. |
62
+ | `...HTMLDivAttributes` | — | Всё стандартное для `<div>`. |
63
+
64
+ ---
65
+
66
+ ## Ключевые особенности реализации
67
+
68
+ ### Двухуровневая обёртка
69
+
70
+ ```tsx
71
+ <div className={clsx(styles.body, className)} {...rest} data-tx={...} ref={ref}>
72
+ <div className={styles.bodyInner}>{children}</div>
73
+ </div>
74
+ ```
75
+
76
+ Root — `display: flex; position: relative`. Inner — `flex-grow: 1; width: 100%;
77
+ position: relative`. Двойной уровень нужен, чтобы:
78
+ - Root мог получать `className` и event handler'ы от потребителя без поломки
79
+ flex-layout.
80
+ - Inner гарантированно занимал всю ширину/высоту, что критично для корректного
81
+ позиционирования абсолютных потомков (position: relative на обоих уровнях).
82
+
83
+ ### ref идёт на root
84
+
85
+ `forwardRef` прокидывает ref на **внешний div**, не на inner. Это сохраняет
86
+ стабильный контракт (ref → тот же DOM-элемент, что получает className и spread
87
+ props).
88
+
89
+ ### `data-tx` только на root
90
+
91
+ Версия пакета ставится только на внешний div — второй раз на inner не нужен.
92
+
93
+ ### Пустой интерфейс `IBodyProps`
94
+
95
+ ```tsx
96
+ export interface IBodyProps extends React.HTMLAttributes<HTMLDivElement> {}
97
+ ```
98
+
99
+ ESLint может предлагать заменить на type-alias `type IBodyProps = React.HTMLAttributes<HTMLDivElement>`,
100
+ но `interface` сохранён для возможности расширения в будущем (например, если
101
+ потребуется добавить `verticalMargin` на уровень Body, а не BodyPage). Не
102
+ переписывать на type.
103
+
104
+ ---
105
+
106
+ ## Инварианты
107
+
108
+ - **`forwardRef`** — обязателен. Ref идёт на root div.
109
+ - **`data-tx={process.env.npm_package_version}`** — не удалять (версия для
110
+ отладки).
111
+ - **Двухуровневая структура (`.body` → `.bodyInner`)** — не схлопывать в один
112
+ div. От этого зависит lafyut-контракт потребителей, особенно `BodyPage`
113
+ (он оборачивает Body в Island для типа FIRST).
114
+ - **`position: relative` на обоих уровнях** — не убирать. Потребители могут
115
+ полагаться на то, что абсолютно спозиционированные элементы привязаны к
116
+ этим контейнерам.
117
+ - **`flex-grow: 1` на inner** — не убирать. Обеспечивает поведение "body
118
+ занимает всё доступное место по высоте".
119
+ - **`IBodyProps` как interface (не type)** — сохранить для будущего расширения.
120
+ - **Нет своих дизайн-токенов** — не добавлять без согласования (компонент
121
+ намеренно стилистически нейтрален, цвет/шрифт/отступы задаёт потребитель
122
+ или родитель).
123
+
124
+ ---
125
+
126
+ ## Accessibility
127
+
128
+ - **Нет собственной ARIA-роли** — `<div>` семантически нейтрален. Если нужна
129
+ semantic main-область — потребитель передаёт `role="main"` через `...rest`
130
+ или использует `<main>` как обёртку снаружи.
131
+ - **Не перехватывает фокус, не манипулирует tabindex** — полностью прозрачен
132
+ для навигации.
133
+
134
+ ---
135
+
136
+ ## Дизайн-токены
137
+
138
+ Нет — компонент структурный, без визуального оформления.
139
+
140
+ ---
141
+
142
+ ## Связанные компоненты
143
+
144
+ - `Page` (`src/components/Page`) — страничный layout. Содержит Header / Body /
145
+ Footer как compound-пропсы.
146
+ - `BodyPage` / `Page.Body` (`src/components/Page/components/BodyPage.tsx`) —
147
+ расширенный Body с поддержкой `type` (FIRST/SECOND), `verticalMargin`,
148
+ опциональной обёрткой в Island. В большинстве сценариев потребитель использует
149
+ Page.Body, а не Body напрямую.
150
+ - `Header` / `Page.Header`, `Footer` / `Page.Footer` — соседние компоненты страницы.
151
+ - `Island` (`src/components/Island`) — используется внутри `Page.Body` типа FIRST,
152
+ даёт body карточное оформление.
153
+
154
+ ---
155
+
156
+ ## Stories
157
+
158
+ Отдельных stories нет. Поведение Body показано через `Page.Body` в
159
+ `stories/Page/BodyPage.stories.tsx` с вариациями `type` и `verticalMargin`.
160
+
161
+ ---
162
+
163
+ ## История изменений
164
+
165
+ | Дата | Изменение |
166
+ |---|---|
167
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,230 @@
1
+ ---
2
+ component: Button
3
+ category: Buttons
4
+ figma-node: "1-328"
5
+ figma-file: "https://www.figma.com/design/MeAqaaLV9acAgoBOkZC9C2/-W--LIB-DSN-01-Components-DCB-Next-v.1.3.0"
6
+ related: [ButtonIcon, ButtonDropdown, ButtonDropdownExtended]
7
+ tokens:
8
+ - --triplex-next-Button-General_Background_Default
9
+ - --triplex-next-Button-General_Color_Default
10
+ - --triplex-next-Button-General_Background_Hover
11
+ - --triplex-next-Button-General_Color_Hover
12
+ - --triplex-next-Button-General_Background_Active
13
+ - --triplex-next-Button-General_Color_Active
14
+ - --triplex-next-Button-General_Shadow_Focus
15
+ - --triplex-next-Button-General_Background_Disabled
16
+ - --triplex-next-Button-General_Color_Disabled
17
+ - --triplex-next-Button-Secondary_Background_Default
18
+ - --triplex-next-Button-Secondary_Color_Default
19
+ - --triplex-next-Button-Secondary_Background_Hover
20
+ - --triplex-next-Button-Secondary_Color_Hover
21
+ - --triplex-next-Button-Secondary_Background_Active
22
+ - --triplex-next-Button-Secondary_Color_Active
23
+ - --triplex-next-Button-Secondary_Shadow_Focus
24
+ - --triplex-next-Button-Secondary_Background_Disabled
25
+ - --triplex-next-Button-Secondary_Color_Disabled
26
+ - --triplex-next-Button-SecondaryLight_Background_Default
27
+ - --triplex-next-Button-SecondaryLight_Color_Default
28
+ - --triplex-next-Button-SecondaryLight_Background_Hover
29
+ - --triplex-next-Button-SecondaryLight_Color_Hover
30
+ - --triplex-next-Button-SecondaryLight_Background_Active
31
+ - --triplex-next-Button-SecondaryLight_Color_Active
32
+ - --triplex-next-Button-SecondaryLight_Shadow_Focus
33
+ - --triplex-next-Button-SecondaryLight_Background_Disabled
34
+ - --triplex-next-Button-SecondaryLight_Color_Disabled
35
+ - --triplex-next-Button-Danger_Background_Default
36
+ - --triplex-next-Button-Danger_Color_Default
37
+ - --triplex-next-Button-Danger_Background_Hover
38
+ - --triplex-next-Button-Danger_Color_Hover
39
+ - --triplex-next-Button-Danger_Background_Active
40
+ - --triplex-next-Button-Danger_Color_Active
41
+ - --triplex-next-Button-Danger_Shadow_Focus
42
+ - --triplex-next-Button-Danger_Background_Disabled
43
+ - --triplex-next-Button-Danger_Color_Disabled
44
+ - --triplex-next-Button-Link_Color_Default
45
+ - --triplex-next-Button-Link_Color_Hover
46
+ - --triplex-next-Button-Link_Color_Active
47
+ - --triplex-next-Button-Link_Shadow_Focus
48
+ - --triplex-next-Button-Link_Color_Disabled
49
+ - --triplex-next-Button-Icon_Shadow_Focus
50
+ stories: stories/Buttons/Button.stories.tsx
51
+ version: "1.0"
52
+ ---
53
+
54
+ # Button
55
+
56
+ ## Назначение
57
+
58
+ Основной интерактивный элемент для запуска действий. Существует в пяти визуальных темах
59
+ и трёх размерах. Поддерживает состояния загрузки, иконки и полноширинный режим.
60
+
61
+ Используй `Button` когда: нужна кнопка с текстом (с иконкой или без).
62
+ Используй `ButtonIcon` когда: нужна кнопка только с иконкой без текста.
63
+ Используй `ButtonDropdown` когда: нужен выбор из нескольких действий.
64
+
65
+ ---
66
+
67
+ ## Файловая структура
68
+
69
+ ```text
70
+ src/components/Button/
71
+ ├── Button.tsx # Основной компонент, union type TButtonProps
72
+ ├── ButtonBase.tsx # Базовый <button>, extends HTML attrs
73
+ ├── ButtonIcon.tsx # Иконочная кнопка (squircle / circle)
74
+ ├── ButtonDropdown.tsx # Кнопка с выпадающим меню
75
+ ├── ButtonDropdownExtended.tsx # Контейнер с кастомным dropdown
76
+ ├── enums.ts # EButtonTheme, EButtonDotsTheme, EButtonIconShape
77
+ ├── index.ts # Barrel exports
78
+ └── styles/
79
+ ├── Button.module.less # Размеры, block, loading, base layout
80
+ ├── ButtonGeneral.module.less # Тема GENERAL
81
+ ├── ButtonSecondary.module.less
82
+ ├── ButtonSecondaryLight.module.less
83
+ ├── ButtonDanger.module.less
84
+ ├── ButtonLink.module.less # Тема LINK — нет min-width, нет bg
85
+ ├── ButtonIcon.module.less # Стили ButtonIcon
86
+ ├── ButtonDropdown.module.less
87
+ └── ButtonDropdownExtended.module.less
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Варианты и props
93
+
94
+ ### Темы (`EButtonTheme`)
95
+
96
+ | Значение | Описание | Поддерживает loading/icon/block |
97
+ |---|---|---|
98
+ | `GENERAL` | Основной стиль (primary) | Да |
99
+ | `SECONDARY` | Вторичный | Да |
100
+ | `SECONDARY_LIGHT` | Вторичный светлый (для тёмных фонов) | Да |
101
+ | `DANGER` | Деструктивное действие | Да |
102
+ | `LINK` | Текстовая ссылка | Нет — `loading`, `icon`, `block` запрещены через `never` |
103
+
104
+ ### Размеры (`EComponentSize`)
105
+
106
+ | Значение | Высота | Padding | Border-radius | Font-size |
107
+ |---|---|---|---|---|
108
+ | `SM` | 28px | 0 12px | 6px | 12px |
109
+ | `MD` | 40px | 0 20px | 8px | 14px |
110
+ | `LG` | 56px | 0 24px | 10px | 16px |
111
+
112
+ ### Props компонента `Button`
113
+
114
+ | Prop | Тип | Обязателен | Описание |
115
+ |---|---|---|---|
116
+ | `theme` | `EButtonTheme` | Да | Визуальный стиль |
117
+ | `size` | `EComponentSize` | Да | Размер |
118
+ | `block` | `boolean` | Нет | Полноширинный режим (только не-LINK темы) |
119
+ | `loading` | `boolean` | Нет | Состояние загрузки: скрывает контент, показывает спиннер (только не-LINK темы) |
120
+ | `icon` | `React.ReactElement` | Нет | Иконка слева от текста; если без `children` — кнопка становится квадратной |
121
+ | `children` | `React.ReactNode` | Нет | Текст кнопки |
122
+ | `...HTMLButtonAttributes` | — | — | Все стандартные атрибуты `<button>` |
123
+
124
+ ### Props компонента `ButtonIcon`
125
+
126
+ | Prop | Тип | По умолчанию | Описание |
127
+ |---|---|---|---|
128
+ | `shape` | `EButtonIconShape` | `SQUIRCLE` | Форма: `SQUIRCLE` (4px radius) или `CIRCLE` (50%) |
129
+ | `active` | `boolean` | `false` | Визуальное активное состояние |
130
+ | `...HTMLButtonAttributes` | — | — | Включая `disabled` |
131
+
132
+ ---
133
+
134
+ ## Ключевые особенности реализации
135
+
136
+ ### Иконка без текста
137
+ Если передан `icon` без `children` — добавляется класс `.icon`, который делает кнопку квадратной:
138
+ ```tsx
139
+ // Button.tsx — логика определения icon-only режима
140
+ const iconOnly = Boolean(icon) && !children;
141
+ <button className={clsx(styles.button, { [styles.icon]: iconOnly })}>
142
+ ```
143
+
144
+ ### Состояние загрузки
145
+ - `loading` скрывает контент через `visibility: hidden` (не `display: none`) — сохраняет размеры,
146
+ - устанавливает `tabIndex={-1}` — кнопка недоступна с клавиатуры
147
+ - Тема лоадера: `SECONDARY` и `SECONDARY_LIGHT` → `ELoaderSmallTheme.BRAND`, остальные → `ELoaderSmallTheme.NEUTRAL`
148
+
149
+ ### `aria-expanded` управляет визуалом
150
+ Состояние "раскрыто" (например, когда кнопка открывает dropdown) управляется через `aria-expanded`:
151
+ ```tsx
152
+ <Button aria-expanded={true} ...> → добавляет CSS-классы .expanded и .active
153
+ ```
154
+ Отдельного prop `expanded` нет — используй стандартный HTML-атрибут.
155
+
156
+ ### Тема LINK
157
+ - Нет `min-width`
158
+ - `background: transparent`
159
+ - `padding` по вертикали отличается от других тем (меньше)
160
+ - `block`, `loading`, `icon` — тип `never` в интерфейсе, TypeScript запрещает передачу
161
+
162
+ ---
163
+
164
+ ## Accessibility
165
+
166
+ - Нативный `<button>` — полная поддержка клавиатуры (Tab, Enter, Space) без дополнительных атрибутов.
167
+ - **`ButtonIcon`**: иконочная кнопка без видимого текста — потребитель **обязан** передать `aria-label` через `...rest`. Библиотека мультиязычная, текст не хардкодится.
168
+ - **`loading`**: устанавливает `tabIndex={-1}` — кнопка исключается из tab-порядка. Если нужна доступность состояния загрузки для скринридеров, потребитель добавляет `aria-busy="true"` через props.
169
+ - **`aria-expanded`**: управляет визуальным состоянием "раскрыто" (добавляет CSS-классы `.expanded`, `.active`). Передаётся потребителем при использовании кнопки как триггера dropdown.
170
+ - Фокус-стиль через `:focus-visible` — виден только при клавиатурной навигации.
171
+
172
+ ---
173
+
174
+ ## Дизайн-токены
175
+
176
+ Паттерн: `--triplex-next-Button-{Theme}_{Property}_{State}`
177
+
178
+ Каждая тема (кроме LINK) имеет полный набор:
179
+ - `_Background_Default/Hover/Active/Disabled`
180
+ - `_Color_Default/Hover/Active/Disabled`
181
+ - `_Shadow_Focus`
182
+
183
+ Тема LINK — только `_Color_*` и `_Shadow_Focus` (нет фона).
184
+
185
+ При добавлении нового визуального состояния нужен новый токен в `src/generated/themesCssVariables.css`.
186
+
187
+ ---
188
+
189
+ ## Инварианты
190
+
191
+ - **`forwardRef`** — обязателен на `Button`, `ButtonBase`, `ButtonIcon`, `ButtonDropdown`. Не убирать.
192
+ - **`TButtonProps` union type** — должен включать все тематические интерфейсы. При добавлении новой темы — добавь интерфейс в union.
193
+ - **`EButtonTheme` значения** — не переименовывать. Это публичное API.
194
+ - **`EComponentSize`** — общий enum из `src/enums/EComponentSize`, не делай локальный аналог.
195
+ - **Размеры (28px/40px/56px)** — не менять без согласования с дизайнером, другие компоненты ориентируются на эти размеры.
196
+
197
+ ---
198
+
199
+ ## Связанные компоненты
200
+
201
+ - `ButtonIcon` (`src/components/Button/ButtonIcon.tsx`) — иконочная кнопка, часть того же компонента
202
+ - `ButtonDropdown` (`src/components/Button/ButtonDropdown.tsx`) — кнопка с выпадающим меню опций
203
+ - `ButtonDropdownExtended` — контейнер для кастомного dropdown с render-функциями
204
+ - `Loader` (`src/components/Loader`) — используется внутри Button для состояния загрузки
205
+ - `Dropdown` (`src/components/Dropdown`) — используется внутри ButtonDropdown
206
+
207
+ ---
208
+
209
+ ## Stories
210
+
211
+ `stories/Buttons/Button.stories.tsx`
212
+ Файлы примеров: `stories/Buttons/examples/Button/`
213
+
214
+ | Story | Example file | Что демонстрирует |
215
+ |---|---|---|
216
+ | `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль всех props |
217
+ | `Default` | `DefaultExample.tsx` | Базовое использование |
218
+ | `States` | `StatesExample.tsx` | Expanded, loading, disabled |
219
+ | `Sizes` | `SizesExample.tsx` | SM / MD / LG для всех тем |
220
+ | `Themes` | `ThemesExample.tsx` | Все пять тем |
221
+ | `WithIcon` | `WithIconExample.tsx` | Icon-only и text+icon |
222
+ | `BlockMode` | `BlockModeExample.tsx` | Полноширинный режим |
223
+
224
+ ---
225
+
226
+ ## История изменений
227
+
228
+ | Дата | Изменение |
229
+ |---|---|
230
+ | 2026-03-31 | Создан документ (пилот AI-Ready) |