@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.
- package/README.md +124 -0
- package/bundle/.gitkeep +0 -0
- package/bundle/components/AbstractTree.md +198 -0
- package/bundle/components/AccordionBase.md +227 -0
- package/bundle/components/Alert.md +317 -0
- package/bundle/components/Amount.md +225 -0
- package/bundle/components/AmountField.md +289 -0
- package/bundle/components/Avatar.md +209 -0
- package/bundle/components/Badge.md +277 -0
- package/bundle/components/Body.md +167 -0
- package/bundle/components/Button.md +230 -0
- package/bundle/components/ButtonDropdown.md +159 -0
- package/bundle/components/ButtonIcon.md +122 -0
- package/bundle/components/Calendar.md +445 -0
- package/bundle/components/Card.md +374 -0
- package/bundle/components/CarouselExtended.md +250 -0
- package/bundle/components/Checkbox.md +126 -0
- package/bundle/components/CheckboxTree.md +280 -0
- package/bundle/components/CheckboxTreeExtended.md +321 -0
- package/bundle/components/CheckboxXGroup.md +68 -0
- package/bundle/components/CheckboxYGroup.md +67 -0
- package/bundle/components/Chip.md +404 -0
- package/bundle/components/ChipGroup.md +179 -0
- package/bundle/components/Col.md +221 -0
- package/bundle/components/CollapsableTree.md +255 -0
- package/bundle/components/Confirm.md +343 -0
- package/bundle/components/DateField.md +371 -0
- package/bundle/components/DatePickerExtended.md +342 -0
- package/bundle/components/DateRange.md +275 -0
- package/bundle/components/DesignTokens.md +385 -0
- package/bundle/components/Divider.md +196 -0
- package/bundle/components/DocumentNumberEdit.md +280 -0
- package/bundle/components/Dropdown.md +433 -0
- package/bundle/components/Ellipsis.md +208 -0
- package/bundle/components/EmptyView.md +99 -0
- package/bundle/components/ExpandAnimation.md +281 -0
- package/bundle/components/Footer.md +339 -0
- package/bundle/components/FormField.md +326 -0
- package/bundle/components/FormGroup.md +99 -0
- package/bundle/components/Gap.md +113 -0
- package/bundle/components/Header.md +280 -0
- package/bundle/components/HelpBox.md +154 -0
- package/bundle/components/IconWrapper.md +145 -0
- package/bundle/components/Island.md +197 -0
- package/bundle/components/IslandAccordion.md +230 -0
- package/bundle/components/IslandWidget.md +233 -0
- package/bundle/components/KeyDownListener.md +157 -0
- package/bundle/components/LightBox.md +322 -0
- package/bundle/components/Link.md +161 -0
- package/bundle/components/List.md +247 -0
- package/bundle/components/ListMaster.md +204 -0
- package/bundle/components/Loader.md +161 -0
- package/bundle/components/LoaderScreen.md +134 -0
- package/bundle/components/Marker.md +127 -0
- package/bundle/components/MarkerStatus.md +148 -0
- package/bundle/components/MediaWidth.md +169 -0
- package/bundle/components/MobileView.md +120 -0
- package/bundle/components/ModalWindow.md +308 -0
- package/bundle/components/MonthYearField.md +168 -0
- package/bundle/components/MultiselectField.md +213 -0
- package/bundle/components/Notification.md +233 -0
- package/bundle/components/NumberField.md +178 -0
- package/bundle/components/OrderedList.md +169 -0
- package/bundle/components/Overlay.md +237 -0
- package/bundle/components/Page.md +246 -0
- package/bundle/components/Pagination.md +298 -0
- package/bundle/components/Portal.md +119 -0
- package/bundle/components/Radio.md +174 -0
- package/bundle/components/Row.md +125 -0
- package/bundle/components/SMSField.md +160 -0
- package/bundle/components/SegmentedControl.md +235 -0
- package/bundle/components/SelectExtendedField.md +322 -0
- package/bundle/components/SelectField.md +213 -0
- package/bundle/components/Skeleton.md +129 -0
- package/bundle/components/Slider.md +157 -0
- package/bundle/components/SliderExtended.md +210 -0
- package/bundle/components/SliderRange.md +160 -0
- package/bundle/components/SmallInput.md +101 -0
- package/bundle/components/Spoiler.md +121 -0
- package/bundle/components/StatusTracker.md +151 -0
- package/bundle/components/Step.md +121 -0
- package/bundle/components/Stepper.md +163 -0
- package/bundle/components/Suggest.md +160 -0
- package/bundle/components/SuggestField.md +157 -0
- package/bundle/components/SwipeableArea.md +144 -0
- package/bundle/components/Table.md +199 -0
- package/bundle/components/Tabs.md +152 -0
- package/bundle/components/TabsExtended.md +273 -0
- package/bundle/components/TabsLine.md +189 -0
- package/bundle/components/Tag.md +135 -0
- package/bundle/components/TagColor.md +121 -0
- package/bundle/components/TagGroup.md +100 -0
- package/bundle/components/TextField.md +152 -0
- package/bundle/components/TextareaField.md +124 -0
- package/bundle/components/ThemeProvider.md +181 -0
- package/bundle/components/Tooltip.md +254 -0
- package/bundle/components/TopOverlay.md +145 -0
- package/bundle/components/TreeView.md +224 -0
- package/bundle/components/Triggers.md +121 -0
- package/bundle/guides/codestyle.md +205 -0
- package/bundle/guides/commits.md +166 -0
- package/bundle/guides/context.md +277 -0
- package/bundle/guides/stories.md +618 -0
- package/bundle/guides/template.md +154 -0
- package/bundle/guides/tests.md +301 -0
- package/bundle/icons.json +4156 -0
- package/bundle/manifest.json +796 -0
- package/bundle/release-notes/1.1.0.mdx +26 -0
- package/bundle/release-notes/1.1.1.mdx +14 -0
- package/bundle/release-notes/1.10.0.mdx +43 -0
- package/bundle/release-notes/1.11.0.mdx +19 -0
- package/bundle/release-notes/1.12.0.mdx +21 -0
- package/bundle/release-notes/1.13.0.mdx +43 -0
- package/bundle/release-notes/1.14.0.mdx +29 -0
- package/bundle/release-notes/1.15.0.mdx +56 -0
- package/bundle/release-notes/1.16.0.mdx +55 -0
- package/bundle/release-notes/1.17.0.mdx +15 -0
- package/bundle/release-notes/1.18.0.mdx +24 -0
- package/bundle/release-notes/1.19.0.mdx +48 -0
- package/bundle/release-notes/1.19.1.mdx +9 -0
- package/bundle/release-notes/1.2.0.mdx +80 -0
- package/bundle/release-notes/1.20.0.mdx +48 -0
- package/bundle/release-notes/1.21.0.mdx +66 -0
- package/bundle/release-notes/1.22.0.mdx +75 -0
- package/bundle/release-notes/1.23.0.mdx +50 -0
- package/bundle/release-notes/1.24.0.mdx +59 -0
- package/bundle/release-notes/1.25.0.mdx +52 -0
- package/bundle/release-notes/1.26.0.mdx +11 -0
- package/bundle/release-notes/1.3.0.mdx +21 -0
- package/bundle/release-notes/1.4.0.mdx +37 -0
- package/bundle/release-notes/1.5.0.mdx +24 -0
- package/bundle/release-notes/1.6.0.mdx +37 -0
- package/bundle/release-notes/1.6.1.mdx +11 -0
- package/bundle/release-notes/1.7.0.mdx +29 -0
- package/bundle/release-notes/1.8.0.mdx +38 -0
- package/bundle/release-notes/1.9.0.mdx +28 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: Col
|
|
3
|
+
category: Layout
|
|
4
|
+
figma-node: ""
|
|
5
|
+
figma-file: ""
|
|
6
|
+
related: [Row, Page, Gap]
|
|
7
|
+
tokens: []
|
|
8
|
+
stories: stories/Col/Col.stories.tsx
|
|
9
|
+
version: "1.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Col
|
|
13
|
+
|
|
14
|
+
## Назначение
|
|
15
|
+
|
|
16
|
+
Ячейка responsive-grid, реализованная в духе Bootstrap 4 (12-колоночная
|
|
17
|
+
сетка). Управляет шириной колонки, offset'ом и видимостью через
|
|
18
|
+
breakpoint-префиксы (base / sm / md / lg / xl). Всегда используется
|
|
19
|
+
внутри `Row` (который создаёт flex-контейнер с отрицательными margin'ами
|
|
20
|
+
для компенсации padding'ов Col).
|
|
21
|
+
|
|
22
|
+
`Col` — FC-обёртка над `<div>` с композицией CSS-классов по пропсам.
|
|
23
|
+
Сами CSS-классы генерируются LESS-миксином `createCol` для всех
|
|
24
|
+
breakpoint-префиксов.
|
|
25
|
+
|
|
26
|
+
Используй когда: нужна responsive-сетка страницы/формы с точным контролем
|
|
27
|
+
ширины колонок на разных разрешениях.
|
|
28
|
+
Не используй когда: простой flex/grid вручную проще — брать Col только
|
|
29
|
+
ради одной колонки не нужно; для фиксированных отступов между блоками —
|
|
30
|
+
бери `Gap`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Файловая структура
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
src/components/Col/
|
|
38
|
+
├── Col.tsx # React.FC, нет forwardRef
|
|
39
|
+
├── index.ts # Barrel
|
|
40
|
+
├── styles/Col.module.less # LESS миксин createCol(), генерирует классы
|
|
41
|
+
└── __tests__/
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Особенности:
|
|
45
|
+
- **Нет forwardRef** — FC без ref-форвардинга. Это известный AI-ready debt.
|
|
46
|
+
Не добавлять точечно.
|
|
47
|
+
- **LESS-миксин `createCol(@resolutionType)`** — генерирует 12 column-классов
|
|
48
|
+
и 12 offset-классов для каждого breakpoint'а. Добавление нового breakpoint —
|
|
49
|
+
одна строка в LESS.
|
|
50
|
+
- **Bootstrap-подобный API**: `col-1..12`, `col-sm-1..12`, `col-md-*`, `col-lg-*`, `col-xl-*`,
|
|
51
|
+
`offset-*`, `d-none`, `d-block`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Варианты и props
|
|
56
|
+
|
|
57
|
+
### `IColProps extends React.HTMLAttributes<HTMLDivElement>`
|
|
58
|
+
|
|
59
|
+
**Base (применяется на всех разрешениях):**
|
|
60
|
+
|
|
61
|
+
| Prop | Тип | Default | Описание |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `size` | `TColumnSize` (1..12) | `12` | Ширина колонки в 12-ти колоночной сетке. |
|
|
64
|
+
| `offset` | `TOffsetSize` (0..11) | — | Отступ слева в колонках. |
|
|
65
|
+
| `hidden` | `boolean` | — | `display: none !important`. |
|
|
66
|
+
| `block` | `boolean` | — | `display: block !important`. |
|
|
67
|
+
|
|
68
|
+
**Responsive (каждый breakpoint-префикс дублирует все 4):**
|
|
69
|
+
|
|
70
|
+
| Breakpoint | Size prop | Offset prop | Hidden prop | Block prop | Media |
|
|
71
|
+
|---|---|---|---|---|---|
|
|
72
|
+
| sm | `sizeSm` | `offsetSm` | `hiddenSm` | `blockSm` | `(min-width: @screen-sm)` |
|
|
73
|
+
| md | `sizeMd` | `offsetMd` | `hiddenMd` | `blockMd` | `(min-width: @screen-md)` |
|
|
74
|
+
| lg | `sizeLg` | `offsetLg` | `hiddenLg` | `blockLg` | `(min-width: @screen-lg)` |
|
|
75
|
+
| xl | `sizeXl` | `offsetXl` | `hiddenXl` | `blockXl` | `(min-width: @screen-xl)` |
|
|
76
|
+
|
|
77
|
+
**Стандартные:**
|
|
78
|
+
|
|
79
|
+
| Prop | Тип | Описание |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `children` | `ReactNode` | Контент колонки. |
|
|
82
|
+
| `className` | `string` | Доп. класс. |
|
|
83
|
+
| `...HTMLDivAttributes` | — | Все стандартные. |
|
|
84
|
+
|
|
85
|
+
### Types
|
|
86
|
+
|
|
87
|
+
- `TColumnSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12`
|
|
88
|
+
- `TOffsetSize = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11`
|
|
89
|
+
|
|
90
|
+
Offset — до 11 (12 offset занял бы всю строку, колонки бы не было).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Ключевые особенности реализации
|
|
95
|
+
|
|
96
|
+
### `getClassNames` helper
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
function getClassNames({ block, hidden, offset, prefix, size }) {
|
|
100
|
+
const prefixAsPart = prefix ? `${prefix}-` : "";
|
|
101
|
+
const prefixVisibility = prefix ? `-${prefix}` : "";
|
|
102
|
+
// ...
|
|
103
|
+
if (size) classes.push(`col-${prefixAsPart}${size}`);
|
|
104
|
+
if (offset !== undefined) classes.push(`offset-${prefixAsPart}${offset}`);
|
|
105
|
+
if (block) classes.push(`d-block${prefixVisibility}`);
|
|
106
|
+
if (hidden) classes.push(`d-none${prefixVisibility}`);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Асимметрия префиксов**: `col-sm-6` (префикс в середине), но `d-block-sm`
|
|
111
|
+
(префикс в конце). Это Bootstrap-ная конвенция, повторённая один-в-один.
|
|
112
|
+
Не менять без миграции пользователей.
|
|
113
|
+
|
|
114
|
+
### Классы собираются в массив → `styles[...]`
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const mappedClasses = classNames.map((c) => styles[c]).filter(Boolean);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Имена классов — это ключи в LESS module объекте. `filter(Boolean)`
|
|
121
|
+
защищает от опечаток (если бы класс не существовал → `undefined`).
|
|
122
|
+
|
|
123
|
+
### `size = 12` по умолчанию
|
|
124
|
+
|
|
125
|
+
Если size не задан — колонка занимает всю ширину. Это конвенция Bootstrap.
|
|
126
|
+
На узких экранах (без sm/md/lg overrides) колонка всегда full-width,
|
|
127
|
+
что даёт mobile-first сетку.
|
|
128
|
+
|
|
129
|
+
### `.d-none` / `.d-block` с `!important`
|
|
130
|
+
|
|
131
|
+
```less
|
|
132
|
+
.d-none { display: none !important; }
|
|
133
|
+
.d-block { display: block !important; }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`!important` нужен, потому что `.col-*` уже имеет `display` (через flex
|
|
137
|
+
item родителя). Без important не переопределяли бы.
|
|
138
|
+
|
|
139
|
+
### LESS `each` + `range` генерируют классы
|
|
140
|
+
|
|
141
|
+
```less
|
|
142
|
+
each(range(12), {
|
|
143
|
+
.col-@{resolutionType}@{value} { ... flex: 0 0 (@base-col * @value); max-width: (...); }
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Один миксин — 12 col- + 12 offset-. Вызывается для каждого breakpoint'а.
|
|
148
|
+
**Если добавить XXL** — одна строка `.createCol(xxl-);` в media-query.
|
|
149
|
+
|
|
150
|
+
### `@grid-horizontal-gap` — не токен, а LESS-переменная
|
|
151
|
+
|
|
152
|
+
В `src/styles/style.less`. Часть grid-системы (не в список токенов
|
|
153
|
+
компонента). Должен быть синхронизирован с Row'ом (у которого
|
|
154
|
+
отрицательный margin).
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Инварианты
|
|
159
|
+
|
|
160
|
+
- **`size` default = 12** — полная ширина, mobile-first поведение. Не менять.
|
|
161
|
+
- **`TColumnSize` ограничен 1..12** — не расширять. 12 — bootstrap-константа.
|
|
162
|
+
- **`TOffsetSize` ограничен 0..11** — offset=12 бессмыслен.
|
|
163
|
+
- **LESS миксин `createCol`** — источник истины для имён классов. Если
|
|
164
|
+
переименовывать схему — обновлять **и** миксин, **и** `getClassNames`.
|
|
165
|
+
- **Асимметричные префиксы** `col-sm-*` vs `d-block-sm` — Bootstrap
|
|
166
|
+
конвенция. Не унифицировать.
|
|
167
|
+
- **`!important` на `.d-none` / `.d-block`** — не удалять.
|
|
168
|
+
- **`Col` всегда внутри `Row`** — работает flex-сеткой. Col без Row
|
|
169
|
+
получает полную ширину и нет gap-компенсации.
|
|
170
|
+
- **Нет forwardRef** — документированный debt. Не добавлять точечно.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Accessibility
|
|
175
|
+
|
|
176
|
+
- **Нет ARIA** — div без семантики.
|
|
177
|
+
- **`hidden`** через `display: none` полностью убирает элемент из
|
|
178
|
+
доступности (screen reader не читает, клавиатура пропускает). Это
|
|
179
|
+
ожидаемо для скрытия элементов по breakpoint'у.
|
|
180
|
+
- **Порядок DOM = порядок источника**. Если нужно визуально переставить
|
|
181
|
+
колонки (order), использовать `order` CSS — Col этого не делает сам.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Дизайн-токены
|
|
186
|
+
|
|
187
|
+
Нет — компонент использует LESS-переменные сетки (`@grid-horizontal-gap`,
|
|
188
|
+
`@screen-sm/md/lg/xl`), не CSS-токены.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Связанные компоненты
|
|
193
|
+
|
|
194
|
+
- `Row` (`src/components/Row`) — обязательный родитель. Создаёт flex-контейнер
|
|
195
|
+
с отрицательными margin'ами для Col.
|
|
196
|
+
- `Page` (`src/components/Page`) — страничный layout, часто использует
|
|
197
|
+
Col/Row внутри для структуры.
|
|
198
|
+
- `Gap` (`src/components/Gap`) — для вертикальных отступов между блоками
|
|
199
|
+
(Col — горизонтальные колонки).
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Stories
|
|
204
|
+
|
|
205
|
+
`stories/Col/Col.stories.tsx`
|
|
206
|
+
Примеры: `stories/Col/examples/`
|
|
207
|
+
|
|
208
|
+
Типовые stories:
|
|
209
|
+
- `Default` — колонки равной ширины
|
|
210
|
+
- `Sizes` — разные size на разных breakpoint'ах
|
|
211
|
+
- `Offsets` — с отступами
|
|
212
|
+
- `Hidden/Block` — responsive visibility
|
|
213
|
+
- `Playground` — интерактив
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## История изменений
|
|
218
|
+
|
|
219
|
+
| Дата | Изменение |
|
|
220
|
+
|---|---|
|
|
221
|
+
| 2026-04-18 | Создан документ |
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: CollapsableTree
|
|
3
|
+
category: Internal
|
|
4
|
+
figma-node: ""
|
|
5
|
+
figma-file: ""
|
|
6
|
+
related: [TreeView, AccordionBase, CheckboxTreeExtended, Spoiler]
|
|
7
|
+
tokens: []
|
|
8
|
+
stories: ""
|
|
9
|
+
version: "1.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# CollapsableTree
|
|
13
|
+
|
|
14
|
+
## Назначение
|
|
15
|
+
|
|
16
|
+
Внутренний компонент-"фабрика" для деревьев с раскрывающимися узлами.
|
|
17
|
+
Оборачивает `TreeView` (клавиатурная навигация и активная нода) и подключает
|
|
18
|
+
`AccordionBase` (анимация раскрытия/сворачивания) в каждом узле.
|
|
19
|
+
|
|
20
|
+
Публично **не используется напрямую** потребителями библиотеки — предоставляет
|
|
21
|
+
основу для `CheckboxTreeExtended` и подобных. Потребитель получает
|
|
22
|
+
render-функции `renderHeader` и `renderBody`, управляя ими формирует DOM
|
|
23
|
+
с кастомной разметкой.
|
|
24
|
+
|
|
25
|
+
Используй когда: строишь новый tree-based компонент библиотеки, которому
|
|
26
|
+
нужна анимация открытия + клавиатурная навигация.
|
|
27
|
+
Не используй напрямую в приложениях — нестабильный публичный API, бери
|
|
28
|
+
готовый `CheckboxTreeExtended` / `CheckboxTree` / аналог.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Файловая структура
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
src/components/CollapsableTree/
|
|
36
|
+
├── CollapsableTree.tsx # SFC, обёртка TreeView, compound .Node
|
|
37
|
+
├── components/CollapsableTreeNode.tsx # Class component, композитит TreeView.Node + AccordionBase
|
|
38
|
+
└── styles/CollapsableTree.module.less # .collapsableTreeNodeContent.collapsed { visibility: hidden }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Особенности:
|
|
42
|
+
- **Нет `index.ts`** — компонент импортируется напрямую из `CollapsableTree.tsx`
|
|
43
|
+
(и подкомпонентов). Не стандартизованный барел, потому что внутренний.
|
|
44
|
+
- **Нет `__tests__`** — тесты через потребителей (CheckboxTreeExtended).
|
|
45
|
+
- **Нет stories** — внутренний компонент.
|
|
46
|
+
- **Node — class component**, root CollapsableTree — FC. `Node` использует
|
|
47
|
+
controlled/uncontrolled паттерн с `state.controlled` флагом, определяемым
|
|
48
|
+
один раз.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Варианты и props
|
|
53
|
+
|
|
54
|
+
### Root: `ICollapsableTreeProps extends ITreeViewProps`
|
|
55
|
+
|
|
56
|
+
Пустое расширение — все пропсы идут в `TreeView`. Смотри `TreeView` для
|
|
57
|
+
полного списка (`navigation`, `activeNodeId`, children).
|
|
58
|
+
|
|
59
|
+
### Compound: `CollapsableTree.Node` — `ICollapsableTreeNodeProps extends Omit<ITreeViewNodeProps, "children">, Pick<IAccordionBaseProps, "onToggle" | "toggle">`
|
|
60
|
+
|
|
61
|
+
| Prop | Тип | Обязателен | Описание |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `renderHeader` | `(props: ICollapsableTreeNodeHeaderProvideProps) => JSX.Element` | Да | Render-функция несворачиваемой части узла. |
|
|
64
|
+
| `renderBody` | `(props: ICollapsableTreeNodeBodyProvideProps) => ReactNode` | Да | Render-функция тела (дочерние узлы / контент). |
|
|
65
|
+
| `opened` | `boolean` | Нет | **Controlled-режим**: определяется в конструкторе по `!== undefined`. |
|
|
66
|
+
| `toggle` | `(opened: boolean) => void` | Нет | Controlled-хендлер. |
|
|
67
|
+
| `onToggle` | `(opened: boolean) => void` | Нет | Срабатывает после анимации (из AccordionBase). |
|
|
68
|
+
| `children` | `never` | — | Запрещён — узлы задаются через renderBody. |
|
|
69
|
+
| `...TreeViewNodeProps` | — | — | Наследует `id`, `prevNodeId`, `nextNodeId`, `activeNode` etc. |
|
|
70
|
+
|
|
71
|
+
### Provide-props для render-функций
|
|
72
|
+
|
|
73
|
+
**`ICollapsableTreeNodeBodyProvideProps`:**
|
|
74
|
+
```ts
|
|
75
|
+
{
|
|
76
|
+
activeNode: boolean; // активна клавиатурно
|
|
77
|
+
animating: boolean; // в процессе анимации
|
|
78
|
+
hasChildNodes: boolean; // есть ли дочерние узлы
|
|
79
|
+
opened: boolean; // раскрыт ли узел
|
|
80
|
+
toggle: (opened: boolean) => void;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**`ICollapsableTreeNodeHeaderProvideProps`:**
|
|
85
|
+
```ts
|
|
86
|
+
{
|
|
87
|
+
activeNode: boolean;
|
|
88
|
+
animating: boolean;
|
|
89
|
+
hasChildNodes: boolean;
|
|
90
|
+
isLastNode: boolean; // последний в дереве (для декораций)
|
|
91
|
+
opened: boolean;
|
|
92
|
+
toggle: (opened: boolean) => void;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Разница — `isLastNode` только в header (используется для разметки линий/
|
|
97
|
+
декораций дерева), `animating` присутствует в обоих.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Ключевые особенности реализации
|
|
102
|
+
|
|
103
|
+
### `controlled` определяется один раз в конструкторе
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
state = {
|
|
107
|
+
controlled: typeof this.props.opened !== "undefined",
|
|
108
|
+
};
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Фиксируется в initial state, не пересчитывается.** Переключить
|
|
112
|
+
controlled/uncontrolled на лету нельзя — как и в CardAction, это
|
|
113
|
+
архитектурное ограничение.
|
|
114
|
+
|
|
115
|
+
### `toggle` замыкание на treeViewNodeProvideProps
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
private toggle = ({ openedNode, setOpenedNode }) => (nextOpened: boolean) => {
|
|
119
|
+
const opened = controlled ? openedProps : openedNode;
|
|
120
|
+
if (opened !== nextOpened) {
|
|
121
|
+
controlled ? toggle?.(nextOpened) : setOpenedNode(nextOpened);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Возвращает функцию, которая знает, какая нода из TreeView.Node. Внутри
|
|
127
|
+
выбирает: controlled → вызывает внешний `toggle`; uncontrolled → вызывает
|
|
128
|
+
`setOpenedNode` (из TreeView).
|
|
129
|
+
|
|
130
|
+
**Защита от лишних toggle-вызовов:** `if (opened !== nextOpened)` — не
|
|
131
|
+
вызывает handler, если состояние не изменилось. Важно для AccordionBase,
|
|
132
|
+
который может вызывать toggle при клике на уже открытый заголовок.
|
|
133
|
+
|
|
134
|
+
### `renderBody` оборачивает в `TreeView.Group` только при hasChildNodes
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
if (treeViewNodeProvideProps.hasChildNodes) {
|
|
138
|
+
return <TreeView.Group>{renderBody({...})}</TreeView.Group>;
|
|
139
|
+
}
|
|
140
|
+
return renderBody({...});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`TreeView.Group` нужен для клавиатурной навигации (группировка нод
|
|
144
|
+
одного уровня). Листовые ноды — без Group, чтобы не создавать лишние
|
|
145
|
+
контейнеры.
|
|
146
|
+
|
|
147
|
+
### `visibility: hidden` в свёрнутом состоянии
|
|
148
|
+
|
|
149
|
+
```less
|
|
150
|
+
.collapsableTreeNodeContent {
|
|
151
|
+
&.collapsed {
|
|
152
|
+
visibility: hidden;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Не `display: none`, а `visibility: hidden`.** Причина в комментарии:
|
|
158
|
+
"чтобы по tab не было перехода на скрытые элементы". Но AccordionBase
|
|
159
|
+
даёт `height: 0`, а visibility хорошо сочетается с этим (hidden-элементы
|
|
160
|
+
вне tab-order).
|
|
161
|
+
|
|
162
|
+
**Важно:** одновременно работают `height: 0` (от ExpandAnimation в
|
|
163
|
+
AccordionBase) + `visibility: hidden` (от CollapsableTree). Если удалить
|
|
164
|
+
`visibility` — элементы внутри свёрнутого узла попадут в tab-order.
|
|
165
|
+
|
|
166
|
+
### `opened` взаимодействие между AccordionBase и TreeView
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const opened = controlled ? openedProps : treeViewNodeProps.openedNode;
|
|
170
|
+
// ...
|
|
171
|
+
<AccordionBase isOpen={opened} onToggle={onToggle} ... />
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
AccordionBase получает "решённый" opened, не оригинальный `openedProps`
|
|
175
|
+
(который может быть undefined в uncontrolled). Это гарантирует, что
|
|
176
|
+
AccordionBase всегда видит boolean.
|
|
177
|
+
|
|
178
|
+
### `ICollapsableTreeSFC` — кастомный тип
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
interface ICollapsableTreeSFC extends React.FC<ICollapsableTreeProps> {
|
|
182
|
+
Node: typeof CollapsableTreeNode;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Аналог compound-паттерна Badge/AlertProcess. Присваивание через
|
|
187
|
+
прямую mutation: `CollapsableTree.Node = CollapsableTreeNode`.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Инварианты
|
|
192
|
+
|
|
193
|
+
- **`controlled` определяется один раз** в state — не пересчитывать на
|
|
194
|
+
каждом рендере.
|
|
195
|
+
- **`if (opened !== nextOpened)` в toggle** — защита от no-op вызовов
|
|
196
|
+
AccordionBase. Не удалять.
|
|
197
|
+
- **`TreeView.Group` оборачивает body только при hasChildNodes** — не
|
|
198
|
+
оборачивать всегда (сломает leaf-ноды).
|
|
199
|
+
- **`visibility: hidden` для .collapsed** — не менять на `display: none`.
|
|
200
|
+
AccordionBase анимирует через height, display: none сломает анимацию.
|
|
201
|
+
- **`children: never` на Node** — не превращать в композитный.
|
|
202
|
+
renderHeader/renderBody — единственный способ.
|
|
203
|
+
- **Нет index.ts** — не добавлять для внешнего использования. Держать
|
|
204
|
+
как внутренний. Если нужен публичный API — делать отдельный компонент-
|
|
205
|
+
обёртку (как CheckboxTreeExtended).
|
|
206
|
+
- **Class component CollapsableTreeNode** — не переписывать на FC без
|
|
207
|
+
рефакторинга controlled/uncontrolled init-логики.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Accessibility
|
|
212
|
+
|
|
213
|
+
Вся a11y делегируется:
|
|
214
|
+
- **TreeView** — `role="tree"`, `role="treeitem"`, клавиатурная навигация
|
|
215
|
+
(Up/Down через prev/nextNodeId), `activeNode` → focus.
|
|
216
|
+
- **AccordionBase** — `aria-expanded` на заголовке, `aria-controls` ↔ body.
|
|
217
|
+
- **`visibility: hidden`** свёрнутых элементов — вне tab-order и screen
|
|
218
|
+
reader'ов.
|
|
219
|
+
|
|
220
|
+
CollapsableTree сам ARIA-атрибуты не добавляет.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Дизайн-токены
|
|
225
|
+
|
|
226
|
+
Нет. Весь визуал задаёт потребитель через renderHeader/renderBody (стилизует
|
|
227
|
+
свои обёртки). CollapsableTree добавляет только `visibility: hidden`.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Связанные компоненты
|
|
232
|
+
|
|
233
|
+
- `TreeView` (`src/components/TreeView`) — нижний уровень, клавиатурная
|
|
234
|
+
навигация и активная нода.
|
|
235
|
+
- `AccordionBase` (`src/components/AccordionBase/protected/AccordionBase`) —
|
|
236
|
+
анимация раскрытия (ExpandAnimation).
|
|
237
|
+
- `CheckboxTreeExtended` (`src/components/CheckboxTreeExtended`) —
|
|
238
|
+
основной потребитель.
|
|
239
|
+
- `Spoiler` (`src/components/Spoiler`) — альтернативный раскрывающийся
|
|
240
|
+
блок без дерева/навигации.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Stories
|
|
245
|
+
|
|
246
|
+
**Нет собственных stories.** Внутренний компонент — документируется
|
|
247
|
+
косвенно через `CheckboxTreeExtended`.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## История изменений
|
|
252
|
+
|
|
253
|
+
| Дата | Изменение |
|
|
254
|
+
|---|---|
|
|
255
|
+
| 2026-04-18 | Создан документ |
|