@sberbusiness/triplex-next-mcp-server 1.46.0-beta → 1.50.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 +7 -7
- package/bundle/components/Amount.md +2 -1
- package/bundle/components/AmountField.md +222 -323
- package/bundle/components/Avatar.md +138 -146
- package/bundle/components/Badge.md +2 -1
- package/bundle/components/BodyPage.md +2 -1
- package/bundle/components/Button.md +5 -1
- package/bundle/components/ButtonDropdownExtended.md +3 -1
- package/bundle/components/ButtonIcon.md +3 -1
- package/bundle/components/Calendar.md +3 -1
- package/bundle/components/CardAction.md +1 -0
- package/bundle/components/CardStatic.md +402 -0
- package/bundle/components/CheckboxTree.md +157 -215
- package/bundle/components/CheckboxTreeExtended.md +7 -7
- package/bundle/components/CheckboxXGroup.md +2 -1
- package/bundle/components/Chip.md +2 -1
- package/bundle/components/ChipGroup.md +1 -1
- package/bundle/components/ChipMonthYearPicker.md +6 -5
- package/bundle/components/ChipMultiselect.md +4 -1
- package/bundle/components/ChipOptions.md +2 -1
- package/bundle/components/ChipSort.md +4 -1
- package/bundle/components/ChipSuggest.md +7 -6
- package/bundle/components/CollapsibleTree.md +10 -5
- package/bundle/components/CollapsibleTreeExtended.md +8 -6
- package/bundle/components/ComposedKeyDownListener.md +4 -3
- package/bundle/components/Confirm.md +346 -281
- package/bundle/components/DateField.md +7 -1
- package/bundle/components/DateRange.md +351 -210
- package/bundle/components/Divider.md +85 -138
- package/bundle/components/DocumentNumberEdit.md +173 -214
- package/bundle/components/Dropdown.md +11 -1
- package/bundle/components/Ellipsis.md +131 -147
- package/bundle/components/FooterPage.md +4 -1
- package/bundle/components/FormField.md +13 -5
- package/bundle/components/FormGroup.md +3 -2
- package/bundle/components/Gap.md +1 -1
- package/bundle/components/Header.md +1 -0
- package/bundle/components/HeaderPage.md +3 -1
- package/bundle/components/HelpBox.md +2 -1
- package/bundle/components/IconWrapper.md +10 -6
- package/bundle/components/ImageGallery.md +2 -1
- package/bundle/components/ImageGalleryExtended.md +2 -1
- package/bundle/components/IslandAccordion.md +6 -1
- package/bundle/components/KeyDownListener.md +3 -2
- package/bundle/components/LightBox.md +15 -1
- package/bundle/components/List.md +2 -1
- package/bundle/components/ListActionItem.md +2 -1
- package/bundle/components/ListItem.md +3 -1
- package/bundle/components/ListItemControlsButton.md +2 -1
- package/bundle/components/ListItemSelectable.md +2 -1
- package/bundle/components/ListMaster.md +2 -2
- package/bundle/components/ListMasterFooter.md +2 -1
- package/bundle/components/ListMasterHeader.md +2 -1
- package/bundle/components/ListSortable.md +2 -1
- package/bundle/components/ListSortableItem.md +2 -1
- package/bundle/components/ListTableItem.md +10 -7
- package/bundle/components/LoaderMiddle.md +5 -1
- package/bundle/components/LoaderScreen.md +7 -1
- package/bundle/components/LoaderSmall.md +10 -4
- package/bundle/components/MaskedField.md +3 -1
- package/bundle/components/MediaWidth.md +2 -1
- package/bundle/components/MobileView.md +2 -1
- package/bundle/components/ModalWindow.md +4 -1
- package/bundle/components/MonthYearField.md +19 -5
- package/bundle/components/Notification.md +1 -0
- package/bundle/components/Overlay.md +7 -2
- package/bundle/components/Pagination.md +1 -7
- package/bundle/components/Radio.md +238 -115
- package/bundle/components/RadioXGroup.md +259 -0
- package/bundle/components/RadioYGroup.md +266 -0
- package/bundle/components/SegmentedControl.md +505 -158
- package/bundle/components/SelectExtendedField.md +2 -1
- package/bundle/components/SelectField.md +4 -1
- package/bundle/components/Skeleton.md +140 -69
- package/bundle/components/Slider.md +389 -97
- package/bundle/components/SliderRange.md +486 -105
- package/bundle/components/Spoiler.md +245 -63
- package/bundle/components/StatusTracker.md +386 -94
- package/bundle/components/Step.md +257 -68
- package/bundle/components/Stepper.md +355 -102
- package/bundle/components/StepperExtended.md +633 -0
- package/bundle/components/SuggestField.md +1061 -96
- package/bundle/components/SwipeableArea.md +7 -7
- package/bundle/components/Tabs.md +266 -92
- package/bundle/components/TabsExtended.md +18 -18
- package/bundle/components/TabsLine.md +302 -127
- package/bundle/components/TagColor.md +187 -66
- package/bundle/components/TagGroup.md +184 -48
- package/bundle/components/TextField.md +8 -4
- package/bundle/components/TextareaField.md +279 -70
- package/bundle/components/ThemeProvider.md +2 -1
- package/bundle/components/Tooltip.md +6 -3
- package/bundle/components/TopOverlay.md +17 -1
- package/bundle/components/TreeView.md +16 -7
- package/bundle/components/TriggerClickOnKeyDownEvent.md +277 -0
- package/bundle/components/UploadZone.md +318 -0
- package/bundle/guides/codestyle.md +16 -1
- package/bundle/guides/commits.md +47 -1
- package/bundle/guides/context.md +4 -1
- package/bundle/guides/tests.md +23 -2
- package/bundle/manifest.json +78 -29
- package/bundle/release-notes/1.47.0.mdx +115 -0
- package/bundle/release-notes/1.48.0.mdx +68 -0
- package/bundle/release-notes/1.49.0.mdx +85 -0
- package/bundle/release-notes/1.50.0.mdx +35 -0
- package/bundle/release-notes/1.51.0.mdx +7 -0
- package/bundle/tokens.json +163 -13
- package/dist/index.js +220 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Ellipsis
|
|
3
|
-
category:
|
|
4
|
-
|
|
5
|
-
figma-file: ""
|
|
6
|
-
related: [Typography, Tooltip, Spoiler]
|
|
3
|
+
category: Ellipsis
|
|
4
|
+
related: []
|
|
7
5
|
tokens: []
|
|
8
6
|
stories: stories/Ellipsis/Ellipsis.stories.tsx
|
|
9
7
|
version: "1.0"
|
|
@@ -13,191 +11,153 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
Контейнер, который обрезает вложенный текст многоточием после заданного числа
|
|
15
|
+
строк. Вся работа делается CSS-свойством `line-clamp` — компонент не измеряет
|
|
16
|
+
текст, не режет строки в JS и не добавляет собственного оформления: рендерит
|
|
17
|
+
один `<div>`, в котором включён многострочный клэмп.
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
оставляло пустую строку).
|
|
19
|
+
Используй когда: длина текста не контролируется (название документа, комментарий,
|
|
20
|
+
описание из бэкенда), а место под него в макете фиксировано — одна, две, три
|
|
21
|
+
строки.
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
помещаться в фиксированное количество строк.
|
|
27
|
-
Не используй когда: нужна интерактивность (развернуть/свернуть) — бери
|
|
28
|
-
`Spoiler`; нужен tooltip с полным текстом — оборачивай в `Tooltip`.
|
|
23
|
+
Не используй когда:
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Особенности:
|
|
43
|
-
- **`forwardRef`** есть (в отличие от Col/Divider).
|
|
44
|
-
- **`data-tx`** есть.
|
|
45
|
-
- **Единственный проп помимо HTML attributes** — `maxLines`.
|
|
46
|
-
- **Тесты** покрывают базовое поведение.
|
|
25
|
+
- блоку нужны собственные паддинги: обрезка построена на `display: -webkit-box`,
|
|
26
|
+
вертикальные отступы попадают внутрь обрезаемой области и «съедают» строку.
|
|
27
|
+
Отступы задаёт обёртка вокруг `Ellipsis`, а не он сам;
|
|
28
|
+
- нужен раскрывающийся текст («показать полностью»): `Ellipsis` не имеет
|
|
29
|
+
состояния и кнопки — это `Spoiler` или своя связка с `ExpandAnimation`;
|
|
30
|
+
- нужна обрезка ровно по ширине одной строки без многострочной логики: обычного
|
|
31
|
+
`text-overflow: ellipsis` на своём элементе достаточно, отдельный компонент
|
|
32
|
+
здесь избыточен;
|
|
33
|
+
- полный текст обязан оставаться видимым — обрезка визуальная и необратимая,
|
|
34
|
+
пользователь не может её раскрыть.
|
|
47
35
|
|
|
48
36
|
---
|
|
49
37
|
|
|
50
38
|
## Варианты и props
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
| Prop | Тип | Обязателен | Описание |
|
|
55
|
-
|---|---|---|---|
|
|
56
|
-
| `maxLines` | `number` | Да | Максимум строк. После `maxLines`-й строки — многоточие. |
|
|
57
|
-
| `children` | `ReactNode` | — | Текст или inline-элементы. |
|
|
58
|
-
| `className` | `string` | — | Через `clsx`. |
|
|
59
|
-
| `...HTMLDivAttributes` | — | — | Стандартные. |
|
|
60
|
-
|
|
61
|
-
**Нет дефолтного `maxLines`** — обязательный проп. Если передать 0
|
|
62
|
-
или отрицательное — получишь пустой контейнер (браузер сочтёт 0-строк).
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Ключевые особенности реализации
|
|
67
|
-
|
|
68
|
-
### `--ellipsis-line-clamp` CSS-переменная
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
style={{ "--ellipsis-line-clamp": maxLines } as React.CSSProperties}
|
|
72
|
-
```
|
|
40
|
+
`IEllipsisProps` расширяет `React.HTMLAttributes<HTMLDivElement>` — `...rest`,
|
|
41
|
+
`className` и `style` уходят на корневой `<div>`.
|
|
73
42
|
|
|
74
|
-
|
|
75
|
-
.ellipsisLineClamp {
|
|
76
|
-
--ellipsis-line-clamp: 1;
|
|
77
|
-
-webkit-line-clamp: var(--ellipsis-line-clamp);
|
|
78
|
-
line-clamp: var(--ellipsis-line-clamp);
|
|
79
|
-
}
|
|
80
|
-
```
|
|
43
|
+
### Обязательные props
|
|
81
44
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
побеждает media-query; переменная может быть перезаписана по
|
|
86
|
-
breakpoint'у.
|
|
45
|
+
| Prop | Тип | Описание |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `maxLines` | `number` | Количество строк, после которых текст сворачивается в многоточие. Осмысленны только целые значения ≥ 1: компонент значение не валидирует и передаёт его в CSS как есть |
|
|
87
48
|
|
|
88
|
-
|
|
89
|
-
допускает custom properties без кастинга. Стандартный приём.
|
|
49
|
+
### Опциональные props
|
|
90
50
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
51
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| `children` | `React.ReactNode` | — | Обрезаемое содержимое. Рассчитано на текст; блочная разметка внутри `-webkit-box` ведёт себя непредсказуемо |
|
|
54
|
+
| `className` | `string` | — | Мерджится с собственными классами корневого `<div>` через `clsx` |
|
|
55
|
+
| `style` | `React.CSSProperties` | — | Мерджится с runtime-переменной клэмпа: собственные стили потребителя применяются, переменную они не затирают |
|
|
95
56
|
|
|
96
|
-
|
|
97
|
-
display: -webkit-box;
|
|
98
|
-
-webkit-line-clamp: var(--ellipsis-line-clamp);
|
|
99
|
-
-webkit-box-orient: vertical;
|
|
100
|
-
overflow: hidden;
|
|
101
|
-
```
|
|
57
|
+
### Что делает `maxLines` кроме числа строк
|
|
102
58
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
Без `overflow: hidden` — многоточия не будет.
|
|
59
|
+
Значение уходит в runtime CSS-переменную (см. «Дизайн-токены») и дополнительно
|
|
60
|
+
переключает режим переноса:
|
|
106
61
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
62
|
+
| `maxLines` | Класс | `word-break` | Зачем |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| `1` | `ellipsisLineClamp` + `oneLine` | `break-all` | Единственное длинное слово без пробелов должно обрезаться посередине, а не уезжать за границы |
|
|
65
|
+
| `> 1` | `ellipsisLineClamp` | `break-word` | Обычный перенос по словам, слово рвётся только если целиком не влезает в строку |
|
|
110
66
|
|
|
111
|
-
|
|
67
|
+
---
|
|
112
68
|
|
|
113
|
-
|
|
114
|
-
white-space: normal;
|
|
115
|
-
```
|
|
69
|
+
## Дизайн-токены
|
|
116
70
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
не сработает — текст просто обрежется справа.
|
|
71
|
+
Собственных дизайн-токенов у компонента нет: `Ellipsis.module.less` задаёт только
|
|
72
|
+
раскладку и правила переноса, цвет и типографика наследуются от родителя.
|
|
120
73
|
|
|
121
|
-
|
|
74
|
+
Единственная CSS-переменная — runtime-переменная числа строк, которую компонент
|
|
75
|
+
выставляет сам через `style`:
|
|
122
76
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
&.oneLine {
|
|
126
|
-
word-break: break-all; // разрывает посреди слова
|
|
127
|
-
}
|
|
77
|
+
```text
|
|
78
|
+
--triplex-next-runtime-Ellipsis-Root_LineClamp
|
|
128
79
|
```
|
|
129
80
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Для `maxLines > 1` — `break-word` — красивее (слова не разрываются).
|
|
137
|
-
|
|
138
|
-
### Компонент — `<div>`, не `<p>`
|
|
139
|
-
|
|
140
|
-
Не рендерит semantic `<p>` или `<span>`. Потребитель может обернуть
|
|
141
|
-
любой текст. Если нужна семантика — использовать `as` через прокидывание
|
|
142
|
-
(не реализовано) или выбрать `Typography.Text` + обернуть в Ellipsis.
|
|
81
|
+
Это не дизайн-токен: она не входит в `src/components/DesignTokens`, не
|
|
82
|
+
переопределяется через `ThemeProvider` и существует только потому, что
|
|
83
|
+
`line-clamp` нельзя выразить фиксированным набором классов для произвольного
|
|
84
|
+
числа строк. В стилях у неё есть fallback `1` — на случай, если разметка
|
|
85
|
+
отрендерена без inline-стиля.
|
|
143
86
|
|
|
144
87
|
---
|
|
145
88
|
|
|
146
89
|
## Инварианты
|
|
147
90
|
|
|
148
|
-
- **`
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
- **`
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
-
|
|
91
|
+
- **`forwardRef` на компоненте — не убирать.** Ref идёт на корневой `<div>` —
|
|
92
|
+
тот же элемент, что получает `className`, `style` и `...rest`.
|
|
93
|
+
- **Корневой DOM — один `<div>`** с `data-tx` (версия пакета). Тег не
|
|
94
|
+
настраивается, дополнительных обёрток внутри нет.
|
|
95
|
+
- **Публичные экспорты barrel** (`src/components/Ellipsis/index.ts`): `Ellipsis`,
|
|
96
|
+
`IEllipsisProps`. Переименование — breaking change.
|
|
97
|
+
- **`displayName = "Ellipsis"`.**
|
|
98
|
+
- **`maxLines` обязателен и остаётся `number`.** Значение по умолчанию не
|
|
99
|
+
вводится намеренно: тихая обрезка на «каком-то» числе строк хуже, чем явное
|
|
100
|
+
требование его указать.
|
|
101
|
+
- **Связка CSS-свойств `display: -webkit-box` + `-webkit-box-orient: vertical` +
|
|
102
|
+
`overflow: hidden` — неразрывная.** Клэмп работает только когда выставлены все
|
|
103
|
+
три. Переопределение `display` снаружи (через `className` или `style`) отключает
|
|
104
|
+
обрезку целиком.
|
|
105
|
+
- **`padding: 0` в корневом классе — часть контракта**, а не косметика:
|
|
106
|
+
вертикальные паддинги искажают количество видимых строк. Отступы задаёт
|
|
107
|
+
обёртка.
|
|
108
|
+
- **Runtime-переменная `--triplex-next-runtime-Ellipsis-Root_LineClamp`**
|
|
109
|
+
объявляется в `Ellipsis.tsx` и читается в `Ellipsis.module.less`. Имя следует
|
|
110
|
+
паттерну `docs/ai/codestyle.md`. Публичным API она не является и через
|
|
111
|
+
`ThemeProvider` не переопределяется, но видна в inline-стиле корневого
|
|
112
|
+
элемента, поэтому её имя меняется в обоих файлах разом.
|
|
113
|
+
- **Потребительский `style` мерджится, а не заменяется.** Порядок
|
|
114
|
+
`{...style, "--...": maxLines}` гарантирует, что `maxLines` не теряется при
|
|
115
|
+
передаче своих стилей.
|
|
116
|
+
- **CSS-классы `ellipsisLineClamp` и `oneLine`** проверяются unit-тестами —
|
|
117
|
+
переименование требует синхронного обновления тестов.
|
|
159
118
|
|
|
160
119
|
---
|
|
161
120
|
|
|
162
121
|
## Accessibility
|
|
163
122
|
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
## Дизайн-токены
|
|
176
|
-
|
|
177
|
-
**Нет собственных.** Чисто CSS-техника обрезания.
|
|
123
|
+
- Компонент презентационный: своей роли, ARIA-атрибутов, фокуса и клавиатурных
|
|
124
|
+
обработчиков у него нет. Корневой `<div>` не участвует в порядке обхода по
|
|
125
|
+
`Tab`.
|
|
126
|
+
- **Обрезка чисто визуальная.** Текст целиком остаётся в DOM и в дереве
|
|
127
|
+
доступности, поэтому скринридер прочитает его полностью, а поиск по странице
|
|
128
|
+
найдёт скрытую часть. Для пользователя со зрением текст при этом потерян.
|
|
129
|
+
- Если полный текст важен, потребитель отвечает за его доступность сам:
|
|
130
|
+
`Tooltip` рядом, `title` на элементе через `...rest` или ссылка на полную
|
|
131
|
+
версию. Компонент ничего такого не добавляет — библиотека мультиязычная и
|
|
132
|
+
текстов не хардкодит.
|
|
133
|
+
- `aria-*` и `title` пробрасываются на корневой `<div>` через `...rest`.
|
|
178
134
|
|
|
179
135
|
---
|
|
180
136
|
|
|
181
137
|
## Связанные компоненты
|
|
182
138
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
139
|
+
Собственных связей-контрактов у компонента нет: он ничего не рендерит внутри
|
|
140
|
+
себя, ни от кого не наследует props и не входит ни в какое семейство — поэтому
|
|
141
|
+
`related` пуст. Полезные соседи при вёрстке:
|
|
142
|
+
|
|
143
|
+
- `Tooltip` — типичная пара: обрезанный текст плюс подсказка с полным значением
|
|
144
|
+
по наведению. Связи в коде нет, связку собирает потребитель.
|
|
145
|
+
- `Spoiler` — если текст нужно не обрезать, а сворачивать с возможностью
|
|
146
|
+
раскрыть.
|
|
147
|
+
- `Text`, `Body` — типографика обрезаемого текста: `Ellipsis` цвет и размер
|
|
148
|
+
шрифта не задаёт, они наследуются от родителя.
|
|
187
149
|
|
|
188
150
|
---
|
|
189
151
|
|
|
190
152
|
## Stories
|
|
191
153
|
|
|
192
|
-
`stories/Ellipsis/Ellipsis.stories.tsx`
|
|
193
|
-
|
|
154
|
+
Основные истории: `stories/Ellipsis/Ellipsis.stories.tsx`
|
|
155
|
+
Файлы примеров: `stories/Ellipsis/examples/`
|
|
194
156
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
- `WithTooltip` — комбинация с Tooltip для показа полного текста
|
|
200
|
-
- `Playground` — интерактив
|
|
157
|
+
| Story | Example file | Что демонстрирует |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль `maxLines` на длинном тексте |
|
|
160
|
+
| `Default` | `DefaultExample.tsx` | Обрезка длинного абзаца до двух строк |
|
|
201
161
|
|
|
202
162
|
---
|
|
203
163
|
|
|
@@ -205,4 +165,28 @@ word-break: break-word; // default — разрывает только по с
|
|
|
205
165
|
|
|
206
166
|
| Дата | Изменение |
|
|
207
167
|
|---|---|
|
|
208
|
-
| 2026-
|
|
168
|
+
| 2026-09-30 | Создан документ (TRI-36). Зафиксированы: обязательность `maxLines` без дефолта, связка `display: -webkit-box` + `-webkit-box-orient` + `overflow: hidden`, запрет паддингов, переключение `word-break` на `maxLines === 1`, мердж потребительского `style` с runtime-переменной `--triplex-next-runtime-Ellipsis-Root_LineClamp` и визуальный (не семантический) характер обрезки |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Примеры использования
|
|
173
|
+
|
|
174
|
+
### Default
|
|
175
|
+
|
|
176
|
+
`stories/Ellipsis/examples/DefaultExample.tsx`
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import React from "react";
|
|
180
|
+
import { Ellipsis } from "@sberbusiness/triplex-next";
|
|
181
|
+
|
|
182
|
+
export const DefaultExample = () => (
|
|
183
|
+
<Ellipsis maxLines={2}>
|
|
184
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
|
|
185
|
+
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
|
186
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
|
187
|
+
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
|
|
188
|
+
laborum.
|
|
189
|
+
</Ellipsis>
|
|
190
|
+
);
|
|
191
|
+
```
|
|
192
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: FooterPage
|
|
3
3
|
category: Page
|
|
4
|
-
related: [Page, HeaderPage, BodyPage, Footer, Island
|
|
4
|
+
related: [Page, HeaderPage, BodyPage, Footer, Island]
|
|
5
5
|
tokens:
|
|
6
6
|
- FooterPage.StickyShadow
|
|
7
7
|
stories: stories/Page/FooterPage/FooterPage.stories.tsx
|
|
@@ -115,8 +115,11 @@ version: "1.0"
|
|
|
115
115
|
|
|
116
116
|
| Дата | Изменение |
|
|
117
117
|
|---|---|
|
|
118
|
+
| 2026-09-28 | Токен `FooterPage.StickyShadow` ссылается на `Shadow.05` (светлая) и `DarkShadow.05` (тёмная) вместо литералов: `0 -2px 9px` с прозрачностью 0.15 (светлая) и 0.5 (тёмная). |
|
|
119
|
+
| 2026-09-16 | Добавлен отступ `padding-bottom: 8px` для футера с `type={EFooterPageType.SECOND}`. |
|
|
118
120
|
| 2026-08-06 | Sticky-позиционирование доступно вне `LightBox` при ширине viewport от 992px и отключено при высоте viewport не больше 800px. |
|
|
119
121
|
| 2026-06-19 | Создан документ. AI-рефакторинг (clsx order, JSDoc на props, displayName), unit-тесты, миграция stories на modern pattern. |
|
|
122
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны несимметричные имена (`LightBox`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
120
123
|
|
|
121
124
|
---
|
|
122
125
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: FormField
|
|
3
3
|
category: FormField
|
|
4
|
-
related: [
|
|
4
|
+
related: [FormGroup, TextField, TextareaField, MaskedField, SelectField, SuggestField, DateField]
|
|
5
5
|
tokens:
|
|
6
6
|
- FormField.Background_Default
|
|
7
7
|
- FormField.Background_Hover
|
|
@@ -62,7 +62,7 @@ version: "1.0"
|
|
|
62
62
|
- Горизонтальные внутренние отступы корневого `div` задаются инлайн-стилем из ширин префикса и постфикса (`paddingLeft: prefixWidth`, `paddingRight: postfixWidth`). Значение по умолчанию — `TARGET_PADDING_X_DEFAULT` (12px); `FormFieldPrefix` / `FormFieldPostfix` измеряют себя через `ResizeObserver` и обновляют его. Пользовательский `style` мерджится последним и может переопределить отступы.
|
|
63
63
|
- Класс `filled` выставляется, когда вложенный элемент ввода сообщил о наличии значения. Для `FormFieldInput` / `FormFieldTextarea` это включает браузерное автозаполнение (ловится через CSS-анимационные хуки `autofill-applied-hook` / `autofill-cancelled-hook`), для `FormFieldTarget` — наличие `children`.
|
|
64
64
|
- Кнопка `FormFieldClear` показывается стилями только при `filled` и hover/активном состоянии непустого и не заблокированного поля, а также при собственном фокусе (`:focus`) — чтобы кнопка оставалась видимой при клавиатурной навигации.
|
|
65
|
-
- Идентификаторы генерируются субкомпонентами (`uniqueId` из `lodash-es`, не `React.useId` — код должен оставаться совместимым с React 17) и попадают в контекст как `targetId` / `labelId`; на них опирается связка `
|
|
65
|
+
- Идентификаторы генерируются субкомпонентами (`uniqueId` из `lodash-es`, не `React.useId` — код должен оставаться совместимым с React 17) и попадают в контекст как `targetId` / `labelId`; на них опирается связка лейбла и поля. `targetId` публикуют только labelable-элементы (`FormFieldInput`, `FormFieldTextarea`, а также `FormFieldMaskedInput` — он рендерит `FormFieldInput` внутри себя через `render`); `FormFieldTarget` его не публикует — см. Accessibility.
|
|
66
66
|
- Вне `FormField` субкомпоненты используют `initialFormFieldContext`, где `filled: true` — это осознанный временный фикс для `DropdownMobileHeader`, а сеттеры являются no-op.
|
|
67
67
|
|
|
68
68
|
---
|
|
@@ -104,9 +104,10 @@ FormField.Target_PlaceholderColor_Default
|
|
|
104
104
|
- Barrel `src/components/FormField/index.ts` реэкспортирует `enums`, `types`, `components` и сам `FormField` — состав экспортов не сокращать. Маппинг статуса на класс (`STATUS_TO_CLASS_NAME_MAP`) — внутренняя константа модуля и в barrel не входит.
|
|
105
105
|
- `FormFieldContext` и `FormFieldDescriptionContext` в barrel не входят: это внутренний механизм семейства, но на нём завязаны все субкомпоненты — менять форму значения контекста без правки субкомпонентов нельзя.
|
|
106
106
|
- Классы `formField`, `filled`, `active`, `error`, `warning`, `disabled`, а также `sm` / `md` / `lg` проверяются unit-тестами и используются в вложенных селекторах стилей семейства.
|
|
107
|
+
- `disabled` исключён из props элементов ввода (`IFormFieldInputProps`, `IFormFieldTextareaProps`, `IFormFieldMaskedInputProps` — через `Omit`): блокировка задаётся только `status={EFormFieldStatus.DISABLED}`, иначе переданное значение молча перетиралось бы внутренним.
|
|
107
108
|
- Генерация id — через `uniqueId` (`lodash-es`), без `React.useId`: ветка `release-0` собирается на React 17.
|
|
108
109
|
- `FormFieldDescription` и `FormFieldCounter` объявлены как `React.FC` без `forwardRef` — осознанное историческое отличие от остальных субкомпонентов. Добавление ref расширяет публичный API; решение владельца — оставить как есть.
|
|
109
|
-
- Внутренние утилиты семейства (`components/utils.ts` — `isFilled
|
|
110
|
+
- Внутренние утилиты семейства (`components/utils.ts` — `isFilled`; `components/useFormFieldAffixWidth.ts`) намеренно не попадают в barrel `components/index.ts`. Общий `setForwardedRef` вынесен в `src/helpers/setForwardedRef.ts` и импортируется относительным путём.
|
|
110
111
|
- Компонент не рендерит собственных подписей и текстов — библиотека мультиязычная.
|
|
111
112
|
|
|
112
113
|
---
|
|
@@ -114,9 +115,11 @@ FormField.Target_PlaceholderColor_Default
|
|
|
114
115
|
## Accessibility
|
|
115
116
|
|
|
116
117
|
- Корневой элемент — обычный `div` без роли: семантику даёт вложенный нативный `input` / `textarea`.
|
|
117
|
-
- Связка лейбла и поля: `FormFieldLabel`
|
|
118
|
+
- Связка лейбла и поля: когда в поле есть labelable-элемент, `FormFieldLabel` рендерит `<label htmlFor={targetId}>`, а элемент ввода — сгенерированный `id`. Поэтому `screen.getByLabelText(...)` находит поле.
|
|
118
119
|
- `FormFieldTarget` (нередактируемое значение, например для select-подобных полей) получает `tabIndex={0}`, `aria-labelledby={labelId}` и `aria-disabled`; при `status = DISABLED` — `tabIndex={-1}`.
|
|
119
|
-
-
|
|
120
|
+
- `FormFieldTarget` намеренно **не** публикует свой `id` как `targetId`: это `<div>`, а не labelable-элемент, и `label[htmlFor]` на него ссылаться не может. В таких полях `FormFieldLabel` рендерит `<span>`, а не `<label>` — несвязанный `<label>` браузер тоже считает ошибкой разметки. Имя полю даёт `aria-labelledby` на `FormFieldTarget`, поэтому `screen.getByLabelText(...)` продолжает находить поле.
|
|
121
|
+
- Следствие выбора тега по контексту: `targetId` публикуется в `useLayoutEffect`, поэтому в полях с labelable-элементом лейбл на первом рендере — `<span>`, а после layout-эффекта DOM-узел заменяется на `<label>`. Замена происходит до отрисовки и визуально незаметна, но ref на `FormFieldLabel` вызывается для обоих узлов.
|
|
122
|
+
- При `status = DISABLED` вложенные `input` / `textarea` получают нативный `disabled`, то есть выпадают из таб-порядка. Передать `disabled` мимо статуса нельзя — атрибут исключён из props элементов ввода.
|
|
120
123
|
- Плейсхолдер маски в `FormFieldMaskedInput` рендерится с `aria-hidden="true"` — скринридер читает только реальное значение input.
|
|
121
124
|
- Текст описания (`FormFieldDescription`) визуально связан с полем, но не связывается автоматически через `aria-describedby` — при необходимости потребитель передаёт `aria-describedby` элементу ввода сам.
|
|
122
125
|
|
|
@@ -168,6 +171,11 @@ FormField.Target_PlaceholderColor_Default
|
|
|
168
171
|
| 2026-08-03 | Ломающее изменение: `statusToClassNameMap` убран из публичного barrel и переименован во внутреннюю константу `STATUS_TO_CLASS_NAME_MAP`. Зафиксировано в release notes 1.41.0. |
|
|
169
172
|
| 2026-09-04 | Исправлено: у `FormFieldTextarea` фиксированная `height` для размеров `sm` / `md` / `lg` заменена на `min-height`. |
|
|
170
173
|
| 2026-09-09 | Исправлено: значение с кодом страны раскладывалось по маске телефона со сдвигом и теряло последнюю цифру. Нормализация номера вынесена в `normalizePhoneText` и применяется и к внешнему `value`, и к слою с маской |
|
|
174
|
+
| 2026-09-16 | Исправлено: `FormFieldTarget` больше не публикует свой `id` как `targetId`, а `FormFieldLabel` рендерит `<span>` вместо `<label>`, когда в поле нет labelable-элемента. Ref `FormFieldLabel` типизирован как `HTMLElement`, props — как `React.HTMLAttributes<HTMLElement>`. Доступное имя по-прежнему даёт `aria-labelledby`. |
|
|
175
|
+
| 2026-09-16 | Исправлено: `FormFieldInput` и `FormFieldTextarea` очищают `targetId` при размонтировании — иначе после замены элемента ввода на `FormFieldTarget` лейбл сохранял `htmlFor` с `id` удалённого элемента. |
|
|
176
|
+
| 2026-09-17 | Ломающее изменение: `disabled` убран из `IFormFieldTextareaProps` через `Omit` — так же, как он уже был убран у `FormFieldInput` и `FormFieldMaskedInput`. Поведение не менялось (статус перетирал переданное значение и раньше), но передача `disabled` в props теперь ошибка компиляции. Правка по ревью PR #629, зафиксирована в release notes 1.47.0 |
|
|
177
|
+
| 2026-09-23 | Исправлено: при смене `status` на `EFormFieldStatus.DISABLED`, пока вложенный элемент ввода в фокусе, `FormField` теперь явно сбрасывает состояние `focused` в `useLayoutEffect`. |
|
|
178
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны имена без строки в `docs/ai/ROADMAP.md` (`FormFieldLabel`, `FormFieldInput`, `FormFieldTextarea`, `FormFieldTarget`, `FormFieldMaskedInput`, `FormFieldPrefix`, `FormFieldPostfix`, `FormFieldClear`, `FormFieldDescription`, `FormFieldCounter`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
171
179
|
|
|
172
180
|
---
|
|
173
181
|
|
|
@@ -76,8 +76,9 @@ version: "1.0"
|
|
|
76
76
|
Семантику задаёт потребитель через проброшенные атрибуты — например `role="group"` вместе с
|
|
77
77
|
`aria-labelledby`, если группа должна объявляться скринридером как единое целое.
|
|
78
78
|
|
|
79
|
-
Лейбл связывается с полем внутри `FormField`:
|
|
80
|
-
в `FormFieldContext
|
|
79
|
+
Лейбл связывается с полем внутри `FormField`: в полях с элементом ввода `FormFieldLabel` берёт
|
|
80
|
+
`htmlFor` из `targetId` в `FormFieldContext`, в select-подобных — связь даёт `aria-labelledby`
|
|
81
|
+
на `FormFieldTarget` (см. `FormField-ai.md`). Описание автоматически не связывается — `aria-describedby` на элементе
|
|
81
82
|
ввода (как и `aria-invalid` для ошибки) задаёт потребитель, см. `FormField-ai.md`. `FormGroup`
|
|
82
83
|
не участвует ни в том, ни в другом.
|
|
83
84
|
|
package/bundle/components/Gap.md
CHANGED
|
@@ -194,6 +194,7 @@ Playground не создаётся — у компонента нет настр
|
|
|
194
194
|
|
|
195
195
|
| Дата | Изменение |
|
|
196
196
|
|---|---|
|
|
197
|
+
| 2026-10-01 | `Header.Title.Controls` в адаптиве (`max-width: @screen-sm-max`): вместо отрицательного `margin-left` контейнера и `margin-left/top: 16px` у кнопок используется `display: flex; flex-wrap: wrap; gap: 16px 12px` и `margin-top: 16px` у контейнера. Прямым потомкам `button` и `[class*="buttonDropdown"]` собственные `margin` сбрасываются через `!important` (иначе их перебивают правила отступа между соседними кнопками, специфичность 0,3,0), поэтому пользовательские `margin` на них в адаптиве не действуют. Остальные прямые потомки участвуют во flex-раскладке (`align-items: center`). Десктопные стили не менялись. |
|
|
197
198
|
| 2026-08-28 | Создан документ. AI-рефакторинг (JSDoc на `children` и `withoutPaddings`, выровнен порядок аргументов `clsx`, удалён мёртвый CSS-селектор `.headerLink` и пустое правило `.headerTitleContent`), unit-тесты на все одиннадцать компонентов, stories по modern pattern. |
|
|
198
199
|
|
|
199
200
|
---
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: HeaderPage
|
|
3
3
|
category: Page
|
|
4
|
-
related: [Page, BodyPage, FooterPage, Header, Island
|
|
4
|
+
related: [Page, BodyPage, FooterPage, Header, Island]
|
|
5
5
|
tokens:
|
|
6
6
|
- HeaderPage.StickyShadow
|
|
7
7
|
stories: stories/Page/HeaderPage/HeaderPage.stories.tsx
|
|
@@ -118,8 +118,10 @@ version: "1.0"
|
|
|
118
118
|
|
|
119
119
|
| Дата | Изменение |
|
|
120
120
|
|---|---|
|
|
121
|
+
| 2026-09-28 | Токен `HeaderPage.StickyShadow` ссылается на `Shadow.04` (светлая) и `DarkShadow.04` (тёмная) вместо литералов: `0 2px 9px` с прозрачностью 0.15 (светлая) и 0.5 (тёмная). |
|
|
121
122
|
| 2026-08-06 | Sticky-позиционирование доступно вне `LightBox` при ширине viewport от 992px и отключено при высоте viewport не больше 800px. |
|
|
122
123
|
| 2026-06-23 | Создан документ. AI-рефакторинг (clsx order, JSDoc на props, displayName), unit-тесты, миграция stories на modern pattern. |
|
|
124
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны несимметричные имена (`LightBox`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
123
125
|
|
|
124
126
|
---
|
|
125
127
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: HelpBox
|
|
3
3
|
category: HelpBox
|
|
4
|
-
related: [Tooltip, ButtonIcon, MobileView
|
|
4
|
+
related: [Tooltip, ButtonIcon, MobileView]
|
|
5
5
|
tokens: []
|
|
6
6
|
stories: stories/HelpBox/HelpBox.stories.tsx
|
|
7
7
|
version: "1.0"
|
|
@@ -119,6 +119,7 @@ version: "1.0"
|
|
|
119
119
|
| 2026-07-08 | Актуализирована колонка `Example file`: имена файлов примеров приведены к фактическим (без постфикса `Example`). |
|
|
120
120
|
| 2026-09-08 | AI-рефакторинг: `useId` заменён на `uniqueId` (совместимость с React 17), callback-`ref` стабилизирован через `useCallback`, убраны `!` и `as`-каст в работе с `ref`, `TooltipMobileHeader` берётся из composition-API `Tooltip.MobileHeader`, `paletteIndex` иконки вынесен в константу. Добавлены unit-тесты (25 кейсов, включая мобильную версию). |
|
|
121
121
|
| 2026-09-10 | Ловушка фокуса больше не активируется при открытии подсказки наведением мыши (`needFocusTrap`): фокус остаётся в элементе, с которым работает пользователь. Добавлены unit-тесты на hover- и клавиатурный сценарии. |
|
|
122
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны имена без строки в `docs/ai/ROADMAP.md` (`FocusTrap`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
122
123
|
|
|
123
124
|
---
|
|
124
125
|
|
|
@@ -112,15 +112,19 @@ CSS-модуль `styles/IconWrapper.module.less` содержит только
|
|
|
112
112
|
сделать кликабельную иконку.
|
|
113
113
|
- `Link` (`src/components/Link/Link.tsx`) — оборачивает содержимое ссылки в
|
|
114
114
|
`IconWrapper displayContents`, чтобы иконка внутри ссылки красилась вместе с текстом.
|
|
115
|
-
- `Button` (`src/components/Button/Button.tsx`) — оборачивает содержимое кнопки в
|
|
116
|
-
`IconWrapper` с кастомным `className` и прокидывает `disabled` / `active`. Единственный
|
|
117
|
-
в `src/**` случай передачи собственного `className` в IconWrapper.
|
|
118
115
|
- `Chip`, `ChipSort`, `SegmentedControlSegment`, `StepperStep`, `ListItemControlsButton`,
|
|
119
116
|
`SelectExtendedFieldTarget` — используют IconWrapper для синхронизации цвета иконки
|
|
120
117
|
с состоянием элемента.
|
|
121
|
-
- `
|
|
122
|
-
|
|
123
|
-
|
|
118
|
+
- `Button` (`src/components/Button/Button.tsx`), `CollapsibleTreeNodeHeader`
|
|
119
|
+
(`src/components/CollapsibleTree/components/`) — **не используют** IconWrapper, ставят те
|
|
120
|
+
же глобальные классы (`hoverable` / `active` / `disabled`) напрямую на корневой `<button>`;
|
|
121
|
+
при изменении логики классов держи все места синхронными. `Button` явно переходил на
|
|
122
|
+
`IconWrapper displayContents` и откатился: обёртка добавляла DOM-узел вокруг `<button>`, из-за
|
|
123
|
+
чего два соседних `Button` переставали быть смежными DOM-siblings и ломался CSS-отступ между
|
|
124
|
+
ними (`.button + .button` в `Button.module.less`), плюс это меняло корневой DOM-элемент,
|
|
125
|
+
который внешние потребители могли таргетить напрямую (`>`- и sibling-селекторы). Для
|
|
126
|
+
`ButtonIcon`/`SegmentedControlSegment` того же риска нет — у них нет CSS, зависящего от
|
|
127
|
+
смежности соседних экземпляров.
|
|
124
128
|
|
|
125
129
|
---
|
|
126
130
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: ImageGallery
|
|
3
3
|
category: ImageGallery
|
|
4
|
-
related: [ImageGalleryExtended, MobileView
|
|
4
|
+
related: [ImageGalleryExtended, MobileView]
|
|
5
5
|
tokens:
|
|
6
6
|
- ImageGallery.Accent_Color
|
|
7
7
|
- ImageGallery.Arrow_Background_Default
|
|
@@ -194,6 +194,7 @@ Runtime CSS-переменная высоты крупной картинки
|
|
|
194
194
|
|---|---|
|
|
195
195
|
| 2026-05-28 | Создан документ |
|
|
196
196
|
| 2026-08-31 | Удалены неиспользуемые токены `Arrow_Background_Disabled` и `Arrow_BorderColor_Disabled`: неактивная стрелка скрывается (`display: none`), красить нечем |
|
|
197
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны несимметричные имена (`LightBox`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
197
198
|
|
|
198
199
|
---
|
|
199
200
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: ImageGalleryExtended
|
|
3
3
|
category: ImageGalleryExtended
|
|
4
|
-
related: [ImageGallery, MobileView
|
|
4
|
+
related: [ImageGallery, MobileView]
|
|
5
5
|
tokens:
|
|
6
6
|
- ImageGallery.Accent_Color
|
|
7
7
|
- ImageGallery.Arrow_Background_Default
|
|
@@ -247,6 +247,7 @@ API (экспортируются из barrel ради композиции, н
|
|
|
247
247
|
|---|---|
|
|
248
248
|
| 2026-05-28 | Создан документ |
|
|
249
249
|
| 2026-08-31 | Удалены неиспользуемые токены `Arrow_Background_Disabled` и `Arrow_BorderColor_Disabled`: неактивная стрелка скрывается (`display: none`), красить нечем |
|
|
250
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны несимметричные имена (`LightBox`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
250
251
|
|
|
251
252
|
---
|
|
252
253
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: IslandAccordion
|
|
3
3
|
category: Layout
|
|
4
|
-
related: [Island, IslandWidget, ExpandAnimation, Step, ButtonIcon]
|
|
4
|
+
related: [Island, IslandWidget, Spoiler, ExpandAnimation, Step, ButtonIcon]
|
|
5
5
|
tokens:
|
|
6
6
|
- IslandAccordion.Type1_Header_Background_Hover
|
|
7
7
|
- IslandAccordion.Type2_Header_Background_Hover
|
|
@@ -226,6 +226,10 @@ Hover-фон заголовка применяется только к **свё
|
|
|
226
226
|
пользу, поэтому правки селекторов отступов `Island` ломают аккордеон молча.
|
|
227
227
|
- `IslandWidget` — виджет на `Island`, который сворачивается в адаптиве, а не по клику. Свои
|
|
228
228
|
Header / Body / Footer, частями `Island` не пользуется.
|
|
229
|
+
- `Spoiler` — альтернатива уровнем ниже: одна кнопка-ссылка, раскрывающая содержимое на месте.
|
|
230
|
+
Ни карточки, ни заголовка с номером и статусом, ни удаления, ни группировки нескольких
|
|
231
|
+
элементов, ни анимации высоты — содержимое переключается мгновенно. Если раскрываемый блок
|
|
232
|
+
не должен выглядеть самостоятельной секцией, нужен он, а не аккордеон.
|
|
229
233
|
|
|
230
234
|
### Контракты по рендеру (в `related`)
|
|
231
235
|
|
|
@@ -271,6 +275,7 @@ Hover-фон заголовка применяется только к **свё
|
|
|
271
275
|
|
|
272
276
|
| Дата | Изменение |
|
|
273
277
|
|---|---|
|
|
278
|
+
| 2026-09-28 | В `related` и «Альтернативы» добавлен `Spoiler` — симметрия связи-альтернативы с его AI.md (TRI-81). Правка только документации. |
|
|
274
279
|
| 2026-09-09 | Создан документ. AI-рефакторинг: JSDoc на props, компонентах и контексте; синхронизация `opened` перенесена из `useEffect` в фазу рендера (промежуточный кадр со старым состоянием больше не отрисовывается); автогенерируемые id заголовка и содержимого получили вид `IslandAccordionItem-<n>-header` / `-body`; при `num={0}` со статусом больше не отрисовывается текст «0»; добавлены unit-тесты на `IslandAccordionItem`, контекст, части и публичный контракт `IslandAccordion`. Публичный API не изменён. |
|
|
275
280
|
|
|
276
281
|
---
|