@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,11 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Portal
|
|
3
|
-
category:
|
|
4
|
-
|
|
5
|
-
figma-file: ""
|
|
6
|
-
related: [ModalWindow, LightBox, Dropdown, Tooltip]
|
|
3
|
+
category: Portal
|
|
4
|
+
related: [Dropdown, Tooltip]
|
|
7
5
|
tokens: []
|
|
8
|
-
stories:
|
|
6
|
+
stories: stories/Portal/Portal.stories.tsx
|
|
9
7
|
version: "1.0"
|
|
10
8
|
---
|
|
11
9
|
|
|
@@ -13,107 +11,173 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
внешний DOM-узел (`container`),
|
|
18
|
-
|
|
14
|
+
Сервисный компонент — тонкая обёртка над `ReactDOM.createPortal`. Рендерит
|
|
15
|
+
`children` в указанный внешний DOM-узел (`container`), а не в месте объявления,
|
|
16
|
+
сохраняя React-контекст и всплытие событий по React-дереву.
|
|
19
17
|
|
|
20
|
-
Используй когда:
|
|
21
|
-
`overflow: hidden`, `z-index
|
|
22
|
-
|
|
18
|
+
Используй когда: содержимое нужно вынести из DOM-иерархии родителя — выйти за
|
|
19
|
+
пределы контейнера с `overflow: hidden`, поверх `z-index`-контекста, в
|
|
20
|
+
`document.body` или произвольный узел (всплывающие слои, тултипы, дропдауны).
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
├── Portal.tsx # FC, 1 строка — createPortal
|
|
31
|
-
└── index.ts # Barrel
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Нет стилей, тестов, stories.
|
|
22
|
+
Не используй когда:
|
|
23
|
+
- Нужен готовый всплывающий слой с позиционированием и поведением — используй
|
|
24
|
+
`Dropdown`, `Tooltip`, `ModalWindow`: они уже рендерятся через Portal или
|
|
25
|
+
собственные механизмы.
|
|
26
|
+
- Контейнер ещё не существует на момент рендера — сначала дождись монтирования
|
|
27
|
+
узла (создай его через ref-callback/`useState`), затем рендери Portal.
|
|
35
28
|
|
|
36
29
|
---
|
|
37
30
|
|
|
38
31
|
## Варианты и props
|
|
39
32
|
|
|
40
|
-
###
|
|
33
|
+
### Обязательные props
|
|
41
34
|
|
|
42
|
-
| Prop | Тип |
|
|
43
|
-
|
|
44
|
-
| `children` | `ReactNode` |
|
|
45
|
-
| `container` | `Element \| DocumentFragment` |
|
|
35
|
+
| Prop | Тип | Описание |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `children` | `React.ReactNode` | Содержимое, рендерящееся в `container` |
|
|
38
|
+
| `container` | `Element \| DocumentFragment` | Существующий DOM-узел, в который рендерится содержимое |
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
Опциональных props нет. Компонент не рендерит собственный host-элемент и не
|
|
41
|
+
принимает `className`/rest-атрибуты — стилизуется сам `container` или
|
|
42
|
+
содержимое.
|
|
48
43
|
|
|
49
|
-
|
|
44
|
+
### Особенности поведения
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
- При смене `container` на rerender содержимое переносится в новый узел,
|
|
47
|
+
старый очищается.
|
|
48
|
+
- При unmount содержимое удаляется из `container`; сам узел-контейнер
|
|
49
|
+
компонент не создаёт и не удаляет — его жизненный цикл на потребителе.
|
|
50
|
+
- События из содержимого всплывают по React-дереву (к родителю Portal), а не
|
|
51
|
+
по DOM-дереву контейнера — стандартная семантика `createPortal`.
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
---
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
export const Portal = ({ children, container }) => ReactDOM.createPortal(children, container);
|
|
57
|
-
```
|
|
55
|
+
## Дизайн-токены
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
- **Контекст-провайдеры**, **events bubbling** работают, как если бы дерево было локальным (events bubble через React-tree, не DOM-tree).
|
|
57
|
+
Собственных стилей и CSS-переменных нет — компонент не рендерит разметку.
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
---
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
- Потребитель сам решает, куда монтировать (типичный паттерн: создать `<div>` в `document.body` и передать сюда).
|
|
61
|
+
## Инварианты
|
|
66
62
|
|
|
67
|
-
|
|
63
|
+
- **Без `forwardRef` — осознанное исключение** из общего правила библиотеки:
|
|
64
|
+
Portal не рендерит собственный host-элемент, ref форвардить некуда. Не
|
|
65
|
+
добавлять `forwardRef` без изменения контракта.
|
|
66
|
+
- **Имена props `children` и `container`** и тип `container: Element |
|
|
67
|
+
DocumentFragment` — публичное API с версии 1.21.0, не менять.
|
|
68
|
+
- **Интерфейс `IPortalProps`** экспортируется из barrel — не переименовывать.
|
|
69
|
+
- Реализация остаётся тонкой обёрткой над `ReactDOM.createPortal` (React
|
|
70
|
+
17-совместимый API) — не добавлять состояние, эффекты и React 18-only API:
|
|
71
|
+
код синхронизируется в release-0.
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
- В этом проекте — обычно через `useEffect` создают и монтируют контейнер (см. `ModalWindow`, `LightBox`).
|
|
73
|
+
---
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
## Accessibility
|
|
73
76
|
|
|
74
|
-
-
|
|
77
|
+
- Собственной ARIA-семантики нет — компонент прозрачен для accessibility-дерева.
|
|
78
|
+
- Портал не управляет фокусом: focus trap, возврат фокуса, `aria-modal` и
|
|
79
|
+
прочие контракты всплывающих слоёв — ответственность потребителя
|
|
80
|
+
(`ModalWindow`, `Dropdown` реализуют их самостоятельно).
|
|
81
|
+
- Учитывай порядок чтения screen reader'ом: содержимое читается в месте
|
|
82
|
+
`container` в DOM, а не в месте объявления.
|
|
75
83
|
|
|
76
84
|
---
|
|
77
85
|
|
|
78
|
-
##
|
|
86
|
+
## Связанные компоненты
|
|
79
87
|
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- **Никаких side effects** — нет `useEffect`, нет mount-классов, нет cleanup.
|
|
88
|
+
- `Dropdown` (`src/components/Dropdown/`) — рендерит выпадающий слой через
|
|
89
|
+
Portal в `document.body`.
|
|
90
|
+
- `Tooltip` (`src/components/Tooltip/`) — desktop- и mobile-реализации
|
|
91
|
+
рендерят тултип через Portal: mobile — всегда в `document.body`, desktop — в
|
|
92
|
+
`renderContainer ?? document.body`.
|
|
86
93
|
|
|
87
94
|
---
|
|
88
95
|
|
|
89
|
-
##
|
|
96
|
+
## Stories
|
|
97
|
+
|
|
98
|
+
Основные истории: `stories/Portal/Portal.stories.tsx`
|
|
99
|
+
Файлы примеров: `stories/Portal/examples/`
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
| Story | Example file | Что демонстрирует |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `Playground` | `Playground.tsx` | Интерактивный контроль `children`; `container` задаётся обёрткой (узел с пунктирной рамкой) |
|
|
104
|
+
| `Default` | `Default.tsx` | Содержимое рендерится в указанный DOM-узел, а не в месте объявления |
|
|
105
|
+
| `Example` | `Example.tsx` | Типовой сценарий: вынос содержимого из контейнера с `overflow: hidden` |
|
|
93
106
|
|
|
94
107
|
---
|
|
95
108
|
|
|
96
|
-
##
|
|
109
|
+
## История изменений
|
|
97
110
|
|
|
98
|
-
|
|
111
|
+
| Дата | Изменение |
|
|
112
|
+
|---|---|
|
|
113
|
+
| 2026-07-29 | Создан документ. AI-рефакторинг (TRI-67): JSDoc на props `IPortalProps`, unit-тесты (5 кейсов: рендер в container/DocumentFragment, rerender, смена container, unmount), stories по modern pattern. Публичный API не менялся; `forwardRef` осознанно отсутствует. |
|
|
99
114
|
|
|
100
115
|
---
|
|
101
116
|
|
|
102
|
-
##
|
|
117
|
+
## Примеры использования
|
|
103
118
|
|
|
104
|
-
|
|
105
|
-
- `react-dom` `createPortal` — нативный API.
|
|
119
|
+
### Default
|
|
106
120
|
|
|
107
|
-
|
|
121
|
+
`stories/Portal/examples/Default.tsx`
|
|
108
122
|
|
|
109
|
-
|
|
123
|
+
```tsx
|
|
124
|
+
import React, { useState } from "react";
|
|
125
|
+
import { Portal } from "@sberbusiness/triplex-next";
|
|
126
|
+
|
|
127
|
+
export const Default = () => {
|
|
128
|
+
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "16px", maxWidth: "400px" }}>
|
|
132
|
+
<div>Компонент Portal объявлен здесь, но его содержимое рендерится в контейнер с пунктирной рамкой.</div>
|
|
133
|
+
<div
|
|
134
|
+
ref={setContainer}
|
|
135
|
+
style={{ border: "1px dashed rgb(125, 131, 138)", borderRadius: "4px", padding: "16px" }}
|
|
136
|
+
/>
|
|
137
|
+
{container && <Portal container={container}>Содержимое, отрендеренное через Portal.</Portal>}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
```
|
|
110
142
|
|
|
111
|
-
|
|
143
|
+
### Example
|
|
112
144
|
|
|
113
|
-
|
|
145
|
+
`stories/Portal/examples/Example.tsx`
|
|
114
146
|
|
|
115
|
-
|
|
147
|
+
```tsx
|
|
148
|
+
import React, { useState } from "react";
|
|
149
|
+
import { Portal } from "@sberbusiness/triplex-next";
|
|
150
|
+
|
|
151
|
+
export const Example = () => {
|
|
152
|
+
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "16px", maxWidth: "400px" }}>
|
|
156
|
+
<div
|
|
157
|
+
style={{
|
|
158
|
+
border: "1px solid rgb(125, 131, 138)",
|
|
159
|
+
borderRadius: "4px",
|
|
160
|
+
padding: "16px",
|
|
161
|
+
height: "48px",
|
|
162
|
+
overflow: "hidden",
|
|
163
|
+
}}
|
|
164
|
+
>
|
|
165
|
+
<div>Контейнер с overflow: hidden и фиксированной высотой.</div>
|
|
166
|
+
{container && (
|
|
167
|
+
<Portal container={container}>
|
|
168
|
+
<div>
|
|
169
|
+
Это содержимое объявлено внутри контейнера с overflow: hidden, но через Portal отрендерено
|
|
170
|
+
во внешний узел с пунктирной рамкой, поэтому не обрезается и видно полностью.
|
|
171
|
+
</div>
|
|
172
|
+
</Portal>
|
|
173
|
+
)}
|
|
174
|
+
</div>
|
|
175
|
+
<div
|
|
176
|
+
ref={setContainer}
|
|
177
|
+
style={{ border: "1px dashed rgb(125, 131, 138)", borderRadius: "4px", padding: "16px" }}
|
|
178
|
+
/>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
```
|
|
116
183
|
|
|
117
|
-
| Дата | Изменение |
|
|
118
|
-
|---|---|
|
|
119
|
-
| 2026-04-18 | Создан документ |
|
package/bundle/components/Row.md
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Row
|
|
3
3
|
category: Layout
|
|
4
|
-
|
|
5
|
-
figma-file: ""
|
|
6
|
-
related: [Col, Container]
|
|
4
|
+
related: [Col, Gap]
|
|
7
5
|
tokens: []
|
|
8
6
|
stories: stories/Row/Row.stories.tsx
|
|
9
7
|
version: "1.0"
|
|
@@ -13,108 +11,87 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
Строка
|
|
17
|
-
**отрицательными margin'ами по бокам** для компенсации gutter'ов
|
|
18
|
-
дочерних `Col`. Рекомендованный child — `Col`.
|
|
14
|
+
Строка сетки: flex-контейнер с нижним отступом, предназначенный для использования с колонками `Col` в children. Передаёт размер горизонтального отступа между колонками (`gridHorizontalGap`) в дочерние `Col` через внутренний `RowContext`.
|
|
19
15
|
|
|
20
|
-
Используй когда:
|
|
21
|
-
Для нестандартного layout'а — flex/grid-CSS напрямую.
|
|
16
|
+
Используй когда: нужно разместить контент в колоночной сетке — несколько `Col` в одной строке с управляемым горизонтальным отступом между ними и вертикальным отступом между строками.
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```text
|
|
28
|
-
src/components/Row/
|
|
29
|
-
├── Row.tsx # FC; <div> + flex layout
|
|
30
|
-
├── styles/Row.module.less # margin -horizontal-gap, padding-bottom
|
|
31
|
-
├── index.ts # Barrel
|
|
32
|
-
└── __tests__/
|
|
33
|
-
```
|
|
18
|
+
Не используй когда:
|
|
19
|
+
- Нужен только вертикальный отступ между блоками без колонок — используй `Gap`.
|
|
20
|
+
- Children — не колонки `Col`: компонент рассчитан на связку `Row` → `Col`, отрицательные боковые margin компенсируются padding колонок.
|
|
34
21
|
|
|
35
22
|
---
|
|
36
23
|
|
|
37
24
|
## Варианты и props
|
|
38
25
|
|
|
39
|
-
###
|
|
40
|
-
|
|
41
|
-
| Prop | Тип | Default | Описание |
|
|
42
|
-
|---|---|---|---|
|
|
43
|
-
| `paddingBottom` | `boolean` | `true` | Нижний отступ строки. `false` — отключить. |
|
|
44
|
-
| `...HTMLAttributes` | — | — | На корневой `<div>`. |
|
|
45
|
-
|
|
46
|
-
- `paddingBottom: false` → класс `noPaddingBottom`.
|
|
47
|
-
- **Последняя `Row` в родителе** автоматически получает `padding-bottom: 0` через CSS-селектор `:last-child`.
|
|
48
|
-
|
|
49
|
-
---
|
|
26
|
+
### Обязательные props
|
|
50
27
|
|
|
51
|
-
|
|
28
|
+
Обязательных props нет.
|
|
52
29
|
|
|
53
|
-
###
|
|
30
|
+
### Опциональные props
|
|
54
31
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
margin-left: -@grid-horizontal-gap;
|
|
60
|
-
margin-right: -@grid-horizontal-gap;
|
|
61
|
-
padding-bottom: @row-bottom-padding;
|
|
62
|
-
}
|
|
63
|
-
```
|
|
32
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| `paddingBottom` | `boolean` | `true` | Нижний отступ строки (16px). При `false` — отступ убирается. У последней строки (`:last-child`) отступ убирается стилями независимо от значения prop. |
|
|
35
|
+
| `gridHorizontalGap` | `EComponentSize.SM \| EComponentSize.MD` | `EComponentSize.SM` | Размер отступа между колонками: SM — 8px, MD — 12px. Передаётся в дочерние `Col` через `RowContext`. |
|
|
64
36
|
|
|
65
|
-
|
|
66
|
-
- Стандартный bootstrap-style grid pattern.
|
|
37
|
+
Компонент расширяет `React.HTMLAttributes<HTMLDivElement>` — принимает все стандартные атрибуты `<div>` (`className`, `style`, `aria-*`, `data-*` и т.д.).
|
|
67
38
|
|
|
68
|
-
###
|
|
39
|
+
### Ограничения
|
|
69
40
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
41
|
+
- `gridHorizontalGap` намеренно сужен до `SM | MD` — остальные значения `EComponentSize` не входят в контракт сетки.
|
|
42
|
+
- Механика gap: `Row` задаёт отрицательные `margin-left`/`margin-right`, а `Col` — соответствующий горизонтальный padding (значение получает из `RowContext`). Управлять gap нужно только через prop на `Row`, а не стилями `Col`.
|
|
72
43
|
|
|
73
|
-
|
|
44
|
+
---
|
|
74
45
|
|
|
75
|
-
|
|
46
|
+
## Дизайн-токены
|
|
76
47
|
|
|
77
|
-
|
|
48
|
+
Компонент не использует CSS-переменных `--triplex-next-*`. Размеры берутся из LESS-переменных сетки в `src/styles/components/grid.less`:
|
|
78
49
|
|
|
79
|
-
|
|
50
|
+
```less
|
|
51
|
+
@row-bottom-padding: 16px
|
|
52
|
+
@grid-horizontal-gap-SM: 8px
|
|
53
|
+
@grid-horizontal-gap-MD: 12px
|
|
54
|
+
```
|
|
80
55
|
|
|
81
56
|
---
|
|
82
57
|
|
|
83
58
|
## Инварианты
|
|
84
59
|
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
60
|
+
- **`forwardRef`** — обязателен, не убирать. `ref` пробрасывается на корневой `<div>`.
|
|
61
|
+
- **Имена публичного API**: компонент `Row`, интерфейс `IRowProps`, props `paddingBottom`, `gridHorizontalGap` и их дефолты — менять нельзя (breaking change).
|
|
62
|
+
- **Barrel `src/components/Row/index.ts` экспортирует только `./Row`** — `RowContext` остаётся внутренним модулем, в barrel не добавлять.
|
|
63
|
+
- **`RowContext` — внутренний контракт с `Col`**: `Col` читает `gridHorizontalGap` из контекста (`src/components/Col/Col.tsx`). Изменение формы `IRowContext` или дефолтного значения контекста требует синхронного обновления `Col`.
|
|
64
|
+
- **Значение контекста мемоизировано** (`React.useMemo` по `gridHorizontalGap`) — не убирать, иначе все `Col`-потребители будут перерендериваться на каждом рендере `Row`.
|
|
65
|
+
- **Корневой DOM-элемент — `<div>`** без ARIA-роли.
|
|
66
|
+
- **CSS-классы `SM`, `MD`, `noPaddingBottom`** в `Row.module.less` используются в unit-тестах; класс `row` — корневой, тестами не проверяется, но фиксируется visual baseline. `SM`/`MD` — исторически не camelCase, переименование требует синхронного обновления тестов и проверки visual baseline.
|
|
67
|
+
- **`displayName = "Row"`** — проверяется тестом.
|
|
91
68
|
|
|
92
69
|
---
|
|
93
70
|
|
|
94
71
|
## Accessibility
|
|
95
72
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Дизайн-токены
|
|
101
|
-
|
|
102
|
-
LESS-переменные (через `@import '../../../styles/style'`):
|
|
103
|
-
- `@grid-horizontal-gap` — горизонтальный gap.
|
|
104
|
-
- `@row-bottom-padding` — нижний отступ.
|
|
73
|
+
Компонент не интерактивный: рендерит обычный `<div>` без роли, keyboard navigation и focus management не применимы. Потребитель может передать `role` и `aria-*` атрибуты через spread.
|
|
105
74
|
|
|
106
75
|
---
|
|
107
76
|
|
|
108
77
|
## Связанные компоненты
|
|
109
78
|
|
|
110
|
-
- `Col` —
|
|
111
|
-
-
|
|
79
|
+
- `Col` (`src/components/Col/`) — колонка сетки, единственный ожидаемый тип children. Потребляет `gridHorizontalGap` из `RowContext`.
|
|
80
|
+
- `Gap` (`src/components/Gap/`) — вертикальный отступ-разделитель вне колоночной сетки.
|
|
112
81
|
|
|
113
82
|
---
|
|
114
83
|
|
|
115
84
|
## Stories
|
|
116
85
|
|
|
117
|
-
`stories/Row/Row.stories.tsx`
|
|
86
|
+
Основные истории: `stories/Row/Row.stories.tsx`
|
|
87
|
+
Файлы примеров: `stories/Row/examples/`
|
|
88
|
+
|
|
89
|
+
| Story | Example file | Что демонстрирует |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `Playground` | `Playground.tsx` | Интерактивный контроль `paddingBottom` и `gridHorizontalGap` |
|
|
92
|
+
| `Default` | `Default.tsx` | Две строки по две колонки, отступ между строками по умолчанию |
|
|
93
|
+
| `GridHorizontalGaps` | `GridHorizontalGaps.tsx` | Отступы между колонками SM (8px) и MD (12px) |
|
|
94
|
+
| `WithoutPaddingBottom` | `WithoutPaddingBottom.tsx` | Строки 1 и 3 с `paddingBottom={false}` в контрасте со строкой 2 с отступом по умолчанию |
|
|
118
95
|
|
|
119
96
|
---
|
|
120
97
|
|
|
@@ -122,4 +99,129 @@ LESS-переменные (через `@import '../../../styles/style'`):
|
|
|
122
99
|
|
|
123
100
|
| Дата | Изменение |
|
|
124
101
|
|---|---|
|
|
125
|
-
| 2026-
|
|
102
|
+
| 2026-07-28 | Создан документ. AI-рефакторинг (TRI-71): добавлен `forwardRef`, значение `RowContext` мемоизировано, JSDoc на props и контекст, расширены unit-тесты (ref, проброс gap через контекст); stories переведены на modern pattern (`stories/Row/`), включены визуальные тесты. |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Примеры использования
|
|
107
|
+
|
|
108
|
+
### Default
|
|
109
|
+
|
|
110
|
+
`stories/Row/examples/Default.tsx`
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import React from "react";
|
|
114
|
+
import { Col, Row } from "@sberbusiness/triplex-next";
|
|
115
|
+
|
|
116
|
+
export const Default = () => (
|
|
117
|
+
<div style={{ maxWidth: "320px" }}>
|
|
118
|
+
<Row>
|
|
119
|
+
<Col size={6}>
|
|
120
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
121
|
+
Row 1, Col 1
|
|
122
|
+
</div>
|
|
123
|
+
</Col>
|
|
124
|
+
<Col size={6}>
|
|
125
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
126
|
+
Row 1, Col 2
|
|
127
|
+
</div>
|
|
128
|
+
</Col>
|
|
129
|
+
</Row>
|
|
130
|
+
<Row>
|
|
131
|
+
<Col size={6}>
|
|
132
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
133
|
+
Row 2, Col 1
|
|
134
|
+
</div>
|
|
135
|
+
</Col>
|
|
136
|
+
<Col size={6}>
|
|
137
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
138
|
+
Row 2, Col 2
|
|
139
|
+
</div>
|
|
140
|
+
</Col>
|
|
141
|
+
</Row>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### GridHorizontalGaps
|
|
147
|
+
|
|
148
|
+
`stories/Row/examples/GridHorizontalGaps.tsx`
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import React from "react";
|
|
152
|
+
import { Col, EComponentSize, Row } from "@sberbusiness/triplex-next";
|
|
153
|
+
|
|
154
|
+
export const GridHorizontalGaps = () => (
|
|
155
|
+
<div style={{ maxWidth: "320px" }}>
|
|
156
|
+
<div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>SM</div>
|
|
157
|
+
<Row gridHorizontalGap={EComponentSize.SM}>
|
|
158
|
+
<Col size={6}>
|
|
159
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>Col 1</div>
|
|
160
|
+
</Col>
|
|
161
|
+
<Col size={6}>
|
|
162
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>Col 2</div>
|
|
163
|
+
</Col>
|
|
164
|
+
</Row>
|
|
165
|
+
<div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>MD</div>
|
|
166
|
+
<Row gridHorizontalGap={EComponentSize.MD}>
|
|
167
|
+
<Col size={6}>
|
|
168
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>Col 1</div>
|
|
169
|
+
</Col>
|
|
170
|
+
<Col size={6}>
|
|
171
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>Col 2</div>
|
|
172
|
+
</Col>
|
|
173
|
+
</Row>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### WithoutPaddingBottom
|
|
179
|
+
|
|
180
|
+
`stories/Row/examples/WithoutPaddingBottom.tsx`
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import React from "react";
|
|
184
|
+
import { Col, Row } from "@sberbusiness/triplex-next";
|
|
185
|
+
|
|
186
|
+
export const WithoutPaddingBottom = () => (
|
|
187
|
+
<div style={{ maxWidth: "320px" }}>
|
|
188
|
+
<Row paddingBottom={false}>
|
|
189
|
+
<Col size={6}>
|
|
190
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
191
|
+
Row 1, Col 1
|
|
192
|
+
</div>
|
|
193
|
+
</Col>
|
|
194
|
+
<Col size={6}>
|
|
195
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
196
|
+
Row 1, Col 2
|
|
197
|
+
</div>
|
|
198
|
+
</Col>
|
|
199
|
+
</Row>
|
|
200
|
+
<Row>
|
|
201
|
+
<Col size={6}>
|
|
202
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
203
|
+
Row 2, Col 1
|
|
204
|
+
</div>
|
|
205
|
+
</Col>
|
|
206
|
+
<Col size={6}>
|
|
207
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
208
|
+
Row 2, Col 2
|
|
209
|
+
</div>
|
|
210
|
+
</Col>
|
|
211
|
+
</Row>
|
|
212
|
+
<Row paddingBottom={false}>
|
|
213
|
+
<Col size={6}>
|
|
214
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
215
|
+
Row 3, Col 1
|
|
216
|
+
</div>
|
|
217
|
+
</Col>
|
|
218
|
+
<Col size={6}>
|
|
219
|
+
<div style={{ padding: "16px", textAlign: "center", backgroundColor: "rgb(255, 217, 160)" }}>
|
|
220
|
+
Row 3, Col 2
|
|
221
|
+
</div>
|
|
222
|
+
</Col>
|
|
223
|
+
</Row>
|
|
224
|
+
</div>
|
|
225
|
+
);
|
|
226
|
+
```
|
|
227
|
+
|