@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.
Files changed (73) hide show
  1. package/README.md +10 -0
  2. package/bundle/components/AlertContext.md +268 -0
  3. package/bundle/components/BodyPage.md +186 -0
  4. package/bundle/components/Button.md +93 -85
  5. package/bundle/components/ButtonDropdown.md +36 -70
  6. package/bundle/components/ButtonDropdownExtended.md +422 -0
  7. package/bundle/components/ButtonIcon.md +41 -48
  8. package/bundle/components/Caption.md +291 -0
  9. package/bundle/components/Checkbox.md +43 -122
  10. package/bundle/components/CheckboxXGroup.md +109 -46
  11. package/bundle/components/CheckboxYGroup.md +77 -49
  12. package/bundle/components/CodeText.md +197 -0
  13. package/bundle/components/Col.md +311 -162
  14. package/bundle/components/CollapsibleTree.md +584 -0
  15. package/bundle/components/CollapsibleTreeExtended.md +422 -0
  16. package/bundle/components/Dropdown.md +748 -346
  17. package/bundle/components/EmptyView.md +14 -15
  18. package/bundle/components/FooterPage.md +203 -0
  19. package/bundle/components/Gap.md +115 -57
  20. package/bundle/components/HeaderPage.md +226 -0
  21. package/bundle/components/HelpBox.md +45 -84
  22. package/bundle/components/ImageGallery.md +423 -0
  23. package/bundle/components/ImageGalleryExtended.md +606 -0
  24. package/bundle/components/LightBox.md +2252 -233
  25. package/bundle/components/List.md +216 -183
  26. package/bundle/components/ListActionItem.md +157 -0
  27. package/bundle/components/ListItem.md +276 -0
  28. package/bundle/components/ListItemControlsButton.md +103 -0
  29. package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
  30. package/bundle/components/ListItemSelectable.md +99 -0
  31. package/bundle/components/ListItemTable.md +390 -0
  32. package/bundle/components/ListMaster.md +876 -156
  33. package/bundle/components/ListMasterFooter.md +80 -0
  34. package/bundle/components/ListMasterHeader.md +86 -0
  35. package/bundle/components/ListSortable.md +153 -0
  36. package/bundle/components/ListSortableItem.md +175 -0
  37. package/bundle/components/ListTableItem.md +391 -0
  38. package/bundle/components/ModalWindow.md +427 -237
  39. package/bundle/components/MonthYearField.md +145 -109
  40. package/bundle/components/Notification.md +625 -155
  41. package/bundle/components/Overlay.md +271 -170
  42. package/bundle/components/Page.md +284 -186
  43. package/bundle/components/Pagination.md +206 -229
  44. package/bundle/components/Portal.md +131 -67
  45. package/bundle/components/Row.md +171 -69
  46. package/bundle/components/Text.md +320 -0
  47. package/bundle/components/TextField.md +364 -97
  48. package/bundle/components/Title.md +296 -0
  49. package/bundle/guides/codestyle.md +38 -11
  50. package/bundle/guides/commits.md +119 -26
  51. package/bundle/guides/context.md +34 -30
  52. package/bundle/guides/stories.md +110 -40
  53. package/bundle/guides/template.md +3 -7
  54. package/bundle/guides/tests.md +48 -2
  55. package/bundle/manifest.json +275 -30
  56. package/bundle/release-notes/1.26.0.mdx +33 -2
  57. package/bundle/release-notes/1.27.0.mdx +43 -0
  58. package/bundle/release-notes/1.28.0.mdx +25 -0
  59. package/bundle/release-notes/1.29.0.mdx +47 -0
  60. package/bundle/release-notes/1.30.0.mdx +56 -0
  61. package/bundle/release-notes/1.31.0.mdx +52 -0
  62. package/bundle/release-notes/1.32.0.mdx +35 -0
  63. package/bundle/release-notes/1.33.0.mdx +61 -0
  64. package/bundle/release-notes/1.34.0.mdx +35 -0
  65. package/bundle/release-notes/1.35.0.mdx +21 -0
  66. package/bundle/release-notes/1.35.1.mdx +11 -0
  67. package/bundle/release-notes/1.36.0.mdx +21 -0
  68. package/bundle/release-notes/1.37.0.mdx +71 -0
  69. package/bundle/release-notes/1.38.0.mdx +36 -0
  70. package/bundle/release-notes/1.39.0.mdx +66 -0
  71. package/bundle/release-notes/1.40.0.mdx +27 -0
  72. package/bundle/release-notes/1.41.0.mdx +7 -0
  73. package/package.json +1 -1
@@ -1,237 +1,338 @@
1
1
  ---
2
2
  component: Overlay
3
- category: Overlays
4
- figma-node: ""
5
- figma-file: ""
6
- related: [SideOverlay, ModalWindow, LightBox]
7
- tokens: [triplex-next-Overlay-Panel_Background]
3
+ category: Overlay
4
+ related: [OverlayBase, OverlayMask, OverlayPanel, LightBox, TopOverlay, ModalWindow, DropdownMobile]
5
+ tokens: [--triplex-next-Overlay-Background, --triplex-next-Overlay-Panel_Background]
8
6
  stories: stories/Overlay/Overlay.stories.tsx
9
- version: "1.0"
7
+ version: "1.34.0"
10
8
  ---
11
9
 
12
10
  # Overlay
13
11
 
14
12
  ## Назначение
15
13
 
16
- Низкоуровневый строительный блок для всплывающих панелей с CSS-анимацией
17
- выезда из четырёх направлений (top/right/bottom/left). Сам компонент —
18
- **stage manager** жизненного цикла (opening → opened → closing → closed)
19
- и контейнер с position absolute/fixed; визуальная панель и затемнение —
20
- `Overlay.Panel` и `Overlay.Mask`, рендерятся через render-prop'ы.
14
+ Затемняющий слой с выезжающей из выбранной стороны панелью контента. Применяется
15
+ для отображения дополнительного контента поверх элемента (`absolute`, по
16
+ умолчанию) или поверх всей страницы (`fixed`). Анимация открытия/закрытия —
17
+ CSS-transition панели (`transform`) и маски (`opacity`).
21
18
 
22
- Используй когда: строишь свой нестандартный overlay (drawer, side-sheet)
23
- и нужны хуки на фазах жизненного цикла. Для готовых решений —
24
- `SideOverlay` (на основе Overlay), `ModalWindow`, `LightBox`.
19
+ Компонент построен как семейство: корневой `Overlay` (контейнер + управление
20
+ жизненным циклом через `OverlayBase`) со статическими `Overlay.Mask`
21
+ (кликабельный фон) и `Overlay.Panel` (выезжающая панель). Контент задаётся
22
+ render-функцией `children`, которая получает состояние оверлея.
25
23
 
26
- ---
27
-
28
- ## Файловая структура
29
-
30
- ```text
31
- src/components/Overlay/
32
- ├── Overlay.tsx # FC + slots; контейнер-обёртка, локальный closing для css-класса
33
- ├── OverlayBase.tsx # FC; render-prop, lifecycle (opening/closing), enum direction
34
- ├── OverlayMask.tsx # forwardRef; полупрозрачный фон
35
- ├── OverlayPanel.tsx # forwardRef; выезжающая панель + onTransitionEnd
36
- ├── index.ts # Barrel: Overlay, OverlayBase, OverlayMask, OverlayPanel + enum
37
- └── styles/Overlay.module.less
38
- ```
24
+ Используй когда: нужна выезжающая боковая/верхняя/нижняя панель (drawer,
25
+ off-canvas) над контейнером или страницей.
26
+ Не используй когда: нужно модальное окно по центру — используй `ModalWindow`;
27
+ нужен полноэкранный слой просмотра — `LightBox`.
39
28
 
40
29
  ---
41
30
 
42
- ## Compound-структура (через render-prop)
43
-
44
- ```tsx
45
- <Overlay
46
- direction={EOverlayDirection.RIGHT}
47
- opened={opened}
48
- setOpened={setOpened}
49
- onOpen={...}
50
- onClose={...}
51
- fixed
52
- >
53
- {(provided) => (
54
- <>
55
- <Overlay.Mask opened={provided.opened} onClick={() => provided.setOpened(false)} />
56
- <Overlay.Panel {...provided}>
57
- {/* контент */}
58
- </Overlay.Panel>
59
- </>
60
- )}
61
- </Overlay>
62
- ```
63
-
64
- `Overlay.children` — **функция**, не ReactNode. Получает `IOverlayChildrenProvideProps`.
31
+ ## Варианты и props
65
32
 
66
- ---
33
+ ### `Overlay` — обязательные props
67
34
 
68
- ## Варианты и props
35
+ | Prop | Тип | Описание |
36
+ |---|---|---|
37
+ | `direction` | `EOverlayDirection` | Сторона, из которой выезжает панель: `RIGHT` / `LEFT` / `TOP` / `BOTTOM`. По умолчанию в `OverlayBase` — `RIGHT` |
38
+ | `opened` | `boolean` | Управляемое состояние открытости. Изменение запускает анимацию открытия/закрытия |
39
+ | `setOpened` | `(opened: boolean) => void` | Сеттер `opened`, прокидывается в `provideProps` для управления изнутри панели |
40
+ | `children` | `(provideProps) => React.ReactElement` | Render-функция контента. См. «provideProps» ниже |
69
41
 
70
- ### Overlay — `IOverlayProps extends IOverlayBaseProps, Omit<HTMLAttributes<HTMLDivElement>, "children">`
42
+ ### `Overlay` — опциональные props
71
43
 
72
- | Prop | Тип | Default | Описание |
44
+ | Prop | Тип | По умолчанию | Описание |
73
45
  |---|---|---|---|
74
- | `direction` | `EOverlayDirection` | (default `RIGHT` в `OverlayBase`) | Направление выезда. |
75
- | `opened` | `boolean` | — | Контролируемое состояние открытия. |
76
- | `setOpened` | `(opened: boolean) => void` | — | Сеттер `opened` (передаётся в render-prop). |
77
- | `fixed` | `boolean` | `false` | `position: fixed` (на всю страницу) vs `absolute` (поверх родителя). |
78
- | `onOpening` / `onOpen` / `onClosing` / `onClose` | `() => void` | — | Lifecycle-callback'и (см. ниже). |
79
- | `children` | `(props) => ReactElement` | — | render-prop. |
80
- | `...HTMLAttributes` | — | — | На корневой `<div>`. |
46
+ | `fixed` | `boolean` | `false` | `position: fixed` (на всю страницу) вместо `absolute` (поверх родителя) |
47
+ | `onOpening` | `() => void` | — | Вызывается в начале открытия |
48
+ | `onOpen` | `() => void` | — | Вызывается по завершении анимации открытия |
49
+ | `onClosing` | `() => void` | — | Вызывается в начале закрытия |
50
+ | `onClose` | `() => void` | — | Вызывается по завершении анимации закрытия |
51
+ | `...HTMLDivAttributes` | — | — | Стандартные атрибуты корневого `<div>` (кроме `children`) |
81
52
 
82
- ### OverlayBase — `IOverlayBaseProps`
53
+ ### provideProps (аргумент render-функции `children`)
83
54
 
84
- То же подмножество, что и Overlay (без `fixed` и без HTML-атрибутов). Можно использовать **без** wrapper'а Overlay, если не нужна обёртка-`<div>`.
55
+ Передаются из `OverlayBase` в `children` и далее пробрасываются в `Overlay.Panel`
56
+ через `{...provideProps}`:
85
57
 
86
- ### `IOverlayChildrenProvideProps`
87
-
88
- ```ts
89
- {
90
- direction: EOverlayDirection;
91
- opened: boolean;
92
- setOpened: (opened: boolean) => void;
93
- closing: boolean;
94
- opening: boolean;
95
- setClosing: (closing: boolean) => void;
96
- setOpening: (opening: boolean) => void;
97
- }
98
- ```
58
+ | Поле | Тип | Описание |
59
+ |---|---|---|
60
+ | `direction` | `EOverlayDirection` | Текущее направление |
61
+ | `opened` | `boolean` | Текущее состояние открытости |
62
+ | `opening` | `boolean` | Идёт анимация открытия |
63
+ | `closing` | `boolean` | Идёт анимация закрытия |
64
+ | `setOpened` | `(boolean) => void` | Сеттер `opened` |
65
+ | `setOpening` | `(boolean) => void` | Сеттер флага `opening` |
66
+ | `setClosing` | `(boolean) => void` | Сеттер флага `closing` |
99
67
 
100
- ### EOverlayDirection
68
+ ### `Overlay.Mask` (`OverlayMask`)
101
69
 
102
- `BOTTOM | LEFT | RIGHT | TOP`.
70
+ Кликабельный полупрозрачный фон между контейнером и панелью. Props: `opened`
71
+ (управляет классом `overlayOpened` → `opacity`), плюс `...HTMLDivAttributes`
72
+ (обычно `onClick` для закрытия). `forwardRef` → `HTMLDivElement`.
103
73
 
104
- ### OverlayMask — `IOverlayMaskProps extends Pick<IOverlayChildrenProvideProps, "opened">, HTMLAttributes<HTMLDivElement>`
74
+ ### `Overlay.Panel` (`OverlayPanel`)
105
75
 
106
- - `opened: boolean` — управляет CSS-классом `overlayOpened` (тригерит fade-in).
107
- - `forwardRef<HTMLDivElement>`.
108
- - Не реагирует на клик сам — потребитель вешает `onClick` для закрытия.
76
+ Выезжающая панель с контентом. Принимает весь `provideProps` (через спред) плюс
77
+ `direction`, `children` и `...HTMLDivAttributes`. По `onTransitionEnd` своего
78
+ корневого элемента сбрасывает `closing`/`opening` (отсекая bubbling от потомков
79
+ через сравнение `target === currentTarget`). `forwardRef` → `HTMLDivElement`.
109
80
 
110
- ### OverlayPanel — `IOverlayPanelProps extends HTMLAttributes<HTMLDivElement>, IOverlayChildrenProvideProps`
81
+ ### `OverlayBase`
111
82
 
112
- - `forwardRef<HTMLDivElement>`.
113
- - Внутренний `onTransitionEnd` сбрасывает `closing`/`opening` в `false` **только если** `event.target === currentTarget` (защита от вложенных transitions).
114
- - Контент оборачивается в `<div className={overlayContent}>`.
83
+ Низкоуровневый headless-компонент (render-prop, **без** `forwardRef` — ничего не
84
+ рендерит сам, возвращает `children(provideProps)`). Единый источник истины по
85
+ флагам `opened`/`opening`/`closing` и оркестратор колбэков жизненного цикла.
86
+ Использует `useLayoutEffect` (не `useEffect`) при смене `opened`, чтобы избежать
87
+ мерцания при закрытии.
115
88
 
116
89
  ---
117
90
 
118
- ## Ключевые особенности реализации
119
-
120
- ### Lifecycle: `opening` → `opened` → `closing` → `closed`
121
-
122
- ```ts
123
- useLayoutEffect(() => {
124
- if (prevOpened.current && !opened) { setClosing(true); onClosing?.(); }
125
- else if (!prevOpened.current && opened) { setOpening(true); onOpening?.(); }
126
- prevOpened.current = opened;
127
- }, [opened]);
91
+ ## Дизайн-токены
128
92
 
129
- useEffect(() => { closing ? onClosing?.() : onClose?.(); }, [closing]);
130
- useEffect(() => { opening ? onOpening?.() : onOpen?.(); }, [opening]);
93
+ ```
94
+ --triplex-next-Overlay-Background // фон маски (OverlayMask)
95
+ --triplex-next-Overlay-Panel_Background // фон панели (OverlayPanel)
131
96
  ```
132
97
 
133
- - **`useLayoutEffect`** при смене `opened` — намеренно (комментарий в коде: «иначе в браузере может быть мигание при закрытии»).
134
- - `closing` / `opening` сбрасываются в `false` через `onTransitionEnd` в `OverlayPanel` → тогда вызывается `onClose` / `onOpen`.
135
- - **`onClosing` / `onOpening`** вызывается **дважды** в начале (явно из `useLayoutEffect` + из `useEffect` на `closing`/`opening`). Известный нюанс — потребитель должен быть идемпотентен.
136
-
137
- ### Двойной слой `closing` (Overlay + OverlayBase)
98
+ Box-shadow панели и тайминги transition (`0.3s ease-in-out`) заданы константами в
99
+ `styles/Overlay.module.less` — токенов не имеют.
138
100
 
139
- - `Overlay` хранит свой `closing` для CSS-класса `styles.closing` (виден до окончания анимации).
140
- - `OverlayBase` хранит свой `closing` для render-prop'ов.
141
- - **Причина**: `OverlayBase` без обёртки не имеет доступа к корневому `<div>` — нужно дублировать.
101
+ ---
142
102
 
143
- ### `fixed` vs `absolute`
103
+ ## Инварианты
144
104
 
145
- ```less
146
- .overlay { position: absolute; ... &.fixed { position: fixed; } }
147
- ```
105
+ - **`forwardRef`** обязателен на `Overlay` (target — корневой `HTMLDivElement`),
106
+ `Overlay.Mask` и `Overlay.Panel`. Не убирать. `OverlayBase` — render-prop,
107
+ `forwardRef` к нему неприменим.
108
+ - **Статические `Overlay.Mask` / `Overlay.Panel`** — часть публичного API
109
+ (составной компонент). Навешиваются на `forwardRef`-объект через `Object.assign`
110
+ (как `Badge.Dot`), тип компонента выводится автоматически — отдельный `*FC`-тип
111
+ не нужен.
112
+ - **Значения `EOverlayDirection`** (`"right"`/`"left"`/`"top"`/`"bottom"`) —
113
+ публичный API, не переименовывать.
114
+ - **Единый источник истины по `closing`/`opening`/`opened`** — `OverlayBase`.
115
+ Корневой `div` `Overlay` рендерится внутри render-prop и читает `closing` из
116
+ `provideProps` — не дублировать локальным `useState` в `Overlay`.
117
+ - **`provideProps` нужно пробрасывать в `Overlay.Panel`** — без них панель не
118
+ получит direction/флаги и не сбросит `closing`/`opening` по `transitionEnd`.
119
+ - **CSS-классы `bottom`/`left`/`right`/`top`/`opened`/`closing`/`fixed`/
120
+ `overlayOpened`** управляют анимацией — переименование ломает визуальные
121
+ переходы и покрыто unit-тестами.
122
+ - **React 17-совместимость** (ветка `release-0`): без `useId` и других React
123
+ 18-only API.
124
+
125
+ ### Гарантия однократного вызова lifecycle-колбэков
126
+
127
+ `OverlayBase` вызывает каждый из `onOpening` / `onClosing` / `onOpen` / `onClose`
128
+ **ровно один раз** за переход. `useLayoutEffect([opened])` только выставляет
129
+ флаги `opening` / `closing`, а сами колбэки вызываются исключительно в
130
+ `useEffect([opening])` / `useEffect([closing])`. Однократность закреплена
131
+ unit-тестами (`toHaveBeenCalledTimes(1)`).
132
+
133
+ > Ранее (до 2026-06-17) колбэки `onOpening` / `onClosing` вызывались дважды
134
+ > за переход — прямой вызов из `useLayoutEffect` дублировал эффект-driven вызов.
135
+ > Исправлено: прямые вызовы из layout-эффекта удалены.
148
136
 
149
- - По умолчанию — `absolute` (поверх родителя). `fixed` — на весь viewport.
137
+ ---
150
138
 
151
- ### `left: -10000px; visibility: hidden` для closed-state
139
+ ## Accessibility
152
140
 
153
- ```less
154
- .overlay {
155
- left: -10000px;
156
- visibility: hidden;
157
- &.closing, &.opened { visibility: visible; left: 0; right: 0; }
158
- }
159
- ```
141
+ - `Overlay.Mask` кликабелен для закрытия — потребитель навешивает `onClick`
142
+ (`setOpened(false)`); компонент текст/aria не хардкодит (библиотека
143
+ мультиязычная). При необходимости потребитель сам задаёт `aria-label`.
144
+ - Скрытый оверлей выведен за пределы экрана (`left: -10000px`) и `visibility:
145
+ hidden`, чтобы его содержимое не получало фокус, пока он закрыт.
146
+ - Роль диалога (`role="dialog"`/`aria-modal`), захват и возврат фокуса, обработка
147
+ `Escape` — **не реализованы** в самом `Overlay`; при необходимости их
148
+ обеспечивает потребитель или обёртка (`LightBox`, `ModalWindow`).
160
149
 
161
- - Закрытый overlay уезжает за viewport, чтобы:
162
- - Анимация при закрытии не была обрезана `display: none`.
163
- - Внутренние элементы не получали focus (через `visibility: hidden`).
150
+ ---
164
151
 
165
- ### Transform-based анимация в Panel
152
+ ## Связанные компоненты
166
153
 
167
- ```less
168
- .overlayPanel { transition: transform 0.3s ease-in-out; }
169
- .right { transform: translateX(100%); ... &.opened { transform: translateX(0); } }
170
- ```
154
+ - `OverlayBase` — headless-ядро (render-prop), управляет флагами и колбэками
155
+ жизненного цикла. Экспортируется из barrel, отдельного AI.md не имеет (описан
156
+ здесь).
157
+ - `OverlayMask` (`Overlay.Mask`) — кликабельный фон.
158
+ - `OverlayPanel` (`Overlay.Panel`) — выезжающая панель.
159
+ - `LightBox`, `TopOverlay` — построены поверх механики оверлея.
160
+ - `ModalWindow` — альтернатива для центрированных модальных окон.
171
161
 
172
- - Каждое направление — свой `translate` (100% начальное, 0 открытое).
173
- - **Длительность 300ms** — захардкожена.
174
- - **`box-shadow`** — захардкожен (`rgba(0,0,0,0.14)` 13px-blur 17px), не из токенов.
162
+ ---
175
163
 
176
- ### Mask — отдельный компонент, не часть Panel
164
+ ## Stories
177
165
 
178
- - Потребитель сам решает, нужна ли маска и как она реагирует на клик. Это даёт гибкость: можно сделать non-modal overlay (без затемнения).
166
+ Основные истории: `stories/Overlay/Overlay.stories.tsx`
167
+ Файлы примеров: `stories/Overlay/examples/`
179
168
 
180
- ### Render-prop, не Context
169
+ | Story | Example file | Что демонстрирует |
170
+ |---|---|---|
171
+ | `Playground` | `Playground.tsx` | Интерактивный контроль `direction` / `fixed` / `opened`, маска и кнопки открытия/закрытия |
172
+ | `Default` | `Default.tsx` | Минимальный оверлей (RIGHT, не fixed) |
173
+ | `Directions` | `Directions.tsx` | Все 4 направления выезда панели |
174
+ | `Fixed` | `Fixed.tsx` | Fixed-оверлей на всю страницу |
175
+ | `VisualTests` | `VisualTests.tsx` | Скриншот-регрессия: `play` открывает панели всех направлений |
181
176
 
182
- - API через render-prop, а не Context, чтобы дочерние Mask/Panel могли быть переданы по-разному в каждом случае.
183
- - Минус: верстать вложенные компоненты сложнее (handler'ы внутри замыкания).
177
+ Visual baseline для `components-overlay--visual-tests` генерируется только в CI
178
+ (Linux) через `GitHub Actions → Update Visual Snapshots`.
184
179
 
185
180
  ---
186
181
 
187
- ## Инварианты
182
+ ## История изменений
188
183
 
189
- - **`children` — render-prop** (`(props) => ReactElement`), не ReactNode. Изменение API — breaking.
190
- - **`direction` default `RIGHT`** в `OverlayBase`, в `Overlay` — без default'а (пробрасывается как-есть).
191
- - **`closing`/`opening` сбрасываются через `onTransitionEnd`** на `OverlayPanel` — если потребитель не использует `OverlayPanel` или ломает transition, lifecycle зависнет.
192
- - **`onClosing`/`onOpening` вызываются дважды** на каждое открытие/закрытие. Делай идемпотентным.
193
- - **Двойной `closing` state** (Overlay + OverlayBase) — не упрощать без миграции CSS.
194
- - **`fixed` — `position: fixed`** на корневой `<div>`, иначе `absolute`. Не работает в transformed-родителях (фундаментальный CSS).
195
- - **300ms transition** — захардкожена, не настраивается.
196
- - **CSS-переменная `--triplex-next-Overlay-Panel_Background`** — публичный токен.
197
- - **Mask и Panel — `forwardRef`**, Overlay/OverlayBase — `FC`.
198
- - **Overlay slots — `Object.assign`-style** (`Overlay.Mask = OverlayMask`) — но через property assignment.
184
+ | Дата | Изменение |
185
+ |---|---|
186
+ | 2026-06-17 | Создан документ. `Overlay` переведён на `forwardRef` (ref → корневой `div`, аддитивно, release notes 1.34.0). Дедуплицирован флаг `closing` (единый источник — `OverlayBase`). Codestyle/JSDoc cleanup в 4 файлах. Добавлены 4 unit-тест-файла. Исправлен двойной вызов `onClosing`/`onOpening` за переход — теперь ровно один раз (закреплено `toHaveBeenCalledTimes(1)`). |
199
187
 
200
188
  ---
201
189
 
202
- ## Accessibility
190
+ ## Примеры использования
203
191
 
204
- - **Нет встроенного focus management / focus trap** — потребитель должен реализовать сам (или использовать SideOverlay/ModalWindow поверх).
205
- - **Нет ESC-обработчика** — закрытие зависит от `setOpened` через клик по Mask или явный close-button.
206
- - **Нет `role="dialog"` / `aria-modal`** — overlay семантически нейтрален. Потребитель должен добавить через `...htmlDivAttributes`.
207
- - `visibility: hidden` в closed-state — корректно убирает focusable-элементы из tab-последовательности.
208
- - Mask — `<div>`, не интерактивный по умолчанию; клик-обработчик потребитель добавляет сам.
192
+ ### Default
209
193
 
210
- ---
194
+ `stories/Overlay/examples/Default.tsx`
211
195
 
212
- ## Дизайн-токены
213
-
214
- - `--triplex-next-Overlay-Panel_Background` — фон панели.
215
- - `box-shadow` — захардкожен, не из токенов (тех-долг).
196
+ ```tsx
197
+ import React, { useState } from "react";
198
+ import { Overlay, EOverlayDirection } from "@sberbusiness/triplex-next";
199
+
200
+ export const Default = () => {
201
+ const [opened, setOpened] = useState(false);
202
+
203
+ return (
204
+ <div
205
+ style={{
206
+ position: "relative",
207
+ width: 320,
208
+ height: 200,
209
+ border: "1px dashed #D0D4D9",
210
+ padding: 12,
211
+ }}
212
+ >
213
+ <button type="button" onClick={() => setOpened(true)} style={{ padding: "6px 12px" }}>
214
+ Открыть оверлей
215
+ </button>
216
+ <Overlay direction={EOverlayDirection.RIGHT} opened={opened} setOpened={setOpened}>
217
+ {(provideProps) => (
218
+ <>
219
+ <Overlay.Mask opened={opened} onClick={() => setOpened(false)} aria-label="Закрыть оверлей" />
220
+ <Overlay.Panel
221
+ {...provideProps}
222
+ direction={EOverlayDirection.RIGHT}
223
+ aria-label="Панель оверлея"
224
+ >
225
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
226
+ <div>Содержимое оверлея</div>
227
+ <button type="button" onClick={() => setOpened(false)}>
228
+ Закрыть
229
+ </button>
230
+ </div>
231
+ </Overlay.Panel>
232
+ </>
233
+ )}
234
+ </Overlay>
235
+ </div>
236
+ );
237
+ };
238
+ ```
216
239
 
217
- ---
240
+ ### Directions
218
241
 
219
- ## Связанные компоненты
242
+ `stories/Overlay/examples/Directions.tsx`
220
243
 
221
- - `SideOverlay` — высокоуровневая обёртка (Overlay + Mask + ESC + focus + контент).
222
- - `ModalWindow` — модал на отдельном механизме (Portal + CSSTransition).
223
- - `LightBox` — full-screen viewer на отдельном механизме.
244
+ ```tsx
245
+ import React, { useState } from "react";
246
+ import { Overlay, EOverlayDirection } from "@sberbusiness/triplex-next";
224
247
 
225
- ---
248
+ interface IDirectionItemProps {
249
+ direction: EOverlayDirection;
250
+ title: string;
251
+ }
226
252
 
227
- ## Stories
253
+ const DirectionItem = ({ direction, title }: IDirectionItemProps) => {
254
+ const [opened, setOpened] = useState(false);
255
+
256
+ return (
257
+ <div
258
+ style={{
259
+ position: "relative",
260
+ width: 320,
261
+ height: 200,
262
+ border: "1px dashed #D0D4D9",
263
+ padding: 12,
264
+ }}
265
+ >
266
+ <div style={{ marginBottom: 8 }}>{title}</div>
267
+ <button type="button" onClick={() => setOpened(true)} style={{ padding: "6px 12px" }}>
268
+ Открыть
269
+ </button>
270
+ <Overlay direction={direction} opened={opened} setOpened={setOpened}>
271
+ {(provideProps) => (
272
+ <>
273
+ <Overlay.Mask opened={opened} onClick={() => setOpened(false)} aria-label="Закрыть оверлей" />
274
+ <Overlay.Panel {...provideProps} direction={direction} aria-label="Панель оверлея">
275
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
276
+ <div>Панель ({title})</div>
277
+ <button type="button" onClick={() => setOpened(false)}>
278
+ Закрыть
279
+ </button>
280
+ </div>
281
+ </Overlay.Panel>
282
+ </>
283
+ )}
284
+ </Overlay>
285
+ </div>
286
+ );
287
+ };
288
+
289
+ export const Directions = () => (
290
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 16 }}>
291
+ <DirectionItem direction={EOverlayDirection.RIGHT} title="RIGHT" />
292
+ <DirectionItem direction={EOverlayDirection.LEFT} title="LEFT" />
293
+ <DirectionItem direction={EOverlayDirection.TOP} title="TOP" />
294
+ <DirectionItem direction={EOverlayDirection.BOTTOM} title="BOTTOM" />
295
+ </div>
296
+ );
297
+ ```
228
298
 
229
- `stories/Overlay/Overlay.stories.tsx`
299
+ ### Fixed
230
300
 
231
- ---
301
+ `stories/Overlay/examples/Fixed.tsx`
232
302
 
233
- ## История изменений
303
+ ```tsx
304
+ import React, { useState } from "react";
305
+ import { Overlay, EOverlayDirection } from "@sberbusiness/triplex-next";
306
+
307
+ export const Fixed = () => {
308
+ const [opened, setOpened] = useState(false);
309
+
310
+ return (
311
+ <div>
312
+ <button type="button" onClick={() => setOpened(true)} style={{ padding: "6px 12px" }}>
313
+ Открыть fixed оверлей
314
+ </button>
315
+ <Overlay fixed direction={EOverlayDirection.RIGHT} opened={opened} setOpened={setOpened}>
316
+ {(provideProps) => (
317
+ <>
318
+ <Overlay.Mask opened={opened} onClick={() => setOpened(false)} aria-label="Закрыть оверлей" />
319
+ <Overlay.Panel
320
+ {...provideProps}
321
+ direction={EOverlayDirection.RIGHT}
322
+ aria-label="Панель оверлея"
323
+ >
324
+ <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
325
+ <div>Оверлей на всю страницу (fixed)</div>
326
+ <button type="button" onClick={() => setOpened(false)}>
327
+ Закрыть
328
+ </button>
329
+ </div>
330
+ </Overlay.Panel>
331
+ </>
332
+ )}
333
+ </Overlay>
334
+ </div>
335
+ );
336
+ };
337
+ ```
234
338
 
235
- | Дата | Изменение |
236
- |---|---|
237
- | 2026-04-18 | Создан документ |