@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,213 @@
1
+ ---
2
+ component: MultiselectField
3
+ category: Form Controls
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [SelectExtendedField, SelectField, Dropdown, Checkbox, FormField]
7
+ tokens: []
8
+ stories: stories/MultiselectField/MultiselectField.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # MultiselectField
13
+
14
+ ## Назначение
15
+
16
+ Контейнер для **мульти-выбора** из списка: `<SelectExtendedField>` с
17
+ `<MultiselectField.Dropdown>` внутри. Сам компонент — **тонкая обёртка**,
18
+ прокидывающая `size` через `MultiselectFieldContext` к дочерним слотам
19
+ (Header/Content/Footer). Список опций (чекбоксы), кнопки применения,
20
+ заголовок с поиском — реализуются потребителем в Header/Content/Footer.
21
+
22
+ Используй когда: нужен выбор нескольких элементов с собственным dropdown'ом
23
+ и UI-контролами (поиск, "выбрать все", apply). Для одиночного выбора —
24
+ `SelectField`. Для более гибкого API — `SelectExtendedField` напрямую.
25
+
26
+ ---
27
+
28
+ ## Файловая структура
29
+
30
+ ```text
31
+ src/components/MultiselectField/
32
+ ├── MultiselectField.tsx # forwardRef, обёртка + Object.assign
33
+ ├── MultiselectFieldContext.ts # { size }
34
+ ├── index.ts # Barrel (только MultiselectField)
35
+ ├── components/
36
+ │ ├── MultiselectFieldDropdown.tsx # Dropdown + FocusTrap + Object.assign
37
+ │ ├── MultiselectFieldDropdownHeader.tsx # <div>
38
+ │ ├── MultiselectFieldDropdownContent.tsx # <div> + опц. LoaderScreen
39
+ │ ├── MultiselectFieldDropdownFooter.tsx # <div>
40
+ │ └── index.ts
41
+ └── styles/*.module.less
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Compound-структура
47
+
48
+ ```tsx
49
+ <MultiselectField
50
+ size={EComponentSize.MD}
51
+ opened={opened}
52
+ onOpenedChange={setOpened}
53
+ >
54
+ <MultiselectField.Target>
55
+ {/* Target — реэкспорт SelectExtendedFieldTarget */}
56
+ </MultiselectField.Target>
57
+
58
+ <MultiselectField.Dropdown>
59
+ <MultiselectField.Dropdown.Header>
60
+ {/* Поиск, "Выбрать все" */}
61
+ </MultiselectField.Dropdown.Header>
62
+
63
+ <MultiselectField.Dropdown.Content loading={loading}>
64
+ {items.map((it) => (
65
+ <Checkbox key={it.id} checked={...} onChange={...}>
66
+ {it.label}
67
+ </Checkbox>
68
+ ))}
69
+ </MultiselectField.Dropdown.Content>
70
+
71
+ <MultiselectField.Dropdown.Footer>
72
+ <Button>Применить</Button>
73
+ </MultiselectField.Dropdown.Footer>
74
+ </MultiselectField.Dropdown>
75
+ </MultiselectField>
76
+ ```
77
+
78
+ `MultiselectField.Target` **= реэкспорт** `SelectExtendedFieldTarget` (не собственный компонент). Используй как псевдоним.
79
+
80
+ ---
81
+
82
+ ## Варианты и props
83
+
84
+ ### MultiselectField — `IMultiselectFieldProps extends ISelectExtendedFieldProps`
85
+
86
+ | Prop | Тип | Default | Описание |
87
+ |---|---|---|---|
88
+ | `size` | `EComponentSize` | `MD` | Пишется в `MultiselectFieldContext` и пробрасывается в Dropdown. |
89
+ | `...ISelectExtendedFieldProps` | — | — | Всё поведение outer-контейнера (opened, onOpenedChange, targetRef, …) от SelectExtendedField. |
90
+
91
+ ### MultiselectField.Dropdown — `IMultiselectFieldDropdownProps extends IDropdownProps`
92
+
93
+ | Prop | Тип | Default | Описание |
94
+ |---|---|---|---|
95
+ | `focusTrapProps` | `FocusTrapProps` | — | Переопределение `focus-trap-react`. |
96
+ | `opened`, `targetRef`, `mobileViewProps`, `...IDropdownProps` | — | — | От `Dropdown`. |
97
+
98
+ - **`width` захардкожен `EDropdownWidth.MIN_TARGET`** — dropdown всегда минимум как target. Не переопределяется.
99
+ - **`size` берётся из `MultiselectFieldContext`**, не от prop'а.
100
+
101
+ ### MultiselectField.Dropdown.Header / Footer / Content — `HTMLAttributes<HTMLDivElement>`
102
+
103
+ - Header / Footer — простые `<div>`-слоты с собственной стилизацией (padding, border).
104
+ - Content — `<div tabIndex={-1}>` с `sizeToClassNameMap[size]` для подстройки (scroll height, padding). Имеет prop **`loading: boolean`** — при true показывает `LoaderScreen type="small"` поверх контента.
105
+
106
+ ### MultiselectFieldContext
107
+
108
+ ```ts
109
+ interface IMultiselectFieldContext { size: EComponentSize; }
110
+ ```
111
+
112
+ Публичная точка расширения: при создании кастомных элементов в Content можно читать `size` и адаптировать под него.
113
+
114
+ ---
115
+
116
+ ## Ключевые особенности реализации
117
+
118
+ ### `size` — через Context, не через prop на Dropdown
119
+
120
+ ```tsx
121
+ <MultiselectFieldContext.Provider value={{ size }}>
122
+ <SelectExtendedField {...props}>{children}</SelectExtendedField>
123
+ </MultiselectFieldContext.Provider>
124
+ ```
125
+
126
+ - Dropdown и Content читают `size` из контекста.
127
+ - **Dropdown переопределяет** `size` prop на Dropdown: `<Dropdown ... size={size} />`. То есть потребительский `size` на Dropdown **игнорируется** — всегда выигрывает context.
128
+
129
+ ### `FocusTrap` внутри Dropdown
130
+
131
+ ```tsx
132
+ <FocusTrap focusTrapOptions={{ clickOutsideDeactivates: true, preventScroll: true, ... }}>
133
+ <div role="presentation">{children}</div>
134
+ </FocusTrap>
135
+ ```
136
+
137
+ - `clickOutsideDeactivates: true` — клик вне dropdown'а деактивирует trap и закрывает (стандарт для popover/selects).
138
+ - Все потомки оборачиваются в `<div role="presentation">` — требование FocusTrap (нужен single wrapper-element).
139
+
140
+ ### `MultiselectField.Target = SelectExtendedFieldTarget`
141
+
142
+ ```tsx
143
+ Object.assign(..., { Dropdown, Target: SelectExtendedFieldTarget })
144
+ ```
145
+
146
+ - **Это не собственная реализация**, а пересвет. Потребитель видит `.Target` в типах, но фактически это SelectExtendedField's target.
147
+
148
+ ### Content `tabIndex={-1}`
149
+
150
+ Чтобы скролл внутри Content был фокусируемым мышью/колесиком (и при этом не участвовал в Tab-последовательности). Для переключения между чекбоксами — TAB идёт по интерактивным детям.
151
+
152
+ ### Loader — `LoaderScreen type="small"`
153
+
154
+ ```tsx
155
+ {loading && <LoaderScreen type="small" className={styles.loaderScreen} />}
156
+ ```
157
+
158
+ - Маленький оверлей (см. LoaderScreen-AI).
159
+ - Visibility — потребитель контролирует `loading` prop.
160
+
161
+ ---
162
+
163
+ ## Инварианты
164
+
165
+ - **`size` через `MultiselectFieldContext`** — публичная точка расширения; не заменять на prop-drilling без решения по обратной совместимости.
166
+ - **`MultiselectField.Target = SelectExtendedFieldTarget`** — псевдоним, не своя реализация. При рефакторинге SelectExtendedField — проверять, что Target совместим.
167
+ - **`EDropdownWidth.MIN_TARGET`** захардкожен — ширина dropdown'а всегда ≥ ширины target'а.
168
+ - **`FocusTrap clickOutsideDeactivates: true`** — контракт: клик вне → закрытие. При смене — потребуется явное `onOpenedChange`.
169
+ - **`MultiselectFieldContext.size` default `MD`** — не менять без breaking-проверки.
170
+ - **`Content.loading`** — контроль loader'а, типичное API.
171
+ - **ForwardRef** на корне `MultiselectField` и на `MultiselectFieldDropdown`.
172
+ - **Header/Footer/Content — `React.FC`** (без forwardRef).
173
+
174
+ ---
175
+
176
+ ## Accessibility
177
+
178
+ - FocusTrap удерживает фокус внутри dropdown'а → клавиатурная навигация между чекбоксами/кнопками корректна.
179
+ - `role="presentation"` на wrapper'е FocusTrap — правильно: обёртка не несёт семантики.
180
+ - **Нет `aria-multiselectable="true"` на dropdown'е** — потребителям для скринридеров имеет смысл добавить через `...rest` на Content / Dropdown.
181
+ - Чекбоксы внутри Content — стандартный `<Checkbox>` с нативной keyboard-семантикой.
182
+ - Target — `SelectExtendedFieldTarget` обеспечивает `aria-expanded` / `aria-haspopup="listbox"` (проверь в SelectExtendedField, если не — гэп).
183
+
184
+ ---
185
+
186
+ ## Дизайн-токены
187
+
188
+ Нет собственных. Размеры/padding/цвет от `Dropdown`, `SelectExtendedField`, `Checkbox`.
189
+
190
+ ---
191
+
192
+ ## Связанные компоненты
193
+
194
+ - `SelectExtendedField` / `SelectExtendedFieldTarget` — основа.
195
+ - `Dropdown` — popover-container.
196
+ - `Checkbox` — типичный элемент в Content.
197
+ - `LoaderScreen` — loader в Content.
198
+ - `focus-trap-react` — FocusTrap.
199
+
200
+ ---
201
+
202
+ ## Stories
203
+
204
+ `stories/MultiselectField/MultiselectField.stories.tsx`
205
+ Примеры: `stories/MultiselectField/examples/`
206
+
207
+ ---
208
+
209
+ ## История изменений
210
+
211
+ | Дата | Изменение |
212
+ |---|---|
213
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,233 @@
1
+ ---
2
+ component: Notification
3
+ category: Feedback
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [SideOverlay, Alert, UnorderedList, ButtonIcon, Typography]
7
+ tokens: []
8
+ stories: stories/Notification/Notification.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # Notification
13
+
14
+ ## Назначение
15
+
16
+ Карточка уведомления — `<div role="alertdialog">` с фиксированной
17
+ compound-структурой: `Icon` (опц.), `Body` (Header / Content / List /
18
+ Footer), `Close` (опц.), `Time` (опц.). Содержательная часть собирается
19
+ потребителем; компонент задаёт лэйаут, типографику и поведение close-by-
20
+ hover для side-overlay.
21
+
22
+ `NotificationGrouped` — визуальная группировка (стопка) — оборачивает
23
+ одну Notification и подкладывает два декоративных `<div>` снизу как
24
+ эффект «стопки карточек» (без логики управления списком).
25
+
26
+ Используй когда: показываешь информационное / системное сообщение
27
+ (в SideOverlay, Alert, отдельной странице, history-list).
28
+
29
+ ---
30
+
31
+ ## Файловая структура
32
+
33
+ ```text
34
+ src/components/Notification/
35
+ ├── Notification.tsx # FC (как INotificationSFC) + slots
36
+ ├── NotificationGrouped.tsx # FC, обёртка + декоративный footer
37
+ ├── components/
38
+ │ ├── NotificationIcon.tsx # <div> wrapper для иконки
39
+ │ ├── NotificationBody.tsx # FC (как INotificationBodySFC) + slots
40
+ │ ├── NotificationHeader.tsx # <h3>
41
+ │ ├── NotificationBodyContent.tsx # <Text size=B3 type=PRIMARY tag=div>
42
+ │ ├── NotificationBodyList.tsx # <UnorderedList> + map по values[]
43
+ │ ├── NotificationFooter.tsx # <div>
44
+ │ ├── NotificationClose.tsx # <ButtonIcon> с CrossStrokeSrvIcon16
45
+ │ ├── NotificationTime.tsx # <span> с временем
46
+ │ └── NotificationGroupedFooter.tsx # 2 декоративных <div>
47
+ ├── index.ts # Barrel: Notification + NotificationGrouped
48
+ ├── styles/Notification.module.less
49
+ └── __tests__/Notification.test.tsx
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Compound-структура
55
+
56
+ ```tsx
57
+ <Notification onClick={...} isShowCloseOnHover>
58
+ <Notification.Icon><MailIcon /></Notification.Icon>
59
+ <Notification.Body>
60
+ <Notification.Body.Header>Заголовок</Notification.Body.Header>
61
+ <Notification.Body.Content>Текст сообщения</Notification.Body.Content>
62
+ <Notification.Body.List values={["Один", "Два"]} />
63
+ <Notification.Body.Footer>
64
+ <Button>Действие</Button>
65
+ </Notification.Body.Footer>
66
+ </Notification.Body>
67
+ <Notification.Close onClick={handleClose} />
68
+ <Notification.Time time="12:34" />
69
+ </Notification>
70
+
71
+ <NotificationGrouped>
72
+ <Notification>...</Notification>
73
+ </NotificationGrouped>
74
+ ```
75
+
76
+ Контракт компонента: «Может содержать только Icon, Body, Close, Time» — на
77
+ уровне типов не ограничено (`children: ReactElement | ReactElement[]`),
78
+ но стилизация рассчитана только на эти 4 слота.
79
+
80
+ ---
81
+
82
+ ## Варианты и props
83
+
84
+ ### Notification — `INotificationProps extends React.ButtonHTMLAttributes<HTMLElement>`
85
+
86
+ | Prop | Тип | Default | Описание |
87
+ |---|---|---|---|
88
+ | `children` | `ReactElement \| ReactElement[]` | — | Только Icon/Body/Close/Time. |
89
+ | `withExtraBottomPadding` | `boolean` | `false` | Дополнительный нижний padding (mail-варианты). |
90
+ | `isShowCloseOnHover` | `boolean` | `false` | Close видим только при hover'е (для SideOverlay/Alert). |
91
+ | `onClick` | `() => void` | — | Клик по карточке. |
92
+ | `...HTMLAttributes` | `ButtonHTMLAttributes<HTMLElement>` | — | Прокидываются на корневой `<div>` (имя `Button*` — историческое). |
93
+
94
+ - Корневой тег — **`<div role="alertdialog">`**, не `<button>` (несмотря на `ButtonHTMLAttributes`).
95
+ - `data-tx={process.env.npm_package_version}` — версия пакета.
96
+
97
+ ### Notification.Body — `INotificationBodySFC` (slots: Header, Content, List, Footer)
98
+
99
+ - `children: ReactNode` — последовательность заголовка / контента / списка / футера.
100
+ - Каждый слот — `React.FC` (без forwardRef).
101
+
102
+ ### Notification.Body.Header
103
+
104
+ - `<h3>` с фиксированными стилями. `children: ReactNode`.
105
+
106
+ ### Notification.Body.Content
107
+
108
+ - `<Text tag="div" size=B3 type=PRIMARY>{children}</Text>` — типографика жёстко зашита.
109
+
110
+ ### Notification.Body.List — `INotificationBodyListProps extends IUnorderedListProps`
111
+
112
+ - **`values: string[]`** — массив строк, рендерятся как `UnorderedList.Item`.
113
+ - `...IUnorderedListProps` — пробрасывается. `className` мержится с локальным.
114
+
115
+ ### Notification.Body.Footer
116
+
117
+ - `<div>` с локальной стилизацией. `children: ReactNode`.
118
+
119
+ ### Notification.Close — `INotificationCloseProps extends Omit<IButtonIconProps, "children">`
120
+
121
+ - **Иконка фиксирована**: `CrossStrokeSrvIcon16 paletteIndex={5}`.
122
+ - `onClick: () => void` (обязателен).
123
+ - `children?: never` — нельзя кастомизировать иконку.
124
+ - Обёрнут в `<span>` для позиционирования.
125
+
126
+ ### Notification.Icon — `INotificationIconProps`
127
+
128
+ - `children: ReactElement` — потребительская иконка. Обёрнута в `<div>` с фикс.размером (см. styles).
129
+
130
+ ### Notification.Time — `INotificationTimeProps`
131
+
132
+ - `time: ReactText` (string|number) — рендерится в `<span>` без форматирования.
133
+
134
+ ### NotificationGrouped — `INotificationGroupedProps`
135
+
136
+ - `children: ReactNode` — обычно одна `<Notification>`.
137
+ - Добавляет **2 декоративных `<div>`** снизу (`NotificationGroupedFooter`) — визуальный эффект «стопки».
138
+
139
+ ---
140
+
141
+ ## Ключевые особенности реализации
142
+
143
+ ### `INotificationSFC` — slots через property assignment, не Object.assign
144
+
145
+ ```tsx
146
+ export const Notification: INotificationSFC = ((props) => {...}) as INotificationSFC;
147
+ Notification.displayName = "Notification";
148
+ Notification.Icon = NotificationIcon;
149
+ // ...
150
+ ```
151
+
152
+ То же — `INotificationBodySFC`. **Нет `forwardRef`** на корне.
153
+
154
+ ### `role="alertdialog"` на корневом `<div>`
155
+
156
+ - Семантика модального уведомления, требующего внимания. Несмотря на `ButtonHTMLAttributes` в типах — корень всегда `<div>`, поэтому атрибуты `<button>`-only (например `disabled`, `type="submit"`) не применятся.
157
+
158
+ ### `isShowCloseOnHover` — для SideOverlay/Alert
159
+
160
+ - Класс `styles.showCloseOnHover` — включает CSS-правило, которое делает `Notification.Close` видимым только при hover'е на родителе. Используется в `Alert` и `SideOverlay` (по комментарию в коде).
161
+
162
+ ### `withExtraBottomPadding` — mail-вариант
163
+
164
+ - Дополнительный нижний padding для случая mail-нотификации (где Footer часто содержит CTA-кнопки).
165
+
166
+ ### `Body.List` — только строки
167
+
168
+ - `values: string[]` — невозможно использовать ReactNode-элементы (ссылки, форматирование) внутри списка без рефакторинга. Известное ограничение API.
169
+
170
+ ### `Close` — фиксированная иконка
171
+
172
+ - `CrossStrokeSrvIcon16 paletteIndex={5}` — нельзя заменить (`children: never`). Если нужно другое — потребитель кладёт собственный `ButtonIcon` мимо слота.
173
+
174
+ ### `Grouped` — только декорация
175
+
176
+ - `NotificationGrouped` не управляет stack'ом нескольких уведомлений; это чистый CSS-эффект «карточка из 3-х слоёв» вокруг одного `Notification`.
177
+
178
+ ---
179
+
180
+ ## Инварианты
181
+
182
+ - **Корень — `<div role="alertdialog">`**, не интерактивный элемент. `ButtonHTMLAttributes` — историческое API (имя), не означает `<button>` рендера.
183
+ - **`children` — только Icon / Body / Close / Time** (контракт документации; типы шире, но стили рассчитаны только на эти 4 слота).
184
+ - **`Body` — Header / Content / List / Footer** в этом смысловом порядке (CSS закладывает spacing).
185
+ - **`Close` иконка фиксирована**; `children: never`.
186
+ - **`Body.List.values: string[]`** — не `ReactNode[]`. При расширении API — breaking.
187
+ - **`Body.Content` типография зашита** (`B3 / PRIMARY`).
188
+ - **`Body.Header` — `<h3>`**. Heading-уровень не настраивается — может конфликтовать с outline страницы (a11y).
189
+ - **`isShowCloseOnHover` ↔ родитель** — работает только когда `Notification` — внутри SideOverlay/Alert (CSS `:hover` на родителе/самом элементе).
190
+ - **FC, не forwardRef** на всех уровнях (legacy).
191
+ - **`NotificationGrouped` — декорация**, не контейнер для списка.
192
+ - **`data-tx`** — версия пакета на корне.
193
+
194
+ ---
195
+
196
+ ## Accessibility
197
+
198
+ - `role="alertdialog"` — корректный для модального уведомления, но контейнер не сам управляет `aria-labelledby` / `aria-describedby` — потребитель должен передать их через `...HTMLAttributes`.
199
+ - `<h3>` в `Body.Header` — фиксированный heading-уровень. Для контекстов, где это нарушает outline (например, top-level Alert на странице без h1/h2), — возможен a11y-гэп.
200
+ - `Close` — `<ButtonIcon>` с иконкой crossbar; **нет `aria-label`** в коде (передаётся через `...buttonProps`). Потребитель должен установить `aria-label="Закрыть уведомление"` при создании `<Notification.Close>`.
201
+ - `isShowCloseOnHover` — close-кнопка не видна без hover'а ⇒ для keyboard-only пользователей может быть недоступна, если фокус-стили не показывают её. Проверить!
202
+ - Корень — `<div>`, но `onClick` есть — без `keydown` Enter/Space обработчика. Если `onClick` критичен — клавиатура не работает.
203
+
204
+ ---
205
+
206
+ ## Дизайн-токены
207
+
208
+ Нет собственных. Цвета/spacing — из глобальных токенов (см. `styles/Notification.module.less`). Иконка `CrossStrokeSrvIcon16` использует `paletteIndex={5}`.
209
+
210
+ ---
211
+
212
+ ## Связанные компоненты
213
+
214
+ - `SideOverlay` / `Alert` — типичные контейнеры (закрытие по hover).
215
+ - `UnorderedList` — основа `Body.List`.
216
+ - `Text` (Typography) — `Body.Content`.
217
+ - `ButtonIcon` — `Close`.
218
+ - `CrossStrokeSrvIcon16` — иконка close.
219
+
220
+ ---
221
+
222
+ ## Stories
223
+
224
+ `stories/Notification/Notification.stories.tsx`
225
+ Примеры: `stories/Notification/examples/`
226
+
227
+ ---
228
+
229
+ ## История изменений
230
+
231
+ | Дата | Изменение |
232
+ |---|---|
233
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,178 @@
1
+ ---
2
+ component: NumberField
3
+ category: Form Controls
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [TextField, FormField, Amount]
7
+ tokens: []
8
+ stories: stories/NumberField/NumberField.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # NumberField
13
+
14
+ ## Назначение
15
+
16
+ Текстовое поле для ввода **числовых значений**: фильтрует ввод на лету,
17
+ оставляя только цифры, один десятичный разделитель (`,`) и опциональный
18
+ unary minus в позиции 0. Сам visual layer — `TextFieldBase`; уникальное
19
+ поведение — кастомный `<input>` (`NumberFieldInput`), который чистит
20
+ строку и компенсирует позицию каретки.
21
+
22
+ Используй когда: поле для ввода числа без формата суммы (без
23
+ group-separator). Для сумм с разделителями разрядов — `Amount`. Для
24
+ строковых значений — `TextField`.
25
+
26
+ ---
27
+
28
+ ## Файловая структура
29
+
30
+ ```text
31
+ src/components/NumberField/
32
+ ├── NumberField.tsx # FC, обёртка над TextFieldBase + NumberFieldInput
33
+ ├── NumberFieldInput.tsx # forwardRef, кастомная фильтрация ввода
34
+ ├── types.ts # INumberFieldProps = ITextFieldProps
35
+ ├── index.ts # Barrel
36
+ └── __tests__/
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Варианты и props
42
+
43
+ ### `INumberFieldProps extends ITextFieldProps`
44
+
45
+ Полностью наследует API `TextField`. Уникального prop'а нет.
46
+
47
+ | Prop (важные из ITextFieldProps) | Тип | Описание |
48
+ |---|---|---|
49
+ | `inputProps` | `IFormFieldInputProps` | Прокидывается в `<NumberFieldInput>` (включая `value`, `onChange`, `placeholder`, `ref`). |
50
+ | `size` / `status` / `label` / `prefix` / `postfix` / ... | — | От `TextFieldBase`. |
51
+
52
+ ### Внутренние правила фильтрации (`NumberFieldInput`)
53
+
54
+ | Случай | Поведение |
55
+ |---|---|
56
+ | Цифра `0–9` | оставляется |
57
+ | `,` или `.` (decimal separator) | первый — нормализуется в `,`; второй (если **правее каретки**) — заменяет первый, первый стирается |
58
+ | `-` в позиции `0` | оставляется как unary minus |
59
+ | Любое другое | удаляется |
60
+ | `,` или `.` левее уже существующего разделителя | удаляется |
61
+
62
+ - Разделитель — `AmountConst.DecimalComma` (`,`).
63
+ - Каретка корректируется: `setCaretPosition(target, caret + (newLength - oldLength))`.
64
+
65
+ ---
66
+
67
+ ## Ключевые особенности реализации
68
+
69
+ ### Фильтр в `onChange`, **не** в `onBeforeInput`
70
+
71
+ ```tsx
72
+ const handleChange = (event) => {
73
+ const caret = getCaretPosition(event.target);
74
+ const value = getFilteredValue(event.target.value, caret);
75
+ const caretShift = value.length - event.target.value.length;
76
+ event.target.value = value;
77
+ setCaretPosition(event.target, caret + caretShift);
78
+ onChange?.(event);
79
+ };
80
+ ```
81
+
82
+ - `event.target.value` мутируется **синхронно** до вызова потребительского `onChange` — потребитель получает уже отфильтрованное значение.
83
+ - React будет видеть это как controlled-input change (если потребитель контролирует значение).
84
+
85
+ ### Поведение «второй разделитель правее каретки»
86
+
87
+ ```ts
88
+ // Если уже был ',' и пользователь вводит ещё один справа от каретки:
89
+ // сдвигаем разделитель вправо, старый затираем.
90
+ if (separatorIndex == -1) buffer.push(",")
91
+ else if (i > caret) { buffer.push(","); buffer[separatorIndex] = ""; ... }
92
+ ```
93
+
94
+ - Полезно для UX: если пользователь печатает `123,4` и ставит курсор после `123`, нажатие `,` снова — переместит разделитель.
95
+ - Если новый разделитель **левее или на каретке** — он игнорируется (старый сохраняется).
96
+
97
+ ### Unary minus только в позиции 0
98
+
99
+ ```ts
100
+ else if (i === 0 && StringUtils.isUnaryMinus(value[i])) buffer.push("-");
101
+ ```
102
+
103
+ - `-` где-либо ещё — удаляется.
104
+ - Поддерживается **один** минус. Двойной минус — невозможен.
105
+
106
+ ### `,` vs `.`
107
+
108
+ - `.` принимается на ввод (например, нажатие `.` на нумпаде), но конвертируется в `,` (`AmountConst.DecimalComma`).
109
+ - Контракт значения: всегда строка с `,` (если используется decimal). Для backend'а, если ожидается `.` — потребитель должен сам сконвертировать.
110
+
111
+ ### `NumberField` — только `TextFieldBase`-обёртка
112
+
113
+ ```tsx
114
+ export const NumberField = ({ inputProps, ...restProps }) => (
115
+ <TextFieldBase {...restProps}>
116
+ <NumberFieldInput {...inputProps} />
117
+ </TextFieldBase>
118
+ );
119
+ ```
120
+
121
+ - **Не `forwardRef`** на `NumberField` — но `NumberFieldInput` — `forwardRef<HTMLInputElement>`. Если нужен ref на input — потребитель должен передать его через `inputProps.ref`.
122
+
123
+ ### `IFormFieldInputProps` для `inputProps`
124
+
125
+ - `inputProps` — стандартный для FormField API (`value`, `onChange`, `defaultValue`, `placeholder`, `disabled`, `ref`).
126
+
127
+ ---
128
+
129
+ ## Инварианты
130
+
131
+ - **Фильтрация — `digit | "," | начальный "-"`** — расширение списка допустимых символов = breaking.
132
+ - **Один разделитель**, конвертируется в `,`.
133
+ - **Unary minus только в позиции 0** — внутри числа `-` теряется.
134
+ - **`AmountConst.DecimalComma = ","`** — изменение глобальной константы повлияет на NumberField.
135
+ - **`event.target.value` мутируется** до вызова потребительского `onChange` — `onChange` получает уже отфильтрованную строку.
136
+ - **Каретка корректируется** через `setCaretPosition` — без потери позиции при удалении невалидных символов.
137
+ - **`NumberFieldInput` — `forwardRef`**, `NumberField` — простая FC.
138
+ - **API = `ITextFieldProps`** — нет собственных props. Расширения = breaking.
139
+
140
+ ---
141
+
142
+ ## Accessibility
143
+
144
+ - Стандартный `<input>` (через `FormFieldInput`) — клавиатура работает как для TextField.
145
+ - `inputmode` / `type` **не выставляется** на `numeric` / `decimal` — на mobile откроется обычная клавиатура. Потребитель может передать через `inputProps.inputMode = "decimal"`.
146
+ - Скринридеры читают как обычное text input. Для семантики числа — потребитель добавляет `aria-*`.
147
+
148
+ ---
149
+
150
+ ## Дизайн-токены
151
+
152
+ Нет собственных — наследуются от `TextField` / `FormField`.
153
+
154
+ ---
155
+
156
+ ## Связанные компоненты
157
+
158
+ - `TextField` / `TextFieldBase` — визуальная база.
159
+ - `FormFieldInput` — нижележащий `<input>`.
160
+ - `Amount` — для денежных значений (с group-separator и фиксированной точностью).
161
+ - `AmountConst` — `DecimalComma`, `DecimalPoint`.
162
+ - `StringUtils` — `isDigit`, `isDecimalSeparator`, `isUnaryMinus`.
163
+ - `inputUtils` — `getCaretPosition`, `setCaretPosition`.
164
+
165
+ ---
166
+
167
+ ## Stories
168
+
169
+ `stories/NumberField/NumberField.stories.tsx`
170
+ Примеры: `stories/NumberField/examples/`
171
+
172
+ ---
173
+
174
+ ## История изменений
175
+
176
+ | Дата | Изменение |
177
+ |---|---|
178
+ | 2026-04-18 | Создан документ |