@sberbusiness/triplex-next-mcp-server 0.24.0-beta2 → 1.40.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 (73) hide show
  1. package/README.md +10 -0
  2. package/bundle/components/AlertContext.md +268 -0
  3. package/bundle/components/BodyPage.md +186 -0
  4. package/bundle/components/Button.md +93 -85
  5. package/bundle/components/ButtonDropdown.md +36 -70
  6. package/bundle/components/ButtonDropdownExtended.md +422 -0
  7. package/bundle/components/ButtonIcon.md +41 -48
  8. package/bundle/components/Caption.md +291 -0
  9. package/bundle/components/Checkbox.md +43 -122
  10. package/bundle/components/CheckboxXGroup.md +109 -46
  11. package/bundle/components/CheckboxYGroup.md +77 -49
  12. package/bundle/components/CodeText.md +197 -0
  13. package/bundle/components/Col.md +311 -162
  14. package/bundle/components/CollapsibleTree.md +584 -0
  15. package/bundle/components/CollapsibleTreeExtended.md +422 -0
  16. package/bundle/components/Dropdown.md +748 -346
  17. package/bundle/components/EmptyView.md +14 -15
  18. package/bundle/components/FooterPage.md +203 -0
  19. package/bundle/components/Gap.md +115 -57
  20. package/bundle/components/HeaderPage.md +226 -0
  21. package/bundle/components/HelpBox.md +45 -84
  22. package/bundle/components/ImageGallery.md +423 -0
  23. package/bundle/components/ImageGalleryExtended.md +606 -0
  24. package/bundle/components/LightBox.md +2252 -233
  25. package/bundle/components/List.md +216 -183
  26. package/bundle/components/ListActionItem.md +157 -0
  27. package/bundle/components/ListItem.md +276 -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 +876 -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/ListTableItem.md +391 -0
  38. package/bundle/components/ModalWindow.md +427 -237
  39. package/bundle/components/MonthYearField.md +145 -109
  40. package/bundle/components/Notification.md +625 -155
  41. package/bundle/components/Overlay.md +271 -170
  42. package/bundle/components/Page.md +284 -186
  43. package/bundle/components/Pagination.md +206 -229
  44. package/bundle/components/Portal.md +131 -67
  45. package/bundle/components/Row.md +171 -69
  46. package/bundle/components/Text.md +320 -0
  47. package/bundle/components/TextField.md +364 -97
  48. package/bundle/components/Title.md +296 -0
  49. package/bundle/guides/codestyle.md +38 -11
  50. package/bundle/guides/commits.md +119 -26
  51. package/bundle/guides/context.md +34 -30
  52. package/bundle/guides/stories.md +110 -40
  53. package/bundle/guides/template.md +3 -7
  54. package/bundle/guides/tests.md +48 -2
  55. package/bundle/manifest.json +275 -30
  56. package/bundle/release-notes/1.26.0.mdx +33 -2
  57. package/bundle/release-notes/1.27.0.mdx +43 -0
  58. package/bundle/release-notes/1.28.0.mdx +25 -0
  59. package/bundle/release-notes/1.29.0.mdx +47 -0
  60. package/bundle/release-notes/1.30.0.mdx +56 -0
  61. package/bundle/release-notes/1.31.0.mdx +52 -0
  62. package/bundle/release-notes/1.32.0.mdx +35 -0
  63. package/bundle/release-notes/1.33.0.mdx +61 -0
  64. package/bundle/release-notes/1.34.0.mdx +35 -0
  65. package/bundle/release-notes/1.35.0.mdx +21 -0
  66. package/bundle/release-notes/1.35.1.mdx +11 -0
  67. package/bundle/release-notes/1.36.0.mdx +21 -0
  68. package/bundle/release-notes/1.37.0.mdx +71 -0
  69. package/bundle/release-notes/1.38.0.mdx +36 -0
  70. package/bundle/release-notes/1.39.0.mdx +66 -0
  71. package/bundle/release-notes/1.40.0.mdx +27 -0
  72. package/bundle/release-notes/1.41.0.mdx +7 -0
  73. package/package.json +1 -1
package/README.md CHANGED
@@ -80,6 +80,9 @@ npm run inspect
80
80
  # Обновить bundle/ из последнего релиза triplex-next
81
81
  npm run fetch-bundle
82
82
 
83
+ # Обновить только AI-ready компоненты из bundle, остальные данные сохранить
84
+ npm run fetch-bundle -- --merge --file path/to/mcp-data.json
85
+
83
86
  # Обновить bundle/icons.json из @sberbusiness/icons-next
84
87
  npm run fetch-icons
85
88
 
@@ -111,6 +114,13 @@ bundle/
111
114
  содержимое в поддиректории выше. Транзиентный `mcp-data.json` удаляется
112
115
  после раскладки.
113
116
 
117
+ По умолчанию дерево перезаписывается целиком. Флаг `--merge` включает
118
+ инкрементальное обновление: компоненты, у которых в bundle есть данные
119
+ (`raw !== null`), перезаписываются, остальные сохраняют текущую документацию
120
+ и записи в `manifest.json`. Гайды и release notes из bundle перезаписываются,
121
+ отсутствующие в bundle — сохраняются. Режим полезен, пока AI-документация
122
+ в triplex-next выверяется покомпонентно.
123
+
114
124
  В triplex-next bundle собирается скриптом `scripts/generateMcpData.ts`
115
125
  (npm-команда `generateMcpData`) и автоматически прикладывается к релиз-ассетам
116
126
  через `.github/workflows/release.yml`.
@@ -0,0 +1,268 @@
1
+ ---
2
+ component: AlertContext
3
+ category: Alert
4
+ related: [AlertProcess]
5
+ tokens:
6
+ - --triplex-next-AlertContext-Info_Color
7
+ - --triplex-next-AlertContext-Warning_Color
8
+ - --triplex-next-AlertContext-Error_Color
9
+ - --triplex-next-AlertContext-System_Color
10
+ stories: stories/Alerts/AlertContext.stories.tsx
11
+ version: "1.0"
12
+ ---
13
+
14
+ # AlertContext
15
+
16
+ ## Назначение
17
+
18
+ Инлайновое контекстное предупреждение: строка «иконка + короткий текст», которая
19
+ поясняет или уточняет соседний элемент интерфейса. Рендерится в `<span>` с
20
+ `role="alert"`, иконка выбирается автоматически по `type`, текст оборачивается в
21
+ `Text` с размером `ETextSize.B4`.
22
+
23
+ Используй когда: нужно дать пояснение, предупреждение или сообщение об ошибке
24
+ рядом с полем, кнопкой или блоком контента — без рамки, фона и кнопки закрытия.
25
+
26
+ Не используй когда: нужен полноценный блок-уведомление с фоном, скруглением,
27
+ ссылками, спойлером и кнопкой закрытия — это `AlertProcess`. Для всплывающих
28
+ уведомлений поверх интерфейса — `Notification`.
29
+
30
+ ---
31
+
32
+ ## Варианты и props
33
+
34
+ ### Обязательные props
35
+
36
+ | Prop | Тип | Описание |
37
+ | ------ | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
38
+ | `type` | `Exclude<EAlertType, EAlertType.FEATURE>` | Тип предупреждения: `INFO` / `WARNING` / `ERROR` / `SYSTEM`. Определяет и иконку по умолчанию, и цвет текста |
39
+
40
+ ### Опциональные props
41
+
42
+ | Prop | Тип | По умолчанию | Описание |
43
+ | ------------------------------ | ----------------- | ---------------- | -------------------------------------------------------------------------- |
44
+ | `renderIcon` | `React.ReactNode` | иконка по `type` | Полностью заменяет иконку по умолчанию |
45
+ | `children` | `React.ReactNode` | — | Текст предупреждения. Всегда оборачивается в `Text`, наружу не «протекает» |
46
+ | `...HTMLSpanElementAttributes` | — | — | Все стандартные атрибуты `<span>` |
47
+
48
+ ### Ограничения по типам
49
+
50
+ - `EAlertType.FEATURE` **не поддерживается** и исключён на уровне типа
51
+ (`Exclude<EAlertType, EAlertType.FEATURE>`). Класса `.alertTypeFeature` в
52
+ `AlertContext.module.less` нет — общий `ALERT_TYPE_TO_CLASS_NAME_MAP` содержит
53
+ ветку `FEATURE` только ради `AlertProcess`. Если обойти типизацию (`as`) и
54
+ передать `FEATURE`, компонент отрендерится без иконки и без цветового класса.
55
+ - Иконки по умолчанию фиксированы: `InfoStrokeStsIcon16` (`paletteIndex={3}`),
56
+ `WarningStrokeStsIcon16` (`2`), `ErrorStrokeStsIcon16` (`1`),
57
+ `SystemStrokeStsIcon16` (`4`). Менять `paletteIndex` нельзя — они согласованы
58
+ с цветовыми токенами.
59
+
60
+ ---
61
+
62
+ ## Дизайн-токены
63
+
64
+ ```text
65
+ --triplex-next-AlertContext-Info_Color // цвет текста для type=INFO
66
+ --triplex-next-AlertContext-Warning_Color // цвет текста для type=WARNING
67
+ --triplex-next-AlertContext-Error_Color // цвет текста для type=ERROR
68
+ --triplex-next-AlertContext-System_Color // цвет текста для type=SYSTEM
69
+ ```
70
+
71
+ Значения — в `src/components/DesignTokens/components/AlertContext.ts`. Обрати
72
+ внимание: `Info_Color`, `Warning_Color` и `System_Color` ссылаются на один и тот
73
+ же нейтральный цвет (`ColorDarkNeutralAlpha.0` / `ColorNeutralAlpha.0`),
74
+ выделен цветом только `Error_Color`. Типы различаются прежде всего иконкой, а не
75
+ цветом текста.
76
+
77
+ Размеры шрифта токенами не задаются — типографику целиком определяет `Text`
78
+ с `ETextSize.B4` (класс `.b4` в `Typography/styles/Text.module.less`).
79
+
80
+ ---
81
+
82
+ ## Инварианты
83
+
84
+ - **`forwardRef`** — обязателен, target — `HTMLSpanElement`. Не убирать.
85
+ - **Корневой элемент `<span>` с `role="alert"`** — не менять ни тег, ни роль.
86
+ Тег `<span>` выбран ради валидности вложения в инлайновый контекст, но
87
+ `display: flex` делает элемент **блочным** flex-контейнером: из текстового
88
+ потока он выпадает. Не рассчитывай на инлайновое обтекание.
89
+ - **`type` исключает `EAlertType.FEATURE`** — сужение типа публичное, расширять
90
+ без добавления стилей и иконки нельзя.
91
+ - **`renderIcon` переопределяет иконку через `||`, а не `??`** — намеренно:
92
+ falsy-значение (`false`, `null`) означает «показать иконку по умолчанию». Замена
93
+ на `??` изменит поведение для `renderIcon={false}`.
94
+ - **CSS-классы `alertContext`, `alertContextText`, `alertTypeInfo`,
95
+ `alertTypeWarning`, `alertTypeError`, `alertTypeSystem`** — проверяются в
96
+ unit-тестах, не переименовывать.
97
+ - **`Text` получает только `size` и `className`** — никакого `type`. Цвет —
98
+ зона ответственности `AlertContext`, см. «Подводные камни». Тест
99
+ `does not set the mapped Typography font type class on text` охраняет это
100
+ правило. В DOM класс `primary` при этом присутствует: `Text` подставляет
101
+ `EFontType.PRIMARY` по умолчанию — на цвет он не влияет, его перекрывает
102
+ локальное правило.
103
+ - **`ALERT_TYPE_TO_CLASS_NAME_MAP`** (`AlertTypeUtils.tsx`) — общий с
104
+ `AlertProcess` и экспортируется из barrel. Его форма (`Record<EAlertType,
105
+ (styles) => string>`) — часть публичного API, менять нельзя без breaking change.
106
+
107
+ ---
108
+
109
+ ## Подводные камни
110
+
111
+ - **Цвет текста задаётся локальным правилом, а `type` у `Text` намеренно не
112
+ передаётся.** Цвет берётся из `.alertContext.alertTypeX .alertContextText`
113
+ (токены `AlertContext-*`). Раньше компонент дополнительно передавал в `Text`
114
+ вычисленный `EFontType`, но это было мёртвым кодом: локальное правило имеет
115
+ специфичность (0,3,0) и всегда перекрывает `.typography.info` (0,2,0) из
116
+ `Typography.module.less`. Хуже того, значения расходились — см. таблицу ниже.
117
+ Не возвращай `type` у `Text`: цвет от этого не изменится, но код начнёт
118
+ документировать неверное намерение. Обратное тоже неверно — не убирай
119
+ LESS-правила «раз цвет и так задаёт `Text`»: тогда текст станет `primary`.
120
+
121
+ | `type` | `AlertContext-*` (действует) | `Typography-*` (не действует) |
122
+ |---|---|---|
123
+ | `INFO` | нейтральный `rgba(31,31,34,1)` / `rgba(255,255,255,1)` | синий `#0E57CC` / `#1297FE` |
124
+ | `WARNING` | нейтральный, те же значения | оранжевый `#EF4C01` / `#FF7A17` |
125
+ | `ERROR` | `#D10032` / `#F80C45` | `#D10032` / `#F80C45` — совпадает |
126
+ | `SYSTEM` | нейтральный, альфа `1` | `SECONDARY`: альфа `.65` / `.55` |
127
+
128
+ - **Из `.alertContext` удалены `font-size: 12px` / `line-height: 16px`**
129
+ (2026-07-27) как мёртвые правила: типографику текста задаёт `Text` через
130
+ класс `.b4` на самом текстовом элементе, а собственное объявление потомка
131
+ всегда бьёт наследуемое от родителя. На иконки влияния не было — они
132
+ рендерятся как `<svg width="16" height="16">` с px-атрибутами.
133
+ **Остаточный риск:** если потребитель передаёт в `renderIcon` не-svg элемент
134
+ с текстом, его типографика после удаления изменится — раньше он наследовал от
135
+ `.alertContext` 12px/16px, теперь наследует размер шрифта родителя страницы.
136
+ Штатный сценарий (`renderIcon` = иконка из `@sberbusiness/icons-next`) не
137
+ затронут.
138
+ - **`role="alert"` присутствует в DOM с момента монтирования.** Live-region,
139
+ добавленный в дерево вместе со своим содержимым, скринридеры часто не
140
+ анонсируют. Если нужно гарантированное озвучивание при динамическом появлении
141
+ сообщения — держи `AlertContext` смонтированным и меняй `children`, а не
142
+ монтируй компонент целиком.
143
+
144
+ ---
145
+
146
+ ## Accessibility
147
+
148
+ - Корневой `<span>` имеет `role="alert"` — это `aria-live="assertive"` region:
149
+ изменение содержимого прерывает текущую речь скринридера.
150
+ - Иконка декоративная и не имеет текстовой альтернативы — весь смысл должен
151
+ быть в `children`. Не полагайся на цвет и иконку как на единственный носитель
152
+ информации о серьёзности сообщения.
153
+ - Компонент неинтерактивен: не получает фокус, не обрабатывает клавиатуру,
154
+ собственных `aria-*` атрибутов сверх `role` не выставляет. Любые `aria-label`
155
+ / `aria-describedby` пробрасываются через `...rest`.
156
+ - При связывании с полем формы передавай `id` и ссылайся на него из поля через
157
+ `aria-describedby`.
158
+
159
+ ---
160
+
161
+ ## Связанные компоненты
162
+
163
+ - `AlertProcess` — блочное уведомление того же семейства: фон, скругление,
164
+ кнопка закрытия, спойлер, ссылки. Поддерживает `EAlertType.FEATURE`.
165
+ - `EAlertType` — общий enum типов для всего семейства. `AlertContext`
166
+ использует его подмножество.
167
+ - `ALERT_TYPE_TO_CLASS_NAME_MAP` (`AlertTypeUtils.tsx`) — общий маппинг типа в
168
+ CSS-класс, разделяемый с `AlertProcess`. Собственного AI.md не имеет.
169
+ - `Text` — рендерит текст предупреждения (`ETextSize.B4`). Цвет им не
170
+ управляется: prop `type` намеренно не передаётся.
171
+ - `Notification` — всплывающее уведомление поверх интерфейса, а не инлайновое.
172
+
173
+ ---
174
+
175
+ ## Stories
176
+
177
+ Основные истории: `stories/Alerts/AlertContext.stories.tsx`
178
+ Файлы примеров: `stories/Alerts/examples/AlertContext/`
179
+
180
+ | Story | Example file | Что демонстрирует |
181
+ | ---------------- | -------------------- | ---------------------------------------------------------------- |
182
+ | `Playground` | `Playground.tsx` | Интерактивный контроль `type` и `children` |
183
+ | `Default` | `Default.tsx` | Базовое предупреждение с типом `INFO` |
184
+ | `Types` | `Types.tsx` | Все поддерживаемые типы: `INFO` / `WARNING` / `ERROR` / `SYSTEM` |
185
+ | `WithCustomIcon` | `WithCustomIcon.tsx` | Замена иконки через `renderIcon` |
186
+
187
+ Скриншот-тесты: baseline лежат в `__screenshots__/` как
188
+ `alerts-alertcontext--{default,types,with-custom-icon}--{xs,xl}.png`.
189
+ `Playground` исключён из скриншот-тестов через `testRunner: { skip: true }`
190
+ (по `docs/ai/stories-guide.md` — всегда), его визуальная регрессия не покрыта.
191
+ Устаревшие `alerts-alertcontext--playground--{xs,xl}.png` удалены: скрипт
192
+ `scripts/checkOrphanScreenshots.ts` такие файлы не ловит — `parameters` нет в
193
+ `storybook-static/index.json`, поэтому skip-стори считаются ожидаемыми.
194
+ Отдельная `VisualTests` story не создавалась — у компонента нет состояний,
195
+ требующих взаимодействия (hover / focus / disabled / loading отсутствуют).
196
+ Непокрытый визуальный кейс — перенос текста на несколько строк.
197
+
198
+ ---
199
+
200
+ ## История изменений
201
+
202
+ | Дата | Изменение |
203
+ | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
204
+ | 2026-07-27 | Создан документ. AI-рефакторинг: switch иконок заменён на `TYPE_TO_DEFAULT_ICON_MAP`, в `IAlertContextProps` добавлен явный `children`, из `.alertContext` удалены мёртвые `font-size` / `line-height`, из `Text` убран prop `type` вместе с маппингом `EFontType` (перекрывался специфичностью и расходился по значениям с токенами `AlertContext-*`). Unit-тесты расширены с 6 до 25 кейсов. Файлы примеров в `stories/Alerts/examples/AlertContext/` переименованы под modern pattern — без суффикса `Example`. Публичный API не менялся. |
205
+
206
+ ---
207
+
208
+ ## Примеры использования
209
+
210
+ ### Default
211
+
212
+ `stories/Alerts/examples/AlertContext/Default.tsx`
213
+
214
+ ```tsx
215
+ import React from "react";
216
+ import { AlertContext, EAlertType } from "@sberbusiness/triplex-next";
217
+
218
+ export const Default = () => (
219
+ <div style={{ maxWidth: "750px" }}>
220
+ <AlertContext type={EAlertType.INFO}>
221
+ This message provides context or highlights important information to note.
222
+ </AlertContext>
223
+ </div>
224
+ );
225
+ ```
226
+
227
+ ### Types
228
+
229
+ `stories/Alerts/examples/AlertContext/Types.tsx`
230
+
231
+ ```tsx
232
+ import React from "react";
233
+ import { AlertContext, EAlertType } from "@sberbusiness/triplex-next";
234
+
235
+ const TYPES = Object.values(EAlertType).filter((type) => type !== EAlertType.FEATURE);
236
+
237
+ export const Types = () => (
238
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px", maxWidth: "750px" }}>
239
+ {TYPES.map((type) => (
240
+ <div key={type}>
241
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>{type.toUpperCase()}</div>
242
+ <AlertContext type={type}>
243
+ This message provides context or highlights important information to note.
244
+ </AlertContext>
245
+ </div>
246
+ ))}
247
+ </div>
248
+ );
249
+ ```
250
+
251
+ ### WithCustomIcon
252
+
253
+ `stories/Alerts/examples/AlertContext/WithCustomIcon.tsx`
254
+
255
+ ```tsx
256
+ import React from "react";
257
+ import { AlertContext, EAlertType } from "@sberbusiness/triplex-next";
258
+ import { WaitStrokeStsIcon16 } from "@sberbusiness/icons-next";
259
+
260
+ export const WithCustomIcon = () => (
261
+ <div style={{ maxWidth: "750px" }}>
262
+ <AlertContext type={EAlertType.INFO} renderIcon={<WaitStrokeStsIcon16 paletteIndex={4} />}>
263
+ This message provides context or highlights important information to note.
264
+ </AlertContext>
265
+ </div>
266
+ );
267
+ ```
268
+
@@ -0,0 +1,186 @@
1
+ ---
2
+ component: BodyPage
3
+ category: Page
4
+ related: [Page, HeaderPage, FooterPage, Body, Island, LightBox]
5
+ tokens: []
6
+ stories: stories/Page/BodyPage/BodyPage.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # BodyPage
11
+
12
+ ## Назначение
13
+
14
+ Тело страницы `Page`. Доступен как статическое свойство `Page.Body`. Контейнер для основного
15
+ контента страницы между `Page.Header` и `Page.Footer`.
16
+
17
+ Используй когда: нужно разместить основной контент внутри `Page` — как в карточке (Island), так и без неё.
18
+ Не используй когда: нужен заголовок или футер страницы — для этого есть `Page.Header` / `Page.Footer`.
19
+
20
+ ---
21
+
22
+ ## Варианты и props
23
+
24
+ Публичный API — discriminated union по `type`: `IBodyPageTypeFirstProps | IBodyPageTypeSecondProps`.
25
+ Оба интерфейса расширяют `IBodyProps` (≈ `React.HTMLAttributes<HTMLDivElement>`).
26
+
27
+ ### Обязательные props
28
+
29
+ | Prop | Тип | Описание |
30
+ |---|---|---|
31
+ | `type` | `EBodyPageType` | `FIRST` — контент оборачивается в `Island` (карточка с белым фоном и тенью). `SECOND` — контент без карточки. |
32
+ | `children` | `React.ReactNode` | Контент тела страницы. |
33
+
34
+ ### Опциональные props
35
+
36
+ | Prop | Тип | По умолчанию | Описание |
37
+ |---|---|---|---|
38
+ | `verticalMargin` | `EBodyPageVerticalMargin` | `LARGE` | Вертикальные отступы: `LARGE` = 24px (16px на узких экранах), `SMALL` = 16px (8px на узких). В LightBox используется `SMALL`. |
39
+ | `size` | `EComponentSize` | — | Размер острова (Island). **Доступен только для `type=FIRST`**; для `type=SECOND` типизирован как `never`. |
40
+
41
+ ### Ограничения по типам
42
+
43
+ - `size` доступен только при `type=FIRST` (в `SECOND` контент не оборачивается в Island, поэтому `size?: never`).
44
+
45
+ ---
46
+
47
+ ## Дизайн-токены
48
+
49
+ Собственных CSS-переменных нет. Внешний вид карточки наследуется от `Island` (`EIslandType.TYPE_1`).
50
+ Вертикальные отступы заданы фиксированными значениями в `styles/BodyPage.module.less`
51
+ (24/16px и адаптив 16/8px на `@screen-sm-max`).
52
+
53
+ ---
54
+
55
+ ## Инварианты
56
+
57
+ - `forwardRef<HTMLDivElement>` — не убирать. Ref всегда указывает на корневой элемент
58
+ (Island для FIRST, Body для SECOND).
59
+ - `displayName = "BodyPage"` — не менять.
60
+ - Discriminated union по `type` и значения `EBodyPageType` / `EBodyPageVerticalMargin` — часть
61
+ публичного API, менять нельзя.
62
+ - Экспорты `BodyPage`, `IBodyPageTypeFirstProps`, `IBodyPageTypeSecondProps` идут в barrel
63
+ `src/components/Page/index.ts` — сохранять.
64
+ - `verticalMargin` по умолчанию `LARGE` — менять дефолт нельзя без обсуждения.
65
+
66
+ ---
67
+
68
+ ## Accessibility
69
+
70
+ Особого a11y-поведения нет — это структурный контейнер. Семантику и aria-атрибуты задаёт
71
+ потребитель через проброшенные HTML-атрибуты (`...rest` уходит в `Body`).
72
+
73
+ ---
74
+
75
+ ## Связанные компоненты
76
+
77
+ - `Page` — родитель; `BodyPage` доступен как `Page.Body`.
78
+ - `HeaderPage` (`Page.Header`), `FooterPage` (`Page.Footer`) — соседи внутри `Page`.
79
+ - `Body` — внутренний контейнер контента (рендерится в обоих типах).
80
+ - `Island` — карточка-обёртка для `type=FIRST`.
81
+ - `LightBox` — типичное место использования с `verticalMargin=SMALL`.
82
+
83
+ ---
84
+
85
+ ## Stories
86
+
87
+ Основные истории: `stories/Page/BodyPage/BodyPage.stories.tsx`
88
+ Файлы примеров: `stories/Page/BodyPage/examples/`
89
+
90
+ | Story | Example file | Что демонстрирует |
91
+ |---|---|---|
92
+ | `Playground` | `Playground.tsx` | Интерактивный контроль `type` и `verticalMargin` |
93
+ | `Default` | `Default.tsx` | Минимальный пример (FIRST, контент в карточке) |
94
+ | `Types` | `Types.tsx` | Сравнение типов FIRST и SECOND |
95
+ | `VerticalMargins` | `VerticalMargins.tsx` | Отступы LARGE (24px) и SMALL (16px) |
96
+ | `VisualTests` | `VisualTests.tsx` | Матрица type × verticalMargin для скриншот-регрессии |
97
+
98
+ ---
99
+
100
+ ## История изменений
101
+
102
+ | Дата | Изменение |
103
+ |---|---|
104
+ | 2026-06-18 | Создан документ. AI-рефакторинг (clsx order, JSDoc), unit-тесты, миграция stories на modern pattern. |
105
+
106
+ ---
107
+
108
+ ## Примеры использования
109
+
110
+ ### Default
111
+
112
+ `stories/Page/BodyPage/examples/Default.tsx`
113
+
114
+ ```tsx
115
+ import React from "react";
116
+ import { Page, EBodyPageType, Text, ETextSize, EFontType } from "@sberbusiness/triplex-next";
117
+
118
+ export const Default = () => (
119
+ <Page.Body type={EBodyPageType.FIRST}>
120
+ <Text tag="div" size={ETextSize.B2} type={EFontType.PRIMARY}>
121
+ BodyPage типа FIRST оборачивает контент в Island (карточку) с белым фоном и тенью.
122
+ </Text>
123
+ </Page.Body>
124
+ );
125
+ ```
126
+
127
+ ### Types
128
+
129
+ `stories/Page/BodyPage/examples/Types.tsx`
130
+
131
+ ```tsx
132
+ import React from "react";
133
+ import { Page, EBodyPageType, Text, ETextSize, EFontType } from "@sberbusiness/triplex-next";
134
+
135
+ export const Types = () => (
136
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
137
+ <div>
138
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: 700 }}>FIRST</div>
139
+ <Page.Body type={EBodyPageType.FIRST}>
140
+ <Text tag="div" size={ETextSize.B2} type={EFontType.PRIMARY}>
141
+ Тип FIRST оборачивает контент в Island (карточку) с белым фоном и тенью.
142
+ </Text>
143
+ </Page.Body>
144
+ </div>
145
+ <div>
146
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: 700 }}>SECOND</div>
147
+ <Page.Body type={EBodyPageType.SECOND}>
148
+ <Text tag="div" size={ETextSize.B2} type={EFontType.PRIMARY}>
149
+ Тип SECOND отображает контент без карточки.
150
+ </Text>
151
+ </Page.Body>
152
+ </div>
153
+ </div>
154
+ );
155
+ ```
156
+
157
+ ### VerticalMargins
158
+
159
+ `stories/Page/BodyPage/examples/VerticalMargins.tsx`
160
+
161
+ ```tsx
162
+ import React from "react";
163
+ import { Page, EBodyPageType, EBodyPageVerticalMargin, Text, ETextSize, EFontType } from "@sberbusiness/triplex-next";
164
+
165
+ export const VerticalMargins = () => (
166
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
167
+ <div>
168
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: 700 }}>LARGE (24px)</div>
169
+ <Page.Body type={EBodyPageType.FIRST} verticalMargin={EBodyPageVerticalMargin.LARGE}>
170
+ <Text tag="div" size={ETextSize.B2} type={EFontType.PRIMARY}>
171
+ Отступы сверху и снизу 24px (значение по умолчанию).
172
+ </Text>
173
+ </Page.Body>
174
+ </div>
175
+ <div>
176
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: 700 }}>SMALL (16px)</div>
177
+ <Page.Body type={EBodyPageType.FIRST} verticalMargin={EBodyPageVerticalMargin.SMALL}>
178
+ <Text tag="div" size={ETextSize.B2} type={EFontType.PRIMARY}>
179
+ Уменьшенные отступы сверху и снизу 16px. Используется в LightBox.
180
+ </Text>
181
+ </Page.Body>
182
+ </div>
183
+ </div>
184
+ );
185
+ ```
186
+