@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.
- package/README.md +10 -0
- package/bundle/components/AlertContext.md +268 -0
- package/bundle/components/BodyPage.md +186 -0
- package/bundle/components/Button.md +93 -85
- package/bundle/components/ButtonDropdown.md +36 -70
- package/bundle/components/ButtonDropdownExtended.md +422 -0
- package/bundle/components/ButtonIcon.md +41 -48
- package/bundle/components/Caption.md +291 -0
- package/bundle/components/Checkbox.md +43 -122
- package/bundle/components/CheckboxXGroup.md +109 -46
- package/bundle/components/CheckboxYGroup.md +77 -49
- package/bundle/components/CodeText.md +197 -0
- package/bundle/components/Col.md +311 -162
- package/bundle/components/CollapsibleTree.md +584 -0
- package/bundle/components/CollapsibleTreeExtended.md +422 -0
- package/bundle/components/Dropdown.md +748 -346
- package/bundle/components/EmptyView.md +14 -15
- package/bundle/components/FooterPage.md +203 -0
- package/bundle/components/Gap.md +115 -57
- package/bundle/components/HeaderPage.md +226 -0
- package/bundle/components/HelpBox.md +45 -84
- package/bundle/components/ImageGallery.md +423 -0
- package/bundle/components/ImageGalleryExtended.md +606 -0
- package/bundle/components/LightBox.md +2252 -233
- package/bundle/components/List.md +216 -183
- package/bundle/components/ListActionItem.md +157 -0
- package/bundle/components/ListItem.md +276 -0
- package/bundle/components/ListItemControlsButton.md +103 -0
- package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
- package/bundle/components/ListItemSelectable.md +99 -0
- package/bundle/components/ListItemTable.md +390 -0
- package/bundle/components/ListMaster.md +876 -156
- package/bundle/components/ListMasterFooter.md +80 -0
- package/bundle/components/ListMasterHeader.md +86 -0
- package/bundle/components/ListSortable.md +153 -0
- package/bundle/components/ListSortableItem.md +175 -0
- package/bundle/components/ListTableItem.md +391 -0
- package/bundle/components/ModalWindow.md +427 -237
- package/bundle/components/MonthYearField.md +145 -109
- package/bundle/components/Notification.md +625 -155
- package/bundle/components/Overlay.md +271 -170
- package/bundle/components/Page.md +284 -186
- package/bundle/components/Pagination.md +206 -229
- package/bundle/components/Portal.md +131 -67
- package/bundle/components/Row.md +171 -69
- package/bundle/components/Text.md +320 -0
- package/bundle/components/TextField.md +364 -97
- package/bundle/components/Title.md +296 -0
- package/bundle/guides/codestyle.md +38 -11
- package/bundle/guides/commits.md +119 -26
- package/bundle/guides/context.md +34 -30
- package/bundle/guides/stories.md +110 -40
- package/bundle/guides/template.md +3 -7
- package/bundle/guides/tests.md +48 -2
- package/bundle/manifest.json +275 -30
- package/bundle/release-notes/1.26.0.mdx +33 -2
- package/bundle/release-notes/1.27.0.mdx +43 -0
- package/bundle/release-notes/1.28.0.mdx +25 -0
- package/bundle/release-notes/1.29.0.mdx +47 -0
- package/bundle/release-notes/1.30.0.mdx +56 -0
- package/bundle/release-notes/1.31.0.mdx +52 -0
- package/bundle/release-notes/1.32.0.mdx +35 -0
- package/bundle/release-notes/1.33.0.mdx +61 -0
- package/bundle/release-notes/1.34.0.mdx +35 -0
- package/bundle/release-notes/1.35.0.mdx +21 -0
- package/bundle/release-notes/1.35.1.mdx +11 -0
- package/bundle/release-notes/1.36.0.mdx +21 -0
- package/bundle/release-notes/1.37.0.mdx +71 -0
- package/bundle/release-notes/1.38.0.mdx +36 -0
- package/bundle/release-notes/1.39.0.mdx +66 -0
- package/bundle/release-notes/1.40.0.mdx +27 -0
- package/bundle/release-notes/1.41.0.mdx +7 -0
- package/package.json +1 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: EmptyView
|
|
3
3
|
category: Feedback
|
|
4
|
-
figma-node: "80-48"
|
|
5
|
-
figma-file: "https://www.figma.com/design/lpkxmWZ512mG2OJyDvGtHD/-W--LIB-DSN-01-Components-DCB-Next-v.1.3.0"
|
|
6
4
|
related: [Button]
|
|
7
5
|
tokens:
|
|
8
6
|
- --triplex-next-Typography-Primary_Color
|
|
@@ -28,22 +26,22 @@ version: "1.0"
|
|
|
28
26
|
|
|
29
27
|
| Prop | Тип | Описание |
|
|
30
28
|
|---|---|---|
|
|
31
|
-
| `size` | `EEmptyViewSize` | Размер: SM / MD |
|
|
29
|
+
| `size` | `EEmptyViewSize` | Размер: `SM` / `MD` |
|
|
32
30
|
|
|
33
31
|
### Опциональные props
|
|
34
32
|
|
|
35
33
|
| Prop | Тип | По умолчанию | Описание |
|
|
36
34
|
|---|---|---|---|
|
|
37
|
-
| `icon` | `ReactNode` | — | Иконка (96px для SM
|
|
35
|
+
| `icon` | `ReactNode` | — | Иконка (96px для `SM`, 128px для `MD`) |
|
|
38
36
|
| `title` | `ReactNode` | — | Заголовок |
|
|
39
37
|
| `description` | `ReactNode` | — | Текст описания |
|
|
40
38
|
| `caption` | `ReactNode` | — | Подпись |
|
|
41
39
|
| `buttons` | `ReactNode` | — | Кнопки действий |
|
|
42
40
|
|
|
43
|
-
###
|
|
41
|
+
### Ограничения по темам
|
|
44
42
|
|
|
45
|
-
- Если `title`
|
|
46
|
-
- Если `title` не
|
|
43
|
+
- Если `title` задан — описание отображается вторичным цветом (Secondary).
|
|
44
|
+
- Если `title` не задан — описание становится основным текстом (Primary).
|
|
47
45
|
|
|
48
46
|
---
|
|
49
47
|
|
|
@@ -58,22 +56,22 @@ version: "1.0"
|
|
|
58
56
|
|
|
59
57
|
## Инварианты
|
|
60
58
|
|
|
61
|
-
- `forwardRef` на компоненте — не
|
|
62
|
-
- `EEmptyViewSize` — публичный enum, менять значения
|
|
63
|
-
- CSS-классы `emptyView`, `hasTitle` используются в
|
|
59
|
+
- `forwardRef` на компоненте — не убирать.
|
|
60
|
+
- `EEmptyViewSize` — публичный enum, менять значения нельзя.
|
|
61
|
+
- CSS-классы `emptyView`, `hasTitle` используются в тестах.
|
|
64
62
|
|
|
65
63
|
---
|
|
66
64
|
|
|
67
65
|
## Accessibility
|
|
68
66
|
|
|
69
|
-
- Компонент не требует обязательных aria
|
|
70
|
-
- Потребитель может передать `role`, `aria-label` и другие атрибуты через spread
|
|
67
|
+
- Компонент не требует обязательных aria-атрибутов.
|
|
68
|
+
- Потребитель может передать `role`, `aria-label` и другие атрибуты через spread.
|
|
71
69
|
|
|
72
70
|
---
|
|
73
71
|
|
|
74
72
|
## Связанные компоненты
|
|
75
73
|
|
|
76
|
-
- `Button` — используется в `buttons` для
|
|
74
|
+
- `Button` — используется в `buttons` для действий.
|
|
77
75
|
|
|
78
76
|
---
|
|
79
77
|
|
|
@@ -86,7 +84,7 @@ version: "1.0"
|
|
|
86
84
|
|---|---|---|
|
|
87
85
|
| `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль всех props |
|
|
88
86
|
| `Default` | `DefaultExample.tsx` | Минимальное состояние с title, description и caption |
|
|
89
|
-
| `Sizes` | `SizesExample.tsx` | Размеры SM / MD |
|
|
87
|
+
| `Sizes` | `SizesExample.tsx` | Размеры `SM` / `MD` |
|
|
90
88
|
| `WithoutTitle` | `WithoutTitleExample.tsx` | Вариант без заголовка |
|
|
91
89
|
| `WithButtons` | `WithButtonsExample.tsx` | Вариант с кнопками действий |
|
|
92
90
|
|
|
@@ -96,7 +94,8 @@ version: "1.0"
|
|
|
96
94
|
|
|
97
95
|
| Дата | Изменение |
|
|
98
96
|
|---|---|
|
|
99
|
-
| 2026-04-09 | Создан компонент и
|
|
97
|
+
| 2026-04-09 | Создан компонент и документ. |
|
|
98
|
+
| 2026-04-27 | Приведён в соответствие с `docs/ai/template-ai.md`: добавлена колонка `Example file`, переименована подсекция «Поведение описания» в «Ограничения по темам». |
|
|
100
99
|
|
|
101
100
|
---
|
|
102
101
|
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: FooterPage
|
|
3
|
+
category: Page
|
|
4
|
+
related: [Page, HeaderPage, BodyPage, Footer, Island, LightBox]
|
|
5
|
+
tokens: [--triplex-next-FooterPage-StickyShadow]
|
|
6
|
+
stories: stories/Page/FooterPage/FooterPage.stories.tsx
|
|
7
|
+
version: "1.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# FooterPage
|
|
11
|
+
|
|
12
|
+
## Назначение
|
|
13
|
+
|
|
14
|
+
Футер страницы `Page`. Доступен как статическое свойство `Page.Footer`. Нижний блок страницы
|
|
15
|
+
с контентом и управляющими элементами (кнопки, ссылки), располагается под `Page.Body`.
|
|
16
|
+
|
|
17
|
+
Контент обычно строится через составной `Page.Footer.Description` с областями
|
|
18
|
+
`Page.Footer.Description.Content` и `Page.Footer.Description.Controls`.
|
|
19
|
+
|
|
20
|
+
Используй когда: нужен нижний блок страницы с действиями — как в карточке (Island), так и без неё;
|
|
21
|
+
а также прилипающий к низу футер внутри `LightBox`.
|
|
22
|
+
Не используй когда: нужен заголовок или тело страницы — для этого есть `Page.Header` / `Page.Body`.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Варианты и props
|
|
27
|
+
|
|
28
|
+
Публичный API — discriminated union по `type`: `IFooterPageTypeFirstProps | IFooterPageTypeSecondProps`.
|
|
29
|
+
Оба интерфейса расширяют `IFooterProps` (≈ `React.HTMLAttributes<HTMLDivElement>`).
|
|
30
|
+
|
|
31
|
+
### Обязательные props
|
|
32
|
+
|
|
33
|
+
| Prop | Тип | Описание |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `type` | `EFooterPageType` | `FIRST` — футер оборачивается в `Island` (карточка с белым фоном и тенью). `SECOND` — футер без карточки. |
|
|
36
|
+
| `children` | `React.ReactNode` | Контент футера страницы. |
|
|
37
|
+
|
|
38
|
+
### Опциональные props
|
|
39
|
+
|
|
40
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| `sticky` | `boolean` | `false` | Футер прилипает к нижней границе при скролле. **Только для `type=FIRST`** (внутри `LightBox`); для `type=SECOND` типизирован как `never`. |
|
|
43
|
+
| `size` | `EComponentSize` | — | Размер острова (Island). **Доступен только для `type=FIRST`**; для `type=SECOND` типизирован как `never`. |
|
|
44
|
+
|
|
45
|
+
### Ограничения по типам
|
|
46
|
+
|
|
47
|
+
- `size` и `sticky` доступны только при `type=FIRST` (в `SECOND` контент не оборачивается в Island,
|
|
48
|
+
поэтому оба типизированы как `never`).
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Дизайн-токены
|
|
53
|
+
|
|
54
|
+
| Токен | Назначение |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `--triplex-next-FooterPage-StickyShadow` | Тень прилипшего футера (когда `sticky` и футер коснулся нижней границы, `data-stuck="true"`). |
|
|
57
|
+
|
|
58
|
+
Внешний вид карточки наследуется от `Island` (`EIslandType.TYPE_1`). Радиус нижних углов при
|
|
59
|
+
прилипании плавно обнуляется через CSS-переменную `--r-bottom` (управляется хуком
|
|
60
|
+
`useStickyCornerRadius`).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Инварианты
|
|
65
|
+
|
|
66
|
+
- `forwardRef<HTMLDivElement>` — не убирать. Ref всегда указывает на корневой элемент
|
|
67
|
+
(Island для FIRST, Footer для SECOND).
|
|
68
|
+
- Ручной merge ref (`setFooterRef`) обязателен: ref нужен одновременно хуку
|
|
69
|
+
`useStickyCornerRadius` (внутренний `footerRef`) и наружу (проброшенный `ref`). Не упрощать.
|
|
70
|
+
- `displayName = "FooterPage"` — не менять.
|
|
71
|
+
- `FooterPage` собран через `Object.assign(forwardRef(...), { Description })` — статическое
|
|
72
|
+
свойство `Description` (= `Footer.Description`) должно сохраняться.
|
|
73
|
+
- Discriminated union по `type` и значения `EFooterPageType` — часть публичного API, менять нельзя.
|
|
74
|
+
- Экспорты `FooterPage`, `IFooterPageTypeFirstProps`, `IFooterPageTypeSecondProps` идут в barrel
|
|
75
|
+
`src/components/Page/index.ts` — сохранять.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Accessibility
|
|
80
|
+
|
|
81
|
+
Особого a11y-поведения нет — это структурный контейнер. Семантику и aria-атрибуты задаёт
|
|
82
|
+
потребитель через проброшенные HTML-атрибуты (`...rest` уходит в `Footer`). Интерактивность
|
|
83
|
+
обеспечивают вложенные кнопки/ссылки внутри `Description.Controls`.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Связанные компоненты
|
|
88
|
+
|
|
89
|
+
- `Page` — родитель; `FooterPage` доступен как `Page.Footer`.
|
|
90
|
+
- `HeaderPage` (`Page.Header`), `BodyPage` (`Page.Body`) — соседи внутри `Page`.
|
|
91
|
+
- `Footer` — внутренний контейнер футера; `Page.Footer.Description` = `Footer.Description`.
|
|
92
|
+
- `Island` — карточка-обёртка для `type=FIRST`.
|
|
93
|
+
- `LightBox` — типичное место использования с `sticky`.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Stories
|
|
98
|
+
|
|
99
|
+
Основные истории: `stories/Page/FooterPage/FooterPage.stories.tsx`
|
|
100
|
+
Файлы примеров: `stories/Page/FooterPage/examples/`
|
|
101
|
+
|
|
102
|
+
| Story | Example file | Что демонстрирует |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `Playground` | `Playground.tsx` | Интерактивный контроль `type`, `size` |
|
|
105
|
+
| `Default` | `Default.tsx` | Минимальный пример (FIRST, футер в карточке) |
|
|
106
|
+
| `Types` | `Types.tsx` | Сравнение типов FIRST и SECOND (покрывает скриншот-регрессию) |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## История изменений
|
|
111
|
+
|
|
112
|
+
| Дата | Изменение |
|
|
113
|
+
|---|---|
|
|
114
|
+
| 2026-06-19 | Создан документ. AI-рефакторинг (clsx order, JSDoc на props, displayName), unit-тесты, миграция stories на modern pattern. |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Примеры использования
|
|
119
|
+
|
|
120
|
+
### Default
|
|
121
|
+
|
|
122
|
+
`stories/Page/FooterPage/examples/Default.tsx`
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import React from "react";
|
|
126
|
+
import {
|
|
127
|
+
Page,
|
|
128
|
+
EFooterPageType,
|
|
129
|
+
EComponentSize,
|
|
130
|
+
Button,
|
|
131
|
+
EButtonTheme,
|
|
132
|
+
Text,
|
|
133
|
+
ETextSize,
|
|
134
|
+
} from "@sberbusiness/triplex-next";
|
|
135
|
+
|
|
136
|
+
export const Default = () => (
|
|
137
|
+
<Page.Footer type={EFooterPageType.FIRST}>
|
|
138
|
+
<Page.Footer.Description>
|
|
139
|
+
<Page.Footer.Description.Content>
|
|
140
|
+
<Text size={ETextSize.B3}>Контент футера страницы</Text>
|
|
141
|
+
</Page.Footer.Description.Content>
|
|
142
|
+
<Page.Footer.Description.Controls>
|
|
143
|
+
<Button size={EComponentSize.MD} theme={EButtonTheme.SECONDARY}>
|
|
144
|
+
Отмена
|
|
145
|
+
</Button>
|
|
146
|
+
<Button size={EComponentSize.MD} theme={EButtonTheme.GENERAL}>
|
|
147
|
+
Сохранить
|
|
148
|
+
</Button>
|
|
149
|
+
</Page.Footer.Description.Controls>
|
|
150
|
+
</Page.Footer.Description>
|
|
151
|
+
</Page.Footer>
|
|
152
|
+
);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Types
|
|
156
|
+
|
|
157
|
+
`stories/Page/FooterPage/examples/Types.tsx`
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import React from "react";
|
|
161
|
+
import {
|
|
162
|
+
Page,
|
|
163
|
+
EFooterPageType,
|
|
164
|
+
EComponentSize,
|
|
165
|
+
Button,
|
|
166
|
+
EButtonTheme,
|
|
167
|
+
Text,
|
|
168
|
+
ETextSize,
|
|
169
|
+
} from "@sberbusiness/triplex-next";
|
|
170
|
+
|
|
171
|
+
const controls = (type: EFooterPageType) => (
|
|
172
|
+
<Page.Footer.Description>
|
|
173
|
+
<Page.Footer.Description.Content>
|
|
174
|
+
<Text size={ETextSize.B3}>Контент футера страницы</Text>
|
|
175
|
+
</Page.Footer.Description.Content>
|
|
176
|
+
<Page.Footer.Description.Controls>
|
|
177
|
+
<Button
|
|
178
|
+
size={EComponentSize.MD}
|
|
179
|
+
theme={type === EFooterPageType.FIRST ? EButtonTheme.SECONDARY : EButtonTheme.SECONDARY_LIGHT}
|
|
180
|
+
>
|
|
181
|
+
Отмена
|
|
182
|
+
</Button>
|
|
183
|
+
<Button size={EComponentSize.MD} theme={EButtonTheme.GENERAL}>
|
|
184
|
+
Сохранить
|
|
185
|
+
</Button>
|
|
186
|
+
</Page.Footer.Description.Controls>
|
|
187
|
+
</Page.Footer.Description>
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
export const Types = () => (
|
|
191
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
|
|
192
|
+
<div>
|
|
193
|
+
<div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: 700 }}>FIRST</div>
|
|
194
|
+
<Page.Footer type={EFooterPageType.FIRST}>{controls(EFooterPageType.FIRST)}</Page.Footer>
|
|
195
|
+
</div>
|
|
196
|
+
<div>
|
|
197
|
+
<div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: 700 }}>SECOND</div>
|
|
198
|
+
<Page.Footer type={EFooterPageType.SECOND}>{controls(EFooterPageType.SECOND)}</Page.Footer>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
```
|
|
203
|
+
|
package/bundle/components/Gap.md
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Gap
|
|
3
3
|
category: Layout
|
|
4
|
-
|
|
5
|
-
figma-file: ""
|
|
6
|
-
related: [Row, Col, Divider]
|
|
4
|
+
related: [Divider, Col, Row]
|
|
7
5
|
tokens: []
|
|
8
6
|
stories: stories/Gap/Gap.stories.tsx
|
|
9
7
|
version: "1.0"
|
|
@@ -13,96 +11,78 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
Вертикальный
|
|
17
|
-
отступа между блоками по вертикали. Принципиально ограничен дискретным
|
|
18
|
-
набором размеров из дизайн-системы.
|
|
14
|
+
Вертикальный отступ-разделитель фиксированной высоты между блоками. Рендерит пустой `<div>` с `role="presentation"` без визуального контента — только пространство.
|
|
19
15
|
|
|
20
|
-
Используй когда:
|
|
21
|
-
родителя неудобно (например, между двумя независимыми секциями).
|
|
22
|
-
Не используй когда: можешь задать отступ через `gap` flex-контейнера или
|
|
23
|
-
margin соседа — это семантически предпочтительнее.
|
|
16
|
+
Используй когда: нужно добавить вертикальный отступ между двумя соседними блоками из заранее заданной шкалы значений дизайн-системы (4, 8, 12, 16, 24, 32, 64, 128 px).
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```text
|
|
30
|
-
src/components/Gap/
|
|
31
|
-
├── Gap.tsx # forwardRef, <div role="presentation">, height из size
|
|
32
|
-
├── index.ts # Barrel
|
|
33
|
-
└── __tests__/Gap.test.tsx
|
|
34
|
-
```
|
|
18
|
+
Не используй когда:
|
|
19
|
+
- Нужен горизонтальный отступ — управляй им через `margin`/`padding` родителя или через `Col`/`Row` сетки.
|
|
20
|
+
- Нужна визуальная линия-разделитель — используй `Divider`.
|
|
21
|
+
- Нужен отступ произвольной величины (не из шкалы) — задай его через стили родителя, не вводи новое значение `TGapSize`.
|
|
35
22
|
|
|
36
23
|
---
|
|
37
24
|
|
|
38
25
|
## Варианты и props
|
|
39
26
|
|
|
40
|
-
###
|
|
27
|
+
### Обязательные props
|
|
41
28
|
|
|
42
|
-
| Prop | Тип |
|
|
43
|
-
|
|
44
|
-
| `size` | `TGapSize` |
|
|
45
|
-
| `className`, `style`, `...HTMLDivAttributes` | — | — | `style.height` перезаписывается через `${size}px`. |
|
|
29
|
+
| Prop | Тип | Описание |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `size` | `TGapSize` | Высота отступа в пикселях. Один из значений шкалы: `4 \| 8 \| 12 \| 16 \| 24 \| 32 \| 64 \| 128`. |
|
|
46
32
|
|
|
47
|
-
|
|
33
|
+
### Опциональные props
|
|
48
34
|
|
|
49
|
-
|
|
35
|
+
Компонент расширяет `Omit<React.HTMLAttributes<HTMLDivElement>, "children">`, поэтому принимает все стандартные атрибуты `<div>` (включая `className`, `style`, `aria-*`, `data-*`) кроме `children` — пробрасывание содержимого внутрь Gap запрещено типом.
|
|
50
36
|
|
|
51
|
-
|
|
37
|
+
### Ограничения
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<div style={{ height: `${size}px`, ...style }} role="presentation" {...restProps} ref={ref} />
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
- `role="presentation"` — скринридер игнорирует элемент.
|
|
59
|
-
- `style={{ height, ...style }}` — позволяет перекрыть `height` через props, но порядок такой, что `style` из props идёт **после** и может затереть высоту. Это поведение сохранить (намеренная свобода для кастомных кейсов).
|
|
60
|
-
- Нет собственного `className`/стилей — только inline height.
|
|
39
|
+
- `children` исключён из props — Gap не должен оборачивать контент, только разделять его. Если нужно — используй другой контейнер.
|
|
40
|
+
- Прокидываемый снаружи `style.height` переопределит высоту, заданную CSS-классом (более высокая специфичность inline-style). Это допустимо для крайних случаев, но штатно высоту задаёт `size`.
|
|
61
41
|
|
|
62
42
|
---
|
|
63
43
|
|
|
64
|
-
##
|
|
44
|
+
## Дизайн-токены
|
|
65
45
|
|
|
66
|
-
|
|
67
|
-
(4/8/12/16/24/32/64/128) удалять нельзя (breaking change).
|
|
68
|
-
- **`forwardRef`** — не убирать.
|
|
69
|
-
- **`role="presentation"`** — не менять без причины (a11y-контракт: spacer не объявляется).
|
|
70
|
-
- **Вертикальный (`height`) только**. Для горизонтального spacing используй `gap`
|
|
71
|
-
flex-контейнера или `Col`. Не добавляй prop `direction`, пока не появится явный запрос.
|
|
72
|
-
- **Без `children`** — тип `Omit<..., "children">` запрещает передачу через TS.
|
|
46
|
+
Компонент не использует собственных CSS-переменных. Высота задаётся фиксированными значениями в пикселях из CSS-модуля `styles/Gap.module.less` (классы `.size4`, `.size8`, ..., `.size128`).
|
|
73
47
|
|
|
74
48
|
---
|
|
75
49
|
|
|
76
|
-
##
|
|
50
|
+
## Инварианты
|
|
77
51
|
|
|
78
|
-
- `
|
|
79
|
-
-
|
|
52
|
+
- **`forwardRef`** — обязателен, не убирать. `ref` пробрасывается на корневой `<div>`.
|
|
53
|
+
- **`TGapSize`** — публичный union type, экспортируется из barrel. Изменение перечня значений (добавление/удаление чисел) — breaking change.
|
|
54
|
+
- **`IGapProps`** имя интерфейса и `Gap` имя компонента — часть публичного API.
|
|
55
|
+
- **`role="presentation"`** на корневом `<div>` — компонент семантически невидим для assistive technologies.
|
|
56
|
+
- **`Omit<..., "children">`** в `IGapProps` — публичный контракт, что Gap не принимает потомков.
|
|
57
|
+
- **CSS-классы `size4`...`size128`** в `Gap.module.less` — camelCase согласно `docs/ai/codestyle.md`. Могут использоваться в тестах, переименование требует синхронного обновления тестов.
|
|
80
58
|
|
|
81
59
|
---
|
|
82
60
|
|
|
83
|
-
##
|
|
61
|
+
## Accessibility
|
|
84
62
|
|
|
85
|
-
|
|
63
|
+
- Корневой `<div>` имеет `role="presentation"` — Gap не несёт смысловой нагрузки и игнорируется screen reader'ами.
|
|
64
|
+
- Потребитель может передать дополнительные `aria-*` атрибуты через spread (например, `aria-hidden="true"`), но штатно `role="presentation"` уже исключает компонент из accessibility-дерева.
|
|
65
|
+
- Компонент не интерактивный — keyboard navigation и focus management не применимы.
|
|
86
66
|
|
|
87
67
|
---
|
|
88
68
|
|
|
89
69
|
## Связанные компоненты
|
|
90
70
|
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
71
|
+
- `Divider` (`src/components/Divider/`) — горизонтальная линия-разделитель с собственными отступами `marginTopSize`/`marginBottomSize`. Используй вместо Gap, когда нужно визуально разделить блоки линией.
|
|
72
|
+
- `Col`, `Row` (`src/components/Col/`, `src/components/Row/`) — компоненты сетки. Управляют отступами через систему columns/offsets, а не через явный разделитель.
|
|
93
73
|
|
|
94
74
|
---
|
|
95
75
|
|
|
96
76
|
## Stories
|
|
97
77
|
|
|
98
|
-
`stories/Gap/Gap.stories.tsx`
|
|
99
|
-
|
|
78
|
+
Основные истории: `stories/Gap/Gap.stories.tsx`
|
|
79
|
+
Файлы примеров: `stories/Gap/examples/`
|
|
100
80
|
|
|
101
81
|
| Story | Example file | Что демонстрирует |
|
|
102
82
|
|---|---|---|
|
|
103
|
-
| `Playground` | — | Интерактивный
|
|
104
|
-
| `Default` | `DefaultExample.tsx` |
|
|
105
|
-
| `Sizes` | `SizesExample.tsx` | Все
|
|
83
|
+
| `Playground` | — | Интерактивный контроль `size` через select со всеми значениями `TGapSize` |
|
|
84
|
+
| `Default` | `DefaultExample.tsx` | Минимальное использование с `size={16}` между двумя блоками |
|
|
85
|
+
| `Sizes` | `SizesExample.tsx` | Все 8 значений `TGapSize`: 4, 8, 12, 16, 24, 32, 64, 128 px |
|
|
106
86
|
|
|
107
87
|
---
|
|
108
88
|
|
|
@@ -110,4 +90,82 @@ src/components/Gap/
|
|
|
110
90
|
|
|
111
91
|
| Дата | Изменение |
|
|
112
92
|
|---|---|
|
|
113
|
-
| 2026-
|
|
93
|
+
| 2026-05-20 | Создан документ. AI-рефакторинг: inline-`style` высоты заменён на CSS-классы из `Gap.module.less`, добавлены JSDoc на `Gap`, `TGapSize`, `IGapProps.size`, расширены unit-тесты (forwardRef, все значения `size`, `role="presentation"`). |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Примеры использования
|
|
98
|
+
|
|
99
|
+
### Default
|
|
100
|
+
|
|
101
|
+
`stories/Gap/examples/DefaultExample.tsx`
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import React from "react";
|
|
105
|
+
import { Gap } from "@sberbusiness/triplex-next";
|
|
106
|
+
|
|
107
|
+
export const DefaultExample = () => (
|
|
108
|
+
<div>
|
|
109
|
+
<div
|
|
110
|
+
style={{
|
|
111
|
+
padding: "16px",
|
|
112
|
+
textAlign: "center",
|
|
113
|
+
backgroundColor: "rgb(255, 217, 160)",
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
Sample Text Above
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<Gap size={16} />
|
|
120
|
+
|
|
121
|
+
<div
|
|
122
|
+
style={{
|
|
123
|
+
padding: "16px",
|
|
124
|
+
textAlign: "center",
|
|
125
|
+
backgroundColor: "rgb(255, 217, 160)",
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
Sample Text Below
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Sizes
|
|
135
|
+
|
|
136
|
+
`stories/Gap/examples/SizesExample.tsx`
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import React from "react";
|
|
140
|
+
import { Gap, TGapSize } from "@sberbusiness/triplex-next";
|
|
141
|
+
|
|
142
|
+
const SIZES: TGapSize[] = [4, 8, 12, 16, 24, 32, 64, 128];
|
|
143
|
+
|
|
144
|
+
const blockStyle: React.CSSProperties = {
|
|
145
|
+
padding: "16px",
|
|
146
|
+
textAlign: "center",
|
|
147
|
+
backgroundColor: "rgb(255, 217, 160)",
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
interface ISizeItemProps {
|
|
151
|
+
size: TGapSize;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const SizeItem = ({ size }: ISizeItemProps) => (
|
|
155
|
+
<div>
|
|
156
|
+
<div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>{size}px</div>
|
|
157
|
+
<div style={blockStyle}>Above</div>
|
|
158
|
+
<Gap size={size} />
|
|
159
|
+
<div style={blockStyle}>Below</div>
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
export const SizesExample = () => (
|
|
164
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "24px", maxWidth: "300px" }}>
|
|
165
|
+
{SIZES.map((size) => (
|
|
166
|
+
<SizeItem key={size} size={size} />
|
|
167
|
+
))}
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
```
|
|
171
|
+
|