@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,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: EmptyView
|
|
3
|
+
category: Feedback
|
|
4
|
+
figma-node: "80-48"
|
|
5
|
+
figma-file: "https://www.figma.com/design/lpkxmWZ512mG2OJyDvGtHD/-W--LIB-DSN-01-Components-DCB-Next-v.1.3.0"
|
|
6
|
+
related: [Button]
|
|
7
|
+
tokens:
|
|
8
|
+
- --triplex-next-Typography-Primary_Color
|
|
9
|
+
- --triplex-next-Typography-Secondary_Color
|
|
10
|
+
stories: stories/EmptyView/EmptyView.stories.tsx
|
|
11
|
+
version: "1.0"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# EmptyView
|
|
15
|
+
|
|
16
|
+
## Назначение
|
|
17
|
+
|
|
18
|
+
Компонент для отображения пустых состояний: нет данных, сервис недоступен, нет результатов поиска и т.д.
|
|
19
|
+
|
|
20
|
+
Используй когда: нужно показать заглушку при отсутствии контента.
|
|
21
|
+
Не используй когда: есть контент для отображения или нужно показать ошибку загрузки (используй Alert).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Варианты и props
|
|
26
|
+
|
|
27
|
+
### Обязательные props
|
|
28
|
+
|
|
29
|
+
| Prop | Тип | Описание |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `size` | `EEmptyViewSize` | Размер: SM / MD |
|
|
32
|
+
|
|
33
|
+
### Опциональные props
|
|
34
|
+
|
|
35
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| `icon` | `ReactNode` | — | Иконка (96px для SM, 128px для MD) |
|
|
38
|
+
| `title` | `ReactNode` | — | Заголовок |
|
|
39
|
+
| `description` | `ReactNode` | — | Текст описания |
|
|
40
|
+
| `caption` | `ReactNode` | — | Подпись |
|
|
41
|
+
| `buttons` | `ReactNode` | — | Кнопки действий |
|
|
42
|
+
|
|
43
|
+
### Поведение описания
|
|
44
|
+
|
|
45
|
+
- Если `title` задан: описание отображается вторичным цветом (Secondary)
|
|
46
|
+
- Если `title` не задан: описание становится основным текстом (Primary)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Дизайн-токены
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
--triplex-next-Typography-Primary_Color (title, description без title)
|
|
54
|
+
--triplex-next-Typography-Secondary_Color (description с title, caption)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Инварианты
|
|
60
|
+
|
|
61
|
+
- `forwardRef` на компоненте — не убирать
|
|
62
|
+
- `EEmptyViewSize` — публичный enum, менять значения нельзя
|
|
63
|
+
- CSS-классы `emptyView`, `hasTitle` используются в тестах
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Accessibility
|
|
68
|
+
|
|
69
|
+
- Компонент не требует обязательных aria-атрибутов
|
|
70
|
+
- Потребитель может передать `role`, `aria-label` и другие атрибуты через spread
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Связанные компоненты
|
|
75
|
+
|
|
76
|
+
- `Button` — используется в `buttons` для действий
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Stories
|
|
81
|
+
|
|
82
|
+
Основные истории: `stories/EmptyView/EmptyView.stories.tsx`
|
|
83
|
+
Файлы примеров: `stories/EmptyView/examples/`
|
|
84
|
+
|
|
85
|
+
| Story | Example file | Что демонстрирует |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль всех props |
|
|
88
|
+
| `Default` | `DefaultExample.tsx` | Минимальное состояние с title, description и caption |
|
|
89
|
+
| `Sizes` | `SizesExample.tsx` | Размеры SM / MD |
|
|
90
|
+
| `WithoutTitle` | `WithoutTitleExample.tsx` | Вариант без заголовка |
|
|
91
|
+
| `WithButtons` | `WithButtonsExample.tsx` | Вариант с кнопками действий |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## История изменений
|
|
96
|
+
|
|
97
|
+
| Дата | Изменение |
|
|
98
|
+
|---|---|
|
|
99
|
+
| 2026-04-09 | Создан компонент и документ |
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ExpandAnimation
|
|
3
|
+
category: Animation
|
|
4
|
+
figma-node: ""
|
|
5
|
+
figma-file: ""
|
|
6
|
+
related: [AccordionBase, Spoiler, IslandAccordion, CollapsableTree]
|
|
7
|
+
tokens: []
|
|
8
|
+
stories: ""
|
|
9
|
+
version: "1.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ExpandAnimation
|
|
13
|
+
|
|
14
|
+
## Назначение
|
|
15
|
+
|
|
16
|
+
Инфраструктурный компонент-"анимация": плавное сворачивание/разворачивание
|
|
17
|
+
блока по высоте (`height: 0 ↔ scrollHeight`) через `react-transition-group`.
|
|
18
|
+
Используется в `AccordionBase`, `IslandAccordion`, `Spoiler`,
|
|
19
|
+
`CollapsableTree` и любом compound'е, где нужно "раскрыть / свернуть"
|
|
20
|
+
блок.
|
|
21
|
+
|
|
22
|
+
Ключевая задача — **анимация CSS через height** (у которой нет `auto` в
|
|
23
|
+
transitions), реализованная через явное измерение `scrollHeight` и
|
|
24
|
+
переключение между `0 ↔ измеренная высота` в нужные моменты жизненного
|
|
25
|
+
цикла Transition.
|
|
26
|
+
|
|
27
|
+
Используй когда: строишь собственный компонент с разворачивающимся
|
|
28
|
+
блоком. Подписывайся на `onStart`/`onEnd` для syncронизации логики.
|
|
29
|
+
Не используй как: универсальная анимация "fade" — только expand/collapse.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Файловая структура
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
src/components/ExpandAnimation/
|
|
37
|
+
├── ExpandAnimation.tsx # forwardRef, Transition wrapper
|
|
38
|
+
├── index.ts # Barrel
|
|
39
|
+
└── styles/
|
|
40
|
+
├── ExpandAnimation.module.less # .expandAnimation { transition-property: height; timing: ease-in-out }
|
|
41
|
+
└── ExpandedAnimation.module.less # дубликат-остаток (см. ниже)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Особенности:
|
|
45
|
+
- **`forwardRef`** — есть.
|
|
46
|
+
- **`ExpandedAnimation.module.less`** — дублирующийся файл с тем же
|
|
47
|
+
содержимым (`.expandedAnimation` вместо `.expandAnimation`). Не
|
|
48
|
+
импортируется компонентом, legacy-остаток. **Не удалять
|
|
49
|
+
отдельным коммитом без проверки потребителей** — возможно, кто-то
|
|
50
|
+
импортирует его напрямую.
|
|
51
|
+
- **Нет `__tests__`** — покрывается через потребителей
|
|
52
|
+
(AccordionBase-tests проверяют анимацию косвенно).
|
|
53
|
+
- **Нет stories** — внутренний/инфраструктурный.
|
|
54
|
+
- **Без `data-tx`** — не ставит атрибут версии.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Варианты и props
|
|
59
|
+
|
|
60
|
+
### `IExpandAnimationProps extends React.HTMLAttributes<HTMLDivElement>`
|
|
61
|
+
|
|
62
|
+
| Prop | Тип | Default | Описание |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| `expanded` | `boolean` | — (обязателен) | Целевое состояние: раскрыт/свёрнут. Controlled. |
|
|
65
|
+
| `animationTime` | `number` | `300` (мс) | Длительность transition. Идёт в `timeout` Transition'а и в `transitionDuration` inline-стиля. |
|
|
66
|
+
| `onStart` | `() => void` | — | Срабатывает в начале анимации (onEnter и onExit). |
|
|
67
|
+
| `onEnd` | `() => void` | — | Срабатывает в конце анимации (onEntered и onExited). |
|
|
68
|
+
| `transitionProps` | `React.ComponentProps<typeof Transition<HTMLDivElement>>` | — | Дополнительные пропсы для `Transition`. Колбэки мержатся (см. ниже). |
|
|
69
|
+
| `className`, `style`, `children`, `...HTMLDivAttributes` | — | — | Стандартные. |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Ключевые особенности реализации
|
|
74
|
+
|
|
75
|
+
### Transition статусы → inline-styles
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const transitionStylesRef = useRef<Record<TransitionStatus, React.CSSProperties>>({
|
|
79
|
+
entering: { height: undefined, overflow: "hidden" }, // height задаётся в onEnter
|
|
80
|
+
entered: {},
|
|
81
|
+
exiting: { height: 0, overflow: "hidden" },
|
|
82
|
+
exited: { height: 0, overflow: "hidden", visibility: "hidden" },
|
|
83
|
+
unmounted: {},
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Состояния:**
|
|
88
|
+
- **`entering`** — начало раскрытия. `height` проставляется **в
|
|
89
|
+
момент onEnter**, до этого `undefined` (браузер рендерит от 0 к
|
|
90
|
+
`scrollHeight`).
|
|
91
|
+
- **`entered`** — раскрыт. Пусто — браузер держит естественную высоту
|
|
92
|
+
(`auto`).
|
|
93
|
+
- **`exiting`** — начало сворачивания. `height: 0` + `overflow: hidden`.
|
|
94
|
+
- **`exited`** — свёрнут. `height: 0 + overflow: hidden + visibility: hidden`.
|
|
95
|
+
`visibility: hidden` убирает из tab-order.
|
|
96
|
+
- **`unmounted`** — компонент размонтирован, пусто.
|
|
97
|
+
|
|
98
|
+
**useRef** — объект не пересоздаётся между рендерами, ссылки на
|
|
99
|
+
`CSSProperties` стабильны.
|
|
100
|
+
|
|
101
|
+
### Измерение высоты в onEnter
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const handleEnter = (appearing) => {
|
|
105
|
+
if (nodeRef.current) {
|
|
106
|
+
transitionStylesRef.current["entering"].height = nodeRef.current.scrollHeight;
|
|
107
|
+
}
|
|
108
|
+
onStart?.();
|
|
109
|
+
transitionProps?.onEnter?.(appearing);
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**`scrollHeight` читается из DOM** — это реальная высота содержимого.
|
|
114
|
+
Браузер проанимирует от `0` до этого значения. Почему в onEnter:
|
|
115
|
+
перед ним height был `0`, после onEnter — DOM получит конкретное
|
|
116
|
+
значение для transition to.
|
|
117
|
+
|
|
118
|
+
**Проблема "height: auto в transitions":** CSS не может transition
|
|
119
|
+
между `0` и `auto`. ExpandAnimation решает это, подставляя реальное
|
|
120
|
+
число.
|
|
121
|
+
|
|
122
|
+
### onExit: hack с `scrollHeight` и force reflow
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const handleExit = () => {
|
|
126
|
+
if (nodeRef.current) {
|
|
127
|
+
nodeRef.current.style.height = nodeRef.current.scrollHeight + "px";
|
|
128
|
+
// trigger reflow
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
130
|
+
nodeRef.current.scrollHeight;
|
|
131
|
+
}
|
|
132
|
+
onStart?.();
|
|
133
|
+
transitionProps?.onExit?.();
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Последовательность:**
|
|
138
|
+
1. Ставим `style.height = scrollHeight + "px"` — конкретное значение,
|
|
139
|
+
от которого пойдёт transition.
|
|
140
|
+
2. **Force reflow** — читаем `scrollHeight` "впустую" (expression с
|
|
141
|
+
lint-ignore). Без этого браузер может "оптимизировать" и не
|
|
142
|
+
зафиксировать промежуточный state — transition пойдёт от "auto"
|
|
143
|
+
сразу к "0" без плавности.
|
|
144
|
+
3. Вызываем `onStart` и обёрнутый колбэк.
|
|
145
|
+
4. React-Transition-Group затем переключит в `exiting`, где inline
|
|
146
|
+
style из `transitionStylesRef` ставит `height: 0` → браузер
|
|
147
|
+
анимирует от запомненной высоты до 0.
|
|
148
|
+
|
|
149
|
+
**Не удалять `nodeRef.current.scrollHeight;` "пустое" чтение** — это
|
|
150
|
+
**is** reflow trigger. Без него анимация не работает.
|
|
151
|
+
|
|
152
|
+
### `nodeRef` — обязательный для Transition с `nodeRef` паттерном
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
<Transition in={expanded} timeout={animationTime} nodeRef={nodeRef} ...>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`react-transition-group` v4+ требует `nodeRef` для strict-mode
|
|
159
|
+
совместимости (вместо `findDOMNode`). `nodeRef` в ExpandAnimation
|
|
160
|
+
ставится через `setRef` (который также форвардит внешний ref).
|
|
161
|
+
|
|
162
|
+
### Слияние колбэков Transition
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
<Transition
|
|
166
|
+
{...transitionProps}
|
|
167
|
+
onEnter={handleEnter} // переопределяет transitionProps.onEnter
|
|
168
|
+
onEntered={handleEntered}
|
|
169
|
+
onExit={handleExit}
|
|
170
|
+
onExited={handleExited}
|
|
171
|
+
>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**`handle*` вызывают `transitionProps?.onEnter?.(...)` и т. п.** — так
|
|
175
|
+
что если пользователь передал свои `onEnter` через transitionProps,
|
|
176
|
+
они всё равно выполнятся, но **после** наших handler'ов.
|
|
177
|
+
|
|
178
|
+
**Порядок:** наш handler → (onStart для start-ветки) → user's onEnter/Exit.
|
|
179
|
+
|
|
180
|
+
### `style` inline — слияние трёх источников
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
style={{
|
|
184
|
+
transitionDuration: animationTime + "ms",
|
|
185
|
+
...transitionStylesRef.current[state],
|
|
186
|
+
...style,
|
|
187
|
+
}}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Порядок:** дефолт duration → наш state-style → пользовательский
|
|
191
|
+
`style`. Пользовательский стиль побеждает — он может подрезать
|
|
192
|
+
наше поведение, если потребитель этого хочет.
|
|
193
|
+
|
|
194
|
+
### `setRef` — double-duty ref
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const setRef = (instance) => {
|
|
198
|
+
nodeRef.current = instance;
|
|
199
|
+
if (typeof ref === "function") ref(instance);
|
|
200
|
+
else if (ref) ref.current = instance;
|
|
201
|
+
};
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Внутренний `nodeRef` (для Transition) + внешний forwarded ref.
|
|
205
|
+
|
|
206
|
+
### Дубликат файла `ExpandedAnimation.module.less`
|
|
207
|
+
|
|
208
|
+
Файл существует, но **не используется** компонентом. Вероятно legacy
|
|
209
|
+
от переименования. Не удалять без проверки прямого импорта из
|
|
210
|
+
потребителей (`grep -r "ExpandedAnimation"`).
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Инварианты
|
|
215
|
+
|
|
216
|
+
- **`nodeRef.current.scrollHeight;` в handleExit** — force reflow.
|
|
217
|
+
Не удалять. Без него transition ломается.
|
|
218
|
+
- **`expanded` — controlled only** — нет defaultExpanded.
|
|
219
|
+
- **Состояние inline-styles в `transitionStylesRef`** — мутабельные
|
|
220
|
+
объекты, храним в ref чтобы не пересоздавать.
|
|
221
|
+
- **Transition `nodeRef`** — обязателен (v4+ API).
|
|
222
|
+
- **`visibility: hidden` в exited** — убирает из tab-order. Не
|
|
223
|
+
менять на `display: none` (сломает transition).
|
|
224
|
+
- **`transitionProps` колбэки вызываются после наших** — порядок
|
|
225
|
+
важен, не менять.
|
|
226
|
+
- **`animationTime` синхронизирован между `timeout` Transition'а и
|
|
227
|
+
`transitionDuration`** — не менять одно без другого.
|
|
228
|
+
- **`data-tx`** — не проставляется (нестандартно для библиотеки,
|
|
229
|
+
возможен debt).
|
|
230
|
+
- **`forwardRef`** — есть.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Accessibility
|
|
235
|
+
|
|
236
|
+
- **`visibility: hidden` в свёрнутом состоянии** — убирает элементы
|
|
237
|
+
из tab-order и screen reader'а. Важный инвариант для "раскрытые
|
|
238
|
+
элементы не доступны клавиатурой".
|
|
239
|
+
- **`overflow: hidden`** в анимации — скрывает частично видимый
|
|
240
|
+
контент.
|
|
241
|
+
- **`aria-expanded`** — **не** проставляется ExpandAnimation. Это
|
|
242
|
+
задача потребителя (AccordionBase делает это).
|
|
243
|
+
- **`onStart`/`onEnd`** — позволяют потребителю обновить ARIA-state
|
|
244
|
+
в правильный момент (например, объявить "свернуто" для screen
|
|
245
|
+
reader'а после завершения).
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Дизайн-токены
|
|
250
|
+
|
|
251
|
+
**Нет.** Чистая инфраструктура анимации.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Связанные компоненты
|
|
256
|
+
|
|
257
|
+
- `AccordionBase` (`src/components/AccordionBase/protected/AccordionBase`) —
|
|
258
|
+
главный потребитель. Оборачивает ExpandAnimation + добавляет
|
|
259
|
+
`aria-expanded`, заголовок, клик.
|
|
260
|
+
- `IslandAccordion` (`src/components/IslandAccordion`) — использует
|
|
261
|
+
ExpandAnimation напрямую или через AccordionBase.
|
|
262
|
+
- `Spoiler` (`src/components/Spoiler`) — альтернатива без заголовка-
|
|
263
|
+
кнопки.
|
|
264
|
+
- `CollapsableTree` (`src/components/CollapsableTree`) — composes
|
|
265
|
+
ExpandAnimation через AccordionBase.
|
|
266
|
+
- `react-transition-group` — внешняя зависимость.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Stories
|
|
271
|
+
|
|
272
|
+
**Нет собственных stories.** Инфраструктурный компонент. Видно в
|
|
273
|
+
действии через AccordionBase/Spoiler/IslandAccordion stories.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## История изменений
|
|
278
|
+
|
|
279
|
+
| Дата | Изменение |
|
|
280
|
+
|---|---|
|
|
281
|
+
| 2026-04-18 | Создан документ |
|