@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.
Files changed (140) hide show
  1. package/README.md +124 -0
  2. package/bundle/.gitkeep +0 -0
  3. package/bundle/components/AbstractTree.md +198 -0
  4. package/bundle/components/AccordionBase.md +227 -0
  5. package/bundle/components/Alert.md +317 -0
  6. package/bundle/components/Amount.md +225 -0
  7. package/bundle/components/AmountField.md +289 -0
  8. package/bundle/components/Avatar.md +209 -0
  9. package/bundle/components/Badge.md +277 -0
  10. package/bundle/components/Body.md +167 -0
  11. package/bundle/components/Button.md +230 -0
  12. package/bundle/components/ButtonDropdown.md +159 -0
  13. package/bundle/components/ButtonIcon.md +122 -0
  14. package/bundle/components/Calendar.md +445 -0
  15. package/bundle/components/Card.md +374 -0
  16. package/bundle/components/CarouselExtended.md +250 -0
  17. package/bundle/components/Checkbox.md +126 -0
  18. package/bundle/components/CheckboxTree.md +280 -0
  19. package/bundle/components/CheckboxTreeExtended.md +321 -0
  20. package/bundle/components/CheckboxXGroup.md +68 -0
  21. package/bundle/components/CheckboxYGroup.md +67 -0
  22. package/bundle/components/Chip.md +404 -0
  23. package/bundle/components/ChipGroup.md +179 -0
  24. package/bundle/components/Col.md +221 -0
  25. package/bundle/components/CollapsableTree.md +255 -0
  26. package/bundle/components/Confirm.md +343 -0
  27. package/bundle/components/DateField.md +371 -0
  28. package/bundle/components/DatePickerExtended.md +342 -0
  29. package/bundle/components/DateRange.md +275 -0
  30. package/bundle/components/DesignTokens.md +385 -0
  31. package/bundle/components/Divider.md +196 -0
  32. package/bundle/components/DocumentNumberEdit.md +280 -0
  33. package/bundle/components/Dropdown.md +433 -0
  34. package/bundle/components/Ellipsis.md +208 -0
  35. package/bundle/components/EmptyView.md +99 -0
  36. package/bundle/components/ExpandAnimation.md +281 -0
  37. package/bundle/components/Footer.md +339 -0
  38. package/bundle/components/FormField.md +326 -0
  39. package/bundle/components/FormGroup.md +99 -0
  40. package/bundle/components/Gap.md +113 -0
  41. package/bundle/components/Header.md +280 -0
  42. package/bundle/components/HelpBox.md +154 -0
  43. package/bundle/components/IconWrapper.md +145 -0
  44. package/bundle/components/Island.md +197 -0
  45. package/bundle/components/IslandAccordion.md +230 -0
  46. package/bundle/components/IslandWidget.md +233 -0
  47. package/bundle/components/KeyDownListener.md +157 -0
  48. package/bundle/components/LightBox.md +322 -0
  49. package/bundle/components/Link.md +161 -0
  50. package/bundle/components/List.md +247 -0
  51. package/bundle/components/ListMaster.md +204 -0
  52. package/bundle/components/Loader.md +161 -0
  53. package/bundle/components/LoaderScreen.md +134 -0
  54. package/bundle/components/Marker.md +127 -0
  55. package/bundle/components/MarkerStatus.md +148 -0
  56. package/bundle/components/MediaWidth.md +169 -0
  57. package/bundle/components/MobileView.md +120 -0
  58. package/bundle/components/ModalWindow.md +308 -0
  59. package/bundle/components/MonthYearField.md +168 -0
  60. package/bundle/components/MultiselectField.md +213 -0
  61. package/bundle/components/Notification.md +233 -0
  62. package/bundle/components/NumberField.md +178 -0
  63. package/bundle/components/OrderedList.md +169 -0
  64. package/bundle/components/Overlay.md +237 -0
  65. package/bundle/components/Page.md +246 -0
  66. package/bundle/components/Pagination.md +298 -0
  67. package/bundle/components/Portal.md +119 -0
  68. package/bundle/components/Radio.md +174 -0
  69. package/bundle/components/Row.md +125 -0
  70. package/bundle/components/SMSField.md +160 -0
  71. package/bundle/components/SegmentedControl.md +235 -0
  72. package/bundle/components/SelectExtendedField.md +322 -0
  73. package/bundle/components/SelectField.md +213 -0
  74. package/bundle/components/Skeleton.md +129 -0
  75. package/bundle/components/Slider.md +157 -0
  76. package/bundle/components/SliderExtended.md +210 -0
  77. package/bundle/components/SliderRange.md +160 -0
  78. package/bundle/components/SmallInput.md +101 -0
  79. package/bundle/components/Spoiler.md +121 -0
  80. package/bundle/components/StatusTracker.md +151 -0
  81. package/bundle/components/Step.md +121 -0
  82. package/bundle/components/Stepper.md +163 -0
  83. package/bundle/components/Suggest.md +160 -0
  84. package/bundle/components/SuggestField.md +157 -0
  85. package/bundle/components/SwipeableArea.md +144 -0
  86. package/bundle/components/Table.md +199 -0
  87. package/bundle/components/Tabs.md +152 -0
  88. package/bundle/components/TabsExtended.md +273 -0
  89. package/bundle/components/TabsLine.md +189 -0
  90. package/bundle/components/Tag.md +135 -0
  91. package/bundle/components/TagColor.md +121 -0
  92. package/bundle/components/TagGroup.md +100 -0
  93. package/bundle/components/TextField.md +152 -0
  94. package/bundle/components/TextareaField.md +124 -0
  95. package/bundle/components/ThemeProvider.md +181 -0
  96. package/bundle/components/Tooltip.md +254 -0
  97. package/bundle/components/TopOverlay.md +145 -0
  98. package/bundle/components/TreeView.md +224 -0
  99. package/bundle/components/Triggers.md +121 -0
  100. package/bundle/guides/codestyle.md +205 -0
  101. package/bundle/guides/commits.md +166 -0
  102. package/bundle/guides/context.md +277 -0
  103. package/bundle/guides/stories.md +618 -0
  104. package/bundle/guides/template.md +154 -0
  105. package/bundle/guides/tests.md +301 -0
  106. package/bundle/icons.json +4156 -0
  107. package/bundle/manifest.json +796 -0
  108. package/bundle/release-notes/1.1.0.mdx +26 -0
  109. package/bundle/release-notes/1.1.1.mdx +14 -0
  110. package/bundle/release-notes/1.10.0.mdx +43 -0
  111. package/bundle/release-notes/1.11.0.mdx +19 -0
  112. package/bundle/release-notes/1.12.0.mdx +21 -0
  113. package/bundle/release-notes/1.13.0.mdx +43 -0
  114. package/bundle/release-notes/1.14.0.mdx +29 -0
  115. package/bundle/release-notes/1.15.0.mdx +56 -0
  116. package/bundle/release-notes/1.16.0.mdx +55 -0
  117. package/bundle/release-notes/1.17.0.mdx +15 -0
  118. package/bundle/release-notes/1.18.0.mdx +24 -0
  119. package/bundle/release-notes/1.19.0.mdx +48 -0
  120. package/bundle/release-notes/1.19.1.mdx +9 -0
  121. package/bundle/release-notes/1.2.0.mdx +80 -0
  122. package/bundle/release-notes/1.20.0.mdx +48 -0
  123. package/bundle/release-notes/1.21.0.mdx +66 -0
  124. package/bundle/release-notes/1.22.0.mdx +75 -0
  125. package/bundle/release-notes/1.23.0.mdx +50 -0
  126. package/bundle/release-notes/1.24.0.mdx +59 -0
  127. package/bundle/release-notes/1.25.0.mdx +52 -0
  128. package/bundle/release-notes/1.26.0.mdx +11 -0
  129. package/bundle/release-notes/1.3.0.mdx +21 -0
  130. package/bundle/release-notes/1.4.0.mdx +37 -0
  131. package/bundle/release-notes/1.5.0.mdx +24 -0
  132. package/bundle/release-notes/1.6.0.mdx +37 -0
  133. package/bundle/release-notes/1.6.1.mdx +11 -0
  134. package/bundle/release-notes/1.7.0.mdx +29 -0
  135. package/bundle/release-notes/1.8.0.mdx +38 -0
  136. package/bundle/release-notes/1.9.0.mdx +28 -0
  137. package/dist/index.d.ts +2 -0
  138. package/dist/index.js +324 -0
  139. package/dist/index.js.map +1 -0
  140. package/package.json +51 -0
@@ -0,0 +1,181 @@
1
+ ---
2
+ component: ThemeProvider
3
+ category: Infrastructure
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [DesignTokens]
7
+ tokens: []
8
+ stories: ""
9
+ version: "1.0"
10
+ ---
11
+
12
+ # ThemeProvider
13
+
14
+ ## Назначение
15
+
16
+ Провайдер темы и дизайн-токенов: задаёт область видимости CSS-переменных
17
+ через scoped className на HTML-элементе и подставляет токены темы (LIGHT/
18
+ DARK) + опциональные пользовательские override'ы. Токены доступны через
19
+ контекст (`useToken`).
20
+
21
+ Используй когда: нужно применить тему ко всему приложению или к
22
+ изолированному поддереву (например, тёмная панель внутри светлого
23
+ интерфейса). Вне `ThemeProvider` работает дефолтное `LIGHT` оформление.
24
+
25
+ ---
26
+
27
+ ## Файловая структура
28
+
29
+ ```text
30
+ src/components/ThemeProvider/
31
+ ├── ThemeProvider.tsx # FC<IThemeProviderProps>; updateCSS/removeCSS + ThemeProviderView
32
+ ├── ThemeProviderContext.ts # IThemeProviderContext + контекст с дефолтом LIGHT
33
+ ├── ETriplexNextTheme.ts # enum LIGHT/DARK
34
+ ├── useToken.ts # хук-обёртка над контекстом
35
+ ├── components/
36
+ │ └── ThemeProviderView.tsx # классname на scopeRef + Context.Provider с merged-токенами
37
+ ├── __tests__/
38
+ └── index.ts
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Публичный API
44
+
45
+ ### `IThemeProviderProps`
46
+
47
+ | Prop | Тип | Default | Описание |
48
+ |---|---|---|---|
49
+ | `children` | `ReactNode` | — | Дерево, использующее тему. |
50
+ | `scopeRef` | `RefObject<HTMLElement>` | — | **Обязателен**. Ref на DOM-элемент, к которому добавится `scopeClassName` (обычно `html`/`body`/корневой div). |
51
+ | `scopeClassName?` | `string` | `triplex-next-theme-{n}` (uniqueId) | Класс для области видимости. Если не передан — генерируется автоматически. |
52
+ | `theme?` | `ETriplexNextTheme` | `LIGHT` | Тема. |
53
+ | `tokens?` | `TDesignTokensPartial` | `{}` | Override отдельных токенов. |
54
+
55
+ ### `ETriplexNextTheme`
56
+
57
+ ```ts
58
+ enum ETriplexNextTheme {
59
+ LIGHT = "light",
60
+ DARK = "dark",
61
+ }
62
+ ```
63
+
64
+ ### `IThemeProviderContext`
65
+
66
+ ```ts
67
+ {
68
+ scopeClassName: string;
69
+ theme: ETriplexNextTheme;
70
+ tokens: TDesignTokens; // полные токены (Core + Components, по теме + override)
71
+ }
72
+ ```
73
+
74
+ ### `useToken()`
75
+
76
+ ```ts
77
+ () => { scopeClassName: string; theme: ETriplexNextTheme; tokens: TDesignTokens }
78
+ ```
79
+
80
+ Чтение текущей темы и токенов из контекста.
81
+
82
+ ---
83
+
84
+ ## Поведение
85
+
86
+ ### Внедрение CSS
87
+
88
+ `useLayoutEffect` (`ThemeProvider.tsx`):
89
+ 1. `DesignTokenUtils.getStyle(theme, tokens)` → строка `--var-name: value;`.
90
+ 2. `updateCSS(`.${scopeCssClassName} {…}`, ключ `triplex-next-dynamic-tokens-${scopeCssClassName}`)` — вставляет/обновляет `<style>` тег (через `rc-util/Dom/dynamicCSS`).
91
+ 3. SSR: `canUseDom() === false` → `console.log` warning, без вставки.
92
+
93
+ При размонтировании — `removeCSS` по тому же ключу.
94
+
95
+ ### Применение области видимости (`ThemeProviderView`)
96
+
97
+ `useEffect` на `[scopeClassName, scopeRef]`:
98
+ - Добавляет `scopeClassName` в `scopeRef.current.classList`.
99
+ - При cleanup — удаляет `prevScopeClassName.current` (хранит предыдущий класс для корректного removal).
100
+
101
+ ### Сборка токенов в Context
102
+
103
+ `useMemo`:
104
+ ```ts
105
+ defaultsDeep(
106
+ {},
107
+ tokensProps, // 1. user override
108
+ theme === LIGHT ? DesignTokensCore : DesignTokensCoreThemeDark,
109
+ theme === LIGHT ? DesignTokensComponents : DesignTokensComponentsThemeDark,
110
+ );
111
+ ```
112
+
113
+ **Порядок важен** — `defaultsDeep` НЕ перезаписывает уже определённые ключи,
114
+ поэтому первые источники имеют приоритет (user > Core > Components).
115
+
116
+ ---
117
+
118
+ ## Инварианты
119
+
120
+ - **`FC, не forwardRef`** — `ThemeProvider` ref не пробрасывает; ref на DOM передаётся через `scopeRef`.
121
+ - **`scopeRef` обязателен** — без него `classList.add` не выполнится → стили не применятся.
122
+ - **`scopeClassName` авто-генерируется** через `uniqueId("triplex-next-theme-")`, если не передан. Стабилен между рендерами (memo по `[scopeClassName]`).
123
+ - **`useLayoutEffect` для вставки CSS** — критично, чтобы стили применились ДО первого paint'а детей. Не менять на `useEffect`.
124
+ - **Cleanup `removeCSS`** при размонтировании — иначе утечки `<style>` тегов в `<head>`.
125
+ - **Порядок `defaultsDeep` зафиксирован комментарием** — `tokensProps` идёт первым (приоритет), не менять без обсуждения.
126
+ - **`prevScopeClassName: useRef`** — нужен для удаления старого класса при изменении `scopeClassName` (обычный сценарий — не возникает, но защита от смены через props).
127
+ - **SSR не поддержан** — фоллбек на `console.log`. Реальная тема применится только после hydration на клиенте.
128
+ - **Дефолтный контекст содержит `LIGHT` токены** (`DesignTokensCore + DesignTokensComponents`), не пустой объект. Компоненты вне `ThemeProvider` получают дефолтную светлую тему через `useToken`.
129
+ - **Контекст имеет полные токены `TDesignTokens`**, а не `Partial` — `useToken` гарантированно возвращает все ключи.
130
+
131
+ ---
132
+
133
+ ## Использование
134
+
135
+ ```tsx
136
+ const App = () => {
137
+ const rootRef = useRef<HTMLDivElement>(null);
138
+
139
+ return (
140
+ <div ref={rootRef}>
141
+ <ThemeProvider scopeRef={rootRef} theme={ETriplexNextTheme.DARK}>
142
+ <YourApp />
143
+ </ThemeProvider>
144
+ </div>
145
+ );
146
+ };
147
+
148
+ // Чтение токенов в компоненте:
149
+ const { tokens, theme } = useToken();
150
+ ```
151
+
152
+ Несколько `ThemeProvider` могут быть вложены — внутренний переопределяет
153
+ внешний внутри своего scope.
154
+
155
+ ---
156
+
157
+ ## Accessibility
158
+
159
+ - ARIA не задействована — это инфраструктурный компонент.
160
+ - При смене темы для контрастности и читаемости — обеспечивается дизайн-токенами; компонент только применяет их.
161
+
162
+ ---
163
+
164
+ ## Связанные компоненты
165
+
166
+ - `DesignTokens` (`DesignTokensCore`, `DesignTokensComponents`, `*ThemeDark` варианты, `DesignTokenUtils`) — источники значений.
167
+ - Все компоненты дизайн-системы — потребители токенов через CSS-переменные `--triplex-next-*`.
168
+
169
+ ---
170
+
171
+ ## Stories
172
+
173
+ Отдельных stories нет — оборачивает все остальные компоненты в Storybook на уровне preview.
174
+
175
+ ---
176
+
177
+ ## История изменений
178
+
179
+ | Дата | Изменение |
180
+ |---|---|
181
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,254 @@
1
+ ---
2
+ component: Tooltip
3
+ category: Overlay
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [Dropdown, MobileView, MediaWidth]
7
+ tokens: []
8
+ stories: stories/Tooltip/Tooltip.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # Tooltip
13
+
14
+ ## Назначение
15
+
16
+ Всплывающая подсказка с автоматическим позиционированием
17
+ (`above`/`below`/`right`/`left`) и адаптивным переключением desktop/mobile.
18
+ Контент компонуется через слоты: `Target` (триггер) + `Body` (контент) +
19
+ опционально `Link`, `XButton` (закрыть), `MobileHeader`. Управление —
20
+ hover или click.
21
+
22
+ Используй когда: нужна подсказка возле элемента (label-описание, ошибка,
23
+ информация). Для модальных диалогов — `Modal`. Для меню действий — `Dropdown`.
24
+
25
+ ---
26
+
27
+ ## Файловая структура
28
+
29
+ ```text
30
+ src/components/Tooltip/
31
+ ├── Tooltip.tsx # FC + Composition; MobileView switcher; Provider
32
+ ├── TootlipContext.ts # ITooltipContext (опечатка имени файла зафиксирована)
33
+ ├── enums.ts # ETooltipSize, ETooltipPreferPlace, ETooltipAlign + внутренние enum'ы позиционирования
34
+ ├── types.ts # все интерфейсы
35
+ ├── components/
36
+ │ ├── common/
37
+ │ │ ├── TooltipTarget.tsx # клонирование child'а с onClick/onKeyDown
38
+ │ │ ├── TooltipBody.tsx # forwardRef<HTMLDivElement>; MobileView для Text-обёртки
39
+ │ │ ├── TooltipLink.tsx
40
+ │ │ └── TooltipXButton.tsx # children: never
41
+ │ ├── desktop/
42
+ │ │ ├── TooltipDesktop.tsx
43
+ │ │ └── components/ # позиционирование, портал
44
+ │ └── mobile/
45
+ │ ├── TooltipMobile.tsx
46
+ │ └── components/TooltipMobileHeader.tsx
47
+ ├── utils/
48
+ │ ├── Positioning.ts # геометрия для desktop размещения
49
+ │ └── useTooltipTheme.ts # инжект темы в renderContainer
50
+ ├── styles/
51
+ └── index.ts
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Композиция
57
+
58
+ ```tsx
59
+ <Tooltip
60
+ targetRef={btnRef}
61
+ size={ETooltipSize.LG}
62
+ toggleType="hover"
63
+ preferPlace={ETooltipPreferPlace.ABOVE}
64
+ isOpen={open}
65
+ toggle={setOpen}
66
+ >
67
+ <Tooltip.Target>
68
+ <button ref={btnRef}>?</button>
69
+ </Tooltip.Target>
70
+ <Tooltip.Body>Подсказка</Tooltip.Body>
71
+ <Tooltip.Link href="/help">Подробнее</Tooltip.Link>
72
+ <Tooltip.XButton aria-label="Закрыть" />
73
+ <Tooltip.MobileHeader>Заголовок</Tooltip.MobileHeader>
74
+ </Tooltip>
75
+ ```
76
+
77
+ Все слоты — статические свойства `Tooltip.X = X`. Дети распознаются по
78
+ типу через `React.Children.map` (см. `getChildrenElements`); порядок
79
+ расположения в JSX неважен.
80
+
81
+ ---
82
+
83
+ ## Публичный API
84
+
85
+ ### `ITooltipProps`
86
+
87
+ ```ts
88
+ extends HTMLAttributes<HTMLDivElement>
89
+ ```
90
+
91
+ | Prop | Тип | Default | Описание |
92
+ |---|---|---|---|
93
+ | `size` | `ETooltipSize` (`SM` \| `LG`) | — | **Обязателен**. |
94
+ | `targetRef` | `MutableRefObject<HTMLElement \| null>` | — | **Обязателен**. Ref на якорный элемент (используется для расчёта позиции). |
95
+ | `toggleType?` | `"click" \| "hover"` | — | Способ открытия. Если не передан — Tooltip управляется только программно через `isOpen`/`toggle`. |
96
+ | `preferPlace?` | `ETooltipPreferPlace` (`ABOVE`/`BELOW`/`LEFT`/`RIGHT`) | — | Предпочтительная сторона. Если не помещается — flip автоматически. |
97
+ | `alignTip?` | `ETooltipAlign` (`START`/`CENTER`/`END`) | — | Выравнивание указателя относительно target'а. |
98
+ | `renderContainer?` | `Element` | `document.body` | Контейнер для портала. На mobile с включённой адаптивностью — игнорируется (всегда `document.body`). |
99
+ | `disableAdaptiveMode?` | `boolean` | `false` | Отключить переключение на mobile-вариант. |
100
+ | `isOpen?` | `boolean` | — | Контролируемое открытие. Если не передан — внутренний `openState`. |
101
+ | `toggle?` | `(open: boolean) => void` | — | Колбэк изменения. |
102
+ | `onShow?` | `(node: HTMLDivElement) => void` | — | После появления tooltip-DOM. |
103
+ | `children` | `ReactNode` | — | Слоты `Tooltip.*`. |
104
+
105
+ ### Слоты
106
+
107
+ #### `Tooltip.Target`
108
+
109
+ ```ts
110
+ { children: ReactElement } // ровно один React-элемент
111
+ ```
112
+
113
+ Клонирует child через `React.cloneElement`, добавляя `onClick` и `onKeyDown`:
114
+ - `onClick` (если `toggleType === "click"` или `hover` + не висим в hovered-состоянии): `setTooltipOpen(!tooltipOpen)`.
115
+ - `onKeyDown TAB` при открытом — закрывает.
116
+ - Существующие хендлеры на child'е сохраняются (вызываются после).
117
+
118
+ #### `Tooltip.Body`
119
+
120
+ ```ts
121
+ extends HTMLAttributes<HTMLDivElement>
122
+ ```
123
+
124
+ `forwardRef<HTMLDivElement>`. На desktop — `<div>`, на mobile — `<Text tag="div" size=B3 line=NORMAL>` (через `MobileView`).
125
+
126
+ #### `Tooltip.Link`
127
+
128
+ ```ts
129
+ extends AnchorHTMLAttributes<HTMLAnchorElement>
130
+ ```
131
+
132
+ Ссылка внутри tooltip'а.
133
+
134
+ #### `Tooltip.XButton`
135
+
136
+ ```ts
137
+ extends ButtonHTMLAttributes<HTMLButtonElement>
138
+ { children: never }
139
+ ```
140
+
141
+ Кнопка закрытия (без своего content'а — рендерится X-иконка).
142
+
143
+ #### `Tooltip.MobileHeader`
144
+
145
+ ```ts
146
+ extends Omit<IDropdownMobileHeaderProps, "closeButton">
147
+ { controlButtons?: ReactNode }
148
+ ```
149
+
150
+ Заголовок мобильного полноэкранного варианта.
151
+
152
+ ### Enums
153
+
154
+ - `ETooltipSize`: `SM` | `LG`
155
+ - `ETooltipPreferPlace`: `ABOVE` | `BELOW` | `RIGHT` | `LEFT`
156
+ - `ETooltipAlign`: `START` | `CENTER` | `END`
157
+ - `ETooltipDirection`: `UP` | `DOWN` | `LEFT` | `RIGHT` (для указателя)
158
+
159
+ Внутренние enum'ы (`ETooltipAxesType`, `ETooltipFlowTypes`, `ETooltipStartCoordinates`, `ETooltipEndCoordinates`, `ETooltipSizeParameter`, `ETooltipTypeName`) — экспортированы, но используются в основном `Positioning.ts`.
160
+
161
+ ---
162
+
163
+ ## Контекст (`TooltipContext`)
164
+
165
+ ```ts
166
+ {
167
+ elements: ITooltipElements; // распознанные слоты
168
+ tooltipOpen: boolean;
169
+ setTooltipOpen(open): void;
170
+ targetHoveredRef: MutableRefObject<boolean>;
171
+ toggleType?: TTooltipToggleType;
172
+ }
173
+ ```
174
+
175
+ `elements.body/link/closeButton/mobileHeader/target` — `null` или `ReactElement`.
176
+ `getChildrenElements` распознаёт child'ов по `child.type === TooltipTarget` и т.п.
177
+
178
+ ---
179
+
180
+ ## Поведение
181
+
182
+ ### Адаптивность
183
+
184
+ - `useMatchMedia(max-width: SM_MAX)` — определяет mobile.
185
+ - `disableAdaptiveMode === true` → всегда desktop.
186
+ - Иначе — `<MobileView fallback={Desktop}>{Mobile}</MobileView>`.
187
+
188
+ ### Контролируемое vs неконтролируемое
189
+
190
+ - `isOpen` передан → контролируемое (внешний state). `setTooltipOpen` только зовёт `toggle?.(nextOpen)`, не пишет в `openState`.
191
+ - `isOpen` не передан → внутренний `openState`.
192
+ - Сброс `targetHoveredRef.current = false` при `openProp === false` (через `useEffect`) — чтобы повторный hover после программного закрытия снова открывал tooltip.
193
+
194
+ ### `useTooltipTheme(open, container)`
195
+
196
+ Инжектит тему (CSS-переменные) в `renderContainer` (или `document.body`),
197
+ чтобы tooltip-портал имел тот же стиль, что и текущий `ThemeProvider`.
198
+
199
+ ### Targeting
200
+
201
+ - `targetRef` обязателен — без него desktop-позиционирование не сработает.
202
+ - `toggleType: "hover"` — открывает на hover target'а; `"click"` — на клик.
203
+ - Без `toggleType` — tooltip управляется только через `isOpen`/`toggle` (полностью контролируемый сценарий).
204
+
205
+ ---
206
+
207
+ ## Инварианты
208
+
209
+ - **`Tooltip` — `FC` + composition** (`Tooltip.Target = TooltipTarget` и т.д.).
210
+ - **`TooltipTarget` — `FC`**, ожидает **ровно одного** child'а (`React.Children.only`); должен быть `ReactElement` (не string/number).
211
+ - **`TooltipBody` — `forwardRef<HTMLDivElement>`** — не убирать.
212
+ - **Слоты распознаются по типу** (`child.type === TooltipTarget`) — нельзя оборачивать слоты в Fragment'ы или HOC'и (потеряется тип).
213
+ - **`size` и `targetRef` обязательны** — проверять при использовании.
214
+ - **Файл контекста назван `TootlipContext.ts`** (опечатка) — менять имя считается breaking change для импортов.
215
+ - **`renderContainer` игнорируется в mobile + adaptiveMode** — всегда `document.body` (для полноэкранного листа).
216
+ - **`toggleType === "hover"` использует `targetHoveredRef`**, чтобы не дёргать toggle при движении внутри target'а; при `isOpen=false` извне ref сбрасывается.
217
+ - **На desktop body — `<div>`, на mobile — `<Text tag="div" size=B3>`** (через MobileView). Стили совпадают по className, но обёртка разная.
218
+ - **`XButton.children: never`** — иконка X встроена, не передавать content.
219
+ - **Все enum'ы экспортируются** — часть публичного API.
220
+
221
+ ---
222
+
223
+ ## Accessibility
224
+
225
+ - `Tooltip.Target` — потребитель сам ставит `aria-describedby`/`aria-haspopup` на child-элементе (компонент это не делает автоматически — TODO).
226
+ - TAB на target при открытом tooltip — закрывает (clean-up для tab-навигации).
227
+ - `XButton` — `<button>`, `aria-label` ставит потребитель (через `aria-label="Закрыть"`).
228
+ - Mobile-вариант — полноэкранный лист (управляется фокусом через `MobileHeader`/`closeButton`).
229
+ - На hover-tooltip'ах screen-reader пользователи не видят содержимое — для критичной информации использовать `role="status"` или дублировать в `aria-describedby`.
230
+
231
+ ---
232
+
233
+ ## Связанные компоненты
234
+
235
+ - `MobileView` / `useMatchMedia` — переключение desktop/mobile.
236
+ - `Dropdown` — для меню/списков (другая UX-семантика).
237
+ - `Typography.Text` — обёртка body на mobile.
238
+ - `ThemeProvider` (через `useTooltipTheme`) — наследование темы в портал.
239
+ - `IDropdownMobileHeaderProps` — родитель для `ITooltipMobileHeaderProps`.
240
+
241
+ ---
242
+
243
+ ## Stories
244
+
245
+ Основные истории: `stories/Tooltip/Tooltip.stories.tsx`
246
+ Примеры: `stories/Tooltip/examples/`
247
+
248
+ ---
249
+
250
+ ## История изменений
251
+
252
+ | Дата | Изменение |
253
+ |---|---|
254
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,145 @@
1
+ ---
2
+ component: TopOverlay
3
+ category: Overlay
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [Overlay, LightBox]
7
+ tokens: []
8
+ stories: stories/TopOverlay/TopOverlay.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # TopOverlay
13
+
14
+ ## Назначение
15
+
16
+ Оверлей, выезжающий из верха экрана: обёртка над `Overlay` с
17
+ `direction=TOP`, `Mask` + `Panel`, FocusTrap, и автокоррекцией top-позиции
18
+ при скролле родителя/`LightBox`-контейнера. Используется для системных
19
+ сообщений, временных панелей.
20
+
21
+ Используй когда: нужна верхняя shading-панель внутри `LightBox` или
22
+ прокручиваемого родителя, со встроенной фиксацией фокуса. Для общего
23
+ оверлея — `Overlay` напрямую.
24
+
25
+ ---
26
+
27
+ ## Файловая структура
28
+
29
+ ```text
30
+ src/components/TopOverlay/
31
+ ├── TopOverlay.tsx # FC<ITopOverlayProps>; FocusTrap + Overlay(direction=TOP)
32
+ ├── styles/TopOverlay.module.less
33
+ ├── __tests__/
34
+ └── index.ts
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Публичный API
40
+
41
+ ### `ITopOverlayProps`
42
+
43
+ ```ts
44
+ extends Pick<IOverlayProps, "opened" | "onOpen" | "onClose">
45
+ ```
46
+
47
+ | Prop | Тип | Default | Описание |
48
+ |---|---|---|---|
49
+ | `opened` | `boolean` | — | **Обязателен**. Контролируемое открытие. |
50
+ | `onOpen?` | `() => void` | — | Колбэк при открытии (вызывается из `handleOpen`, после `updateTopPosition`). |
51
+ | `onClose?` | `() => void` | — | Колбэк при закрытии (после анимации). |
52
+ | `focusTrapProps?` | `FocusTrapProps` | — | Пропсы для `focus-trap-react`. По умолчанию `allowOutsideClick: true, preventScroll: true`. |
53
+ | `children?` | `ReactNode` | — | Содержимое панели. |
54
+
55
+ ---
56
+
57
+ ## Поведение
58
+
59
+ ### Состояния
60
+
61
+ | Имя | Тип | Назначение |
62
+ |---|---|---|
63
+ | `closing` | `boolean` | Анимация закрытия в процессе (`opened` стал `false`, ещё не отработал). |
64
+ | `activeFocusTrap` | `boolean` | Включён ли FocusTrap (включается на open, отключается перед closing). |
65
+ | `overlayWrapperTopPosition` | `number \| string` | Top-смещение wrapper'а (0 по умолчанию). |
66
+ | `prevOpened` | `Ref<boolean>` | Для определения перехода `true → false` / `false → true`. |
67
+ | `overlayWrapperRef` | `Ref<HTMLDivElement>` | Для расчёта `getBoundingClientRect`. |
68
+
69
+ ### `updateTopPosition`
70
+
71
+ Вызывается в `handleOpen` и при `false → true`:
72
+ 1. Читает `--lightBox-screen-top` CSS-переменную из computed-style wrapper'а.
73
+ 2. Если `position.top < 0` (overlay выше viewport'а) — добавляет `Math.abs(position.top) + lightBoxTopPosition`.
74
+ 3. Иначе — вычитает `position.top - lightBoxTopPosition`.
75
+
76
+ Цель: компенсировать прокрутку родителя/`LightBox`'а так, чтобы overlay
77
+ встал у видимого верха.
78
+
79
+ ### Жизненный цикл
80
+
81
+ - `opened: false → true`: `useEffect` зовёт `updateTopPosition`. `Overlay.onOpen` → `handleOpen` (внутри: `updateTopPosition` ещё раз + `setActiveFocusTrap(true)` + `onOpen?.()`).
82
+ - `opened: true → false`: `setClosing(true)`. `Overlay.onClosing` (анимация началась) → `handleClosing` → `setActiveFocusTrap(false)`. `Overlay.onClose` (анимация завершилась) → `handleClose` → `setClosing(false)` + сброс `overlayWrapperTopPosition` + `onClose?.()`.
83
+
84
+ ### Структура
85
+
86
+ ```tsx
87
+ <FocusTrap active={activeFocusTrap} focusTrapOptions={{allowOutsideClick: true, preventScroll: true, ...}}>
88
+ <div className={topOverlayWrapper {opened, closing}} ref={...} style={{top: ...}}>
89
+ <Overlay direction={TOP} opened={opened} onOpen={handleOpen} onClose={handleClose} onClosing={handleClosing}>
90
+ {(overlayProps) => (
91
+ <>
92
+ <Overlay.Mask opened={overlayProps.opened} />
93
+ <Overlay.Panel {...overlayProps}>{children}</Overlay.Panel>
94
+ </>
95
+ )}
96
+ </Overlay>
97
+ </div>
98
+ </FocusTrap>
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Инварианты
104
+
105
+ - **`FC, не forwardRef`** — ref не пробрасывается.
106
+ - **`opened` контролируемый** — внутреннего state открытости нет. `setOpened` передаётся в `Overlay`, но это пустой no-op (`() => {}`); закрытие должно идти через внешний `opened={false}`.
107
+ - **`direction = EOverlayDirection.TOP`** — зашито; для других направлений использовать `Overlay` напрямую.
108
+ - **`FocusTrap` использует `focus-trap-react`** — `allowOutsideClick: true` и `preventScroll: true` зашиты как defaults; потребитель может переопределить через `focusTrapProps.focusTrapOptions`.
109
+ - **`activeFocusTrap` отключается ДО `onClose`** (на `onClosing`) — чтобы анимация уехала с уже разблокированным фокусом.
110
+ - **`updateTopPosition` читает `--lightBox-screen-top`** — связь с `LightBox`. Без `LightBox` переменная отсутствует → `0`.
111
+ - **`Overlay.Mask` и `Overlay.Panel` рендерятся внутри одного render-prop'а** — порядок Mask → Panel зашит.
112
+ - **Стили `.topOverlay`/`.topOverlayMask`/`.topOverlayPanel`/`.topOverlayWrapper` + `.opened`/`.closing`** — публичные CSS-классы (используются для управления visual transitions).
113
+ - **Без явной валидации `children`** — потребитель отвечает за содержимое.
114
+
115
+ ---
116
+
117
+ ## Accessibility
118
+
119
+ - `FocusTrap` — фокус заперт внутри overlay при `activeFocusTrap = true`.
120
+ - `allowOutsideClick: true` — клик вне overlay не блокируется (закрытие — на потребителе через external `opened`).
121
+ - `preventScroll: true` — focus-trap не вызывает scroll при initial focus.
122
+ - ARIA-роли (dialog/alertdialog) на overlay не выставляются — потребитель отвечает за разметку children (например, `<div role="dialog" aria-modal="true" aria-label>`).
123
+
124
+ ---
125
+
126
+ ## Связанные компоненты
127
+
128
+ - `Overlay` (`Overlay.Mask`, `Overlay.Panel`) — основа.
129
+ - `EOverlayDirection.TOP` — направление.
130
+ - `LightBox` — типичный родитель (через CSS-переменную `--lightBox-screen-top`).
131
+ - `focus-trap-react` (`FocusTrap`, `FocusTrapProps`) — npm-пакет для трапа фокуса.
132
+
133
+ ---
134
+
135
+ ## Stories
136
+
137
+ Основные истории: `stories/TopOverlay/TopOverlay.stories.tsx`
138
+
139
+ ---
140
+
141
+ ## История изменений
142
+
143
+ | Дата | Изменение |
144
+ |---|---|
145
+ | 2026-04-18 | Создан документ |