@sberbusiness/triplex-next-mcp-server 1.50.0-beta → 1.53.1

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 (74) hide show
  1. package/README.md +1 -0
  2. package/bundle/components/AlertProcess.md +6 -3
  3. package/bundle/components/AlertProcessSpoiler.md +216 -0
  4. package/bundle/components/Badge.md +4 -3
  5. package/bundle/components/ButtonDropdown.md +5 -3
  6. package/bundle/components/Carousel.md +671 -0
  7. package/bundle/components/CarouselExtended.md +7 -5
  8. package/bundle/components/CarouselIndicators.md +666 -0
  9. package/bundle/components/CarouselItem.md +579 -0
  10. package/bundle/components/CarouselNextButton.md +633 -0
  11. package/bundle/components/CarouselPrevButton.md +633 -0
  12. package/bundle/components/CarouselViewport.md +631 -0
  13. package/bundle/components/CheckboxTreeExtended.md +21 -7
  14. package/bundle/components/CheckboxTreeExtendedCheckbox.md +591 -0
  15. package/bundle/components/CheckboxTreeExtendedNode.md +577 -0
  16. package/bundle/components/Chip.md +1 -0
  17. package/bundle/components/ChipDatePicker.md +332 -0
  18. package/bundle/components/ChipDatePickerTarget.md +316 -0
  19. package/bundle/components/ChipMonthYearPicker.md +4 -3
  20. package/bundle/components/ChipMonthYearPickerTarget.md +318 -0
  21. package/bundle/components/ChipMultiselect.md +63 -73
  22. package/bundle/components/ChipSelect.md +385 -0
  23. package/bundle/components/ChipSelectTarget.md +388 -0
  24. package/bundle/components/ChipSuggest.md +10 -16
  25. package/bundle/components/ChipSuggestTarget.md +506 -0
  26. package/bundle/components/CollapsibleTree.md +2 -1
  27. package/bundle/components/CollapsibleTreeExtended.md +2 -1
  28. package/bundle/components/DateField.md +4 -2
  29. package/bundle/components/DatePickerExtended.md +16 -14
  30. package/bundle/components/DateRange.md +17 -10
  31. package/bundle/components/Dropdown.md +36 -63
  32. package/bundle/components/EmptyView.md +9 -4
  33. package/bundle/components/ExpandAnimation.md +9 -5
  34. package/bundle/components/FormField.md +1 -1
  35. package/bundle/components/ImageGallery.md +19 -52
  36. package/bundle/components/ImageGalleryExtended.md +123 -139
  37. package/bundle/components/ListItemControlsButtonDropdown.md +3 -2
  38. package/bundle/components/LoaderSmall.md +5 -4
  39. package/bundle/components/MonthYearRange.md +334 -0
  40. package/bundle/components/MultiselectField.md +81 -143
  41. package/bundle/components/Notification.md +2 -1
  42. package/bundle/components/NotificationGrouped.md +174 -0
  43. package/bundle/components/NumberField.md +259 -116
  44. package/bundle/components/OrderedList.md +149 -112
  45. package/bundle/components/Overlay.md +3 -2
  46. package/bundle/components/PageIndicators.md +306 -0
  47. package/bundle/components/Pagination.md +81 -3
  48. package/bundle/components/PaginationExtended.md +160 -0
  49. package/bundle/components/Portal.md +5 -2
  50. package/bundle/components/Puller.md +375 -0
  51. package/bundle/components/SMSField.md +277 -102
  52. package/bundle/components/SelectExtendedField.md +11 -7
  53. package/bundle/components/SelectField.md +7 -4
  54. package/bundle/components/SmartSpot.md +259 -0
  55. package/bundle/components/Step.md +2 -1
  56. package/bundle/components/Stepper.md +7 -7
  57. package/bundle/components/Suggest.md +7 -6
  58. package/bundle/components/SuggestField.md +8 -6
  59. package/bundle/components/TableBasic.md +12 -14
  60. package/bundle/components/Tooltip.md +9 -8
  61. package/bundle/guides/commits.md +4 -1
  62. package/bundle/guides/context.md +5 -5
  63. package/bundle/guides/stories.md +29 -21
  64. package/bundle/manifest.json +145 -13
  65. package/bundle/release-notes/1.50.0.mdx +4 -0
  66. package/bundle/release-notes/1.51.0.mdx +57 -0
  67. package/bundle/release-notes/1.52.0.mdx +55 -0
  68. package/bundle/release-notes/1.53.0.mdx +60 -0
  69. package/bundle/release-notes/1.54.0.mdx +45 -0
  70. package/bundle/release-notes/1.55.0.mdx +7 -0
  71. package/bundle/tokens.json +377 -222
  72. package/dist/index.js +39 -1
  73. package/dist/index.js.map +1 -1
  74. package/package.json +1 -1
@@ -0,0 +1,174 @@
1
+ ---
2
+ component: NotificationGrouped
3
+ category: Feedback
4
+ related: [Notification]
5
+ tokens:
6
+ - Notification.Background
7
+ - Notification.Shadow
8
+ stories: stories/NotificationGrouped/NotificationGrouped.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # NotificationGrouped
13
+
14
+ ## Назначение
15
+
16
+ Визуально обозначает группу уведомлений: под содержимым отображаются два декоративных
17
+ слоя, создающие эффект стопки карточек. Обычно в группу вкладывают один `Notification`,
18
+ который представляет несколько сообщений.
19
+
20
+ Используй когда: нужно показать свёрнутую группу уведомлений одной карточкой.
21
+ Не используй когда: нужно отобразить каждое сообщение отдельно — отрендери список
22
+ `Notification`. Количество сообщений, раскрытие группы и закрытие управляются приложением.
23
+
24
+ ---
25
+
26
+ ## Варианты и props
27
+
28
+ | Prop | Тип | Описание |
29
+ |---|---|---|
30
+ | `children` | `React.ReactNode` | Содержимое группы. Обычно один `Notification`; тип не ограничивает состав дочерних узлов |
31
+
32
+ Других props у обёртки нет: HTML-атрибуты, `className` и обработчики задаются вложенному
33
+ `Notification` или внешнему контейнеру. `ref` передаётся на корневой `div` группы,
34
+ а не на вложенное уведомление.
35
+
36
+ Компонент выводит `children` без преобразования и всегда добавляет декоративный footer,
37
+ в том числе при `children={null}`. Два слоя обозначают стопку независимо от числа сообщений.
38
+ Для пользовательского интерфейса передавай содержательную карточку.
39
+
40
+ Ширина группы на десктопе — 376px, на ширине экрана до 767px — 100% родителя.
41
+ Нижний внешний отступ — 32px; декоративные слои выступают на 8px и 16px ниже содержимого.
42
+ Отступы, иконка, текст, время и действия самой карточки настраиваются через `Notification`.
43
+
44
+ ---
45
+
46
+ ## Дизайн-токены
47
+
48
+ Переопределяются через `ThemeProvider` (prop `tokens`) — см.
49
+ [`ThemeProvider-ai.md`](../ThemeProvider/ThemeProvider-ai.md) → «Как переопределять токены».
50
+ Значения по умолчанию — `src/components/DesignTokens/components/Notification.ts`.
51
+
52
+ | Токен | Назначение |
53
+ |---|---|
54
+ | `Notification.Background` | Фон декоративных слоёв |
55
+ | `Notification.Shadow` | Тень декоративных слоёв |
56
+
57
+ Токены общие с `Notification`: их переопределение меняет карточку и слои стопки.
58
+ Цвет текста и времени относятся к вложенному уведомлению и описаны в
59
+ [`Notification-ai.md`](./Notification-ai.md).
60
+
61
+ ---
62
+
63
+ ## Инварианты
64
+
65
+ - `INotificationGroupedProps.children` обязателен и сохраняет тип `React.ReactNode`.
66
+ - `forwardRef<HTMLDivElement, INotificationGroupedProps>` и `displayName="NotificationGrouped"`
67
+ сохраняются; корневой элемент и ref-target — `div` группы.
68
+ - Публичные экспорты `NotificationGrouped` и `INotificationGroupedProps` из
69
+ `src/components/Notification/index.ts` сохраняются.
70
+ - Декоративный `NotificationGroupedFooter` располагается после `children` и содержит
71
+ два слоя. Он не экспортируется через публичный barrel.
72
+ - Классы `notificationGroupedWrapper`, `notificationGroupedFooterItem`, `first`, `second`
73
+ и пути токенов сохраняются. Разметка и порядок слоёв влияют на visual baselines.
74
+ - Группа не фильтрует дочерние узлы и не управляет состоянием сообщений.
75
+
76
+ ---
77
+
78
+ ## Accessibility
79
+
80
+ Обёртка — обычный `div` без роли, `tabIndex` и клавиатурных обработчиков. Курсор при
81
+ наведении имеет вид указателя, но компонент сам не добавляет интерактивность.
82
+ Декоративные слои не содержат текста или элементов управления.
83
+
84
+ Роль `alertdialog` задаёт вложенный `Notification`, а не группа. Подписи ARIA и действия
85
+ передавай самому уведомлению и его дочерним элементам; например, `aria-label` для
86
+ `Notification.Close` задаёт потребитель на языке приложения. Клавиатурный фокус
87
+ принадлежит вложенным кнопкам и ссылкам.
88
+
89
+ ---
90
+
91
+ ## Связанные компоненты
92
+
93
+ - `Notification` — карточка внутри группы; определяет содержимое, действия и accessibility.
94
+ - `NotificationGroupedFooter` — приватный декоративный footer из двух пустых слоёв;
95
+ отдельного публичного API и AI-документа нет.
96
+
97
+ ---
98
+
99
+ ## Stories
100
+
101
+ Основные истории: `stories/NotificationGrouped/NotificationGrouped.stories.tsx`
102
+ Файлы примеров: `stories/NotificationGrouped/examples/`
103
+
104
+ | Story | Example file | Что демонстрирует |
105
+ |---|---|---|
106
+ | `Default` | `Default.tsx` | Минимальная группа с одним уведомлением |
107
+ | `WithFooter` | `WithFooter.tsx` | Карточка с действием, кнопкой закрытия и временем |
108
+ | `VisualTests` | `VisualTests.tsx` | Клавиатурный фокус на действии и закрытие при наведении на карточку |
109
+
110
+ Playground отсутствует: у обёртки только `children`, настраиваемых вариантов нет.
111
+ Stories снимаются на xs/xl; реальное наведение для `VisualTests` выполняется test-runner
112
+ через `hoverSelector`, а фокус устанавливается клавиатурой в `play`.
113
+ Несколько групп подряд — story `Business Stack` в `stories/Notification/`.
114
+
115
+ ---
116
+
117
+ ## История изменений
118
+
119
+ | Дата | Изменение |
120
+ |---|---|
121
+ | 2026-10-08 | Создан документ; уточнены JSDoc, выделены unit-тесты и добавлены отдельные modern stories NotificationGrouped |
122
+
123
+ ---
124
+
125
+ ## Примеры использования
126
+
127
+ ### Default
128
+
129
+ `stories/NotificationGrouped/examples/Default.tsx`
130
+
131
+ ```tsx
132
+ import React from "react";
133
+ import { Notification, NotificationGrouped } from "@sberbusiness/triplex-next";
134
+
135
+ export const Default = () => (
136
+ <NotificationGrouped>
137
+ <Notification>
138
+ <Notification.Body>
139
+ <Notification.Body.Content>Получены новые сообщения.</Notification.Body.Content>
140
+ </Notification.Body>
141
+ </Notification>
142
+ </NotificationGrouped>
143
+ );
144
+ ```
145
+
146
+ ### WithFooter
147
+
148
+ `stories/NotificationGrouped/examples/WithFooter.tsx`
149
+
150
+ ```tsx
151
+ import React from "react";
152
+ import { Button, EButtonTheme, EComponentSize, Notification, NotificationGrouped } from "@sberbusiness/triplex-next";
153
+
154
+ export const WithFooter = () => (
155
+ <NotificationGrouped>
156
+ <Notification withExtraBottomPadding>
157
+ <Notification.Body>
158
+ <Notification.Body.Header>Новые платежи</Notification.Body.Header>
159
+ <Notification.Body.Content>
160
+ Получены три платежа. Откройте список для проверки.
161
+ </Notification.Body.Content>
162
+ <Notification.Body.Footer>
163
+ <Button theme={EButtonTheme.SECONDARY} size={EComponentSize.SM} onClick={() => {}}>
164
+ Открыть платежи
165
+ </Button>
166
+ </Notification.Body.Footer>
167
+ </Notification.Body>
168
+ <Notification.Close aria-label="Закрыть уведомление" onClick={() => {}} />
169
+ <Notification.Time time="14:30" />
170
+ </Notification>
171
+ </NotificationGrouped>
172
+ );
173
+ ```
174
+
@@ -1,9 +1,7 @@
1
1
  ---
2
2
  component: NumberField
3
- category: Form Controls
4
- figma-node: ""
5
- figma-file: ""
6
- related: [TextField, FormField, Amount]
3
+ category: TextFields
4
+ related: [AmountField, TextField, FormField]
7
5
  tokens: []
8
6
  stories: stories/NumberField/NumberField.stories.tsx
9
7
  version: "1.0"
@@ -13,166 +11,311 @@ version: "1.0"
13
11
 
14
12
  ## Назначение
15
13
 
16
- Текстовое поле для ввода **числовых значений**: фильтрует ввод на лету,
17
- оставляя только цифры, один десятичный разделитель (`,`) и опциональный
18
- unary minus в позиции 0. Сам visual layer — `TextFieldBase`; уникальное
19
- поведение — кастомный `<input>` (`NumberFieldInput`), который чистит
20
- строку и компенсирует позицию каретки.
14
+ Однострочное поле для ввода числовой строки с плавающим лейблом, статусом, префиксом/постфиксом и описанием. При изменении ввода оставляет цифры, ведущий минус и один десятичный разделитель; точку заменяет запятой. Композиция: приватный `TextFieldBase` (семейство `FormField`) и приватный `NumberFieldInput` поверх `FormFieldInput`.
21
15
 
22
- Используй когда: поле для ввода числа без формата суммы (без
23
- group-separator). Для сумм с разделителями разрядов — `Amount`. Для
24
- строковых значений — `TextField`.
16
+ Используй когда: пользователь вводит произвольное целое или дробное число без денежного форматирования, ограничения точности и разделителей разрядов.
25
17
 
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
- ```
18
+ Не используй когда: нужна денежная сумма с форматированием и нормализованным значением (`AmountField`), произвольный текст (`TextField`), фиксированная маска (`MaskedField`) или только отображение числа без ввода.
38
19
 
39
20
  ---
40
21
 
41
22
  ## Варианты и props
42
23
 
43
- ### `INumberFieldProps extends ITextFieldProps`
24
+ `INumberFieldProps` наследует `ITextFieldProps`; собственных дополнительных props нет. `inputProps` передаётся в `NumberFieldInput`, остальные props — в `TextFieldBase`. Полный контракт атрибутов и слотов описан в `TextField-ai.md` и исходных интерфейсах.
44
25
 
45
- Полностью наследует API `TextField`. Уникального prop'а нет.
26
+ ### Обязательные props
46
27
 
47
- | Prop (важные из ITextFieldProps) | Тип | Описание |
28
+ | Prop | Назначение и ограничения |
29
+ |---|---|
30
+ | `inputProps` | Атрибуты и обработчики элемента ввода: `value`/`defaultValue`, `onChange`, `placeholder`, `id`, ARIA-атрибуты, `ref` и `render`. Для контролируемого ввода храни строку из `event.target.value`; это значение с запятой, а не нормализованная числовая строка с точкой. `inputProps.ref` указывает на `HTMLInputElement`. |
31
+
32
+ ### Опциональные props
33
+
34
+ | Prop | По умолчанию | Назначение |
48
35
  |---|---|---|
49
- | `inputProps` | `IFormFieldInputProps` | Прокидывается в `<NumberFieldInput>` (включая `value`, `onChange`, `placeholder`, `ref`). |
50
- | `size` / `status` / `label` / `prefix` / `postfix` / ... | — | От `TextFieldBase`. |
36
+ | `size` | `EComponentSize.LG` | Размер SM / MD / LG; наследуется вложенным input через `FormField`. |
37
+ | `status` | `EFormFieldStatus.DEFAULT` | DEFAULT / ERROR / WARNING / DISABLED. Статус DISABLED устанавливает нативный `disabled` на input. |
38
+ | `active` | `false` | Принудительно активное визуальное состояние; фокус input также делает поле активным. |
39
+ | `label` | — | Плавающий лейбл, связанный с input через `htmlFor`. |
40
+ | `prefix`, `postfix` | — | Контент слева и справа от input; кнопку очистки потребитель добавляет в `postfix` и сам сбрасывает значение. |
41
+ | `description`, `counter` | — | Описание и счётчик под полем, отображаются в общем блоке. |
51
42
 
52
- ### Внутренние правила фильтрации (`NumberFieldInput`)
43
+ `className`, `style`, data-атрибуты и другие div-атрибуты применяются к контейнеру `FormField` внутри `FormGroup`. Внешний `ref` указывает на этот же `<div>`; ссылка на input передаётся отдельно через `inputProps.ref`.
53
44
 
54
- | Случай | Поведение |
55
- |---|---|
56
- | Цифра `0–9` | оставляется |
57
- | `,` или `.` (decimal separator) | первый — нормализуется в `,`; второй (если **правее каретки**) — заменяет первый, первый стирается |
58
- | `-` в позиции `0` | оставляется как unary minus |
59
- | Любое другое | удаляется |
60
- | `,` или `.` левее уже существующего разделителя | удаляется |
45
+ ### Особенности поведения
61
46
 
62
- - Разделитель — `AmountConst.DecimalComma` (`,`).
63
- - Каретка корректируется: `setCaretPosition(target, caret + (newLength - oldLength))`.
47
+ - Фильтрация выполняется только при событии изменения ввода. Значения `value` и `defaultValue`, переданные снаружи, не нормализуются автоматически.
48
+ - Разрешены цифры `0`–`9`. Минус сохраняется только в начале исходной строки; другие символы удаляются. Ведущие нули остаются.
49
+ - Точка и запятая принимаются как десятичные разделители; в результате остаётся не более одной запятой. При повторном разделителе выбор зависит от каретки: разделитель справа от неё заменяет ранее найденный, остальные повторения игнорируются.
50
+ - Пустая строка и промежуточные значения `"-"`, `","`, `"-,"` допустимы. Компонент не проверяет завершённость числа, диапазон или количество дробных знаков и не преобразует строку в `number`.
51
+ - Перед вызовом `inputProps.onChange` изменяется `event.target.value`; обработчик получает тот же event с отфильтрованным значением. Если input в фокусе, каретка сдвигается только на символы, удалённые левее неё: символы, удалённые правее (например, минус не в начале строки), позицию не меняют.
52
+ - По умолчанию рендерится текстовый `<input>`. Сохраняй текстовый тип для работы с запятой и кареткой; подходящий `inputMode` потребитель задаёт через `inputProps`.
53
+ - При использовании `inputProps.render` передавай предоставленные атрибуты, обработчики и ref своему input, чтобы сохранить фильтрацию и связь с `FormField`.
64
54
 
65
55
  ---
66
56
 
67
- ## Ключевые особенности реализации
57
+ ## Дизайн-токены
68
58
 
69
- ### Фильтр в `onChange`, **не** в `onBeforeInput`
59
+ Собственных стилей и токенов нет, поэтому `tokens: []`. Внешний вид задаёт семейство `FormField`; его токены описаны в `FormField-ai.md` и находятся в `src/components/DesignTokens/components/FormField.ts`.
70
60
 
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 (если потребитель контролирует значение).
61
+ ---
84
62
 
85
- ### Поведение «второй разделитель правее каретки»
63
+ ## Инварианты
86
64
 
87
- ```ts
88
- // Если уже был ',' и пользователь вводит ещё один справа от каретки:
89
- // сдвигаем разделитель вправо, старый затираем.
90
- if (separatorIndex == -1) buffer.push(",")
91
- else if (i > caret) { buffer.push(","); buffer[separatorIndex] = ""; ... }
92
- ```
65
+ - `forwardRef<HTMLDivElement, INumberFieldProps>` и `NumberField.displayName = "NumberField"` — не убирать. Внешний ref передаётся через `TextFieldBase` в `<div>` `FormField`; ref на input остаётся отдельным контрактом `inputProps.ref`. Оба поддерживают объектную и callback-форму.
66
+ - Имена `NumberField`, `INumberFieldProps`, унаследованные props, значения `EComponentSize`/`EFormFieldStatus` и barrel-экспорты — публичный API. Не менять без согласования.
67
+ - `NumberFieldInput` не экспортируется из barrel и не имеет отдельного AI.md: это приватная реализация фильтрации. Проверяй её поведение через публичный `NumberField`.
68
+ - Строковый контракт `inputProps.onChange` с запятой и промежуточными значениями сохраняется. Переход на числовое значение, точку или ограничения точности меняет поведение потребителя.
69
+ - Сохраняй композицию `TextFieldBase` / `FormFieldInput`, разделение контейнерных props и `inputProps`, а также общий блок `description`/`counter`.
70
+ - Story IDs и файлы baseline для `Sizes` и `Statuses` используются visual regression тестами; не переименовывать без синхронного обновления.
71
+ - Компонент и его зависимости должны оставаться совместимыми с React 17 для ветки `release-0`; не добавлять React 18-only API.
93
72
 
94
- - Полезно для UX: если пользователь печатает `123,4` и ставит курсор после `123`, нажатие `,` снова — переместит разделитель.
95
- - Если новый разделитель **левее или на каретке** — он игнорируется (старый сохраняется).
73
+ ---
96
74
 
97
- ### Unary minus только в позиции 0
75
+ ## Accessibility
98
76
 
99
- ```ts
100
- else if (i === 0 && StringUtils.isUnaryMinus(value[i])) buffer.push("-");
101
- ```
77
+ - Input имеет стандартную текстовую семантику. Лейбл связывается с ним через `htmlFor` и `id`, переданный в `inputProps.id` либо сгенерированный `FormFieldInput`.
78
+ - Когда видимого лейбла нет, доступное имя задаёт потребитель через `inputProps["aria-label"]` или `inputProps["aria-labelledby"]`.
79
+ - `status={EFormFieldStatus.DISABLED}` блокирует input и исключает его из таб-обхода. `active` задаёт визуальное состояние и сам по себе не переводит фокус.
80
+ - `aria-invalid` и связь с описанием через `aria-describedby` потребитель передаёт через `inputProps`; статус ERROR не устанавливает эти атрибуты автоматически.
81
+ - Фокус и blur синхронизируются с `FormField`; пользовательские обработчики `inputProps.onFocus`/`onBlur` сохраняются. Для программного фокуса используй `inputProps.ref`.
82
+ - Отдельных обработчиков клавиш и роли `spinbutton` нет; клавиатурная навигация стандартная для `<input>`.
102
83
 
103
- - `-` где-либо ещё — удаляется.
104
- - Поддерживается **один** минус. Двойной минус — невозможен.
84
+ ---
105
85
 
106
- ### `,` vs `.`
86
+ ## Связанные компоненты
107
87
 
108
- - `.` принимается на ввод (например, нажатие `.` на нумпаде), но конвертируется в `,` (`AmountConst.DecimalComma`).
109
- - Контракт значения: всегда строка с `,` (если используется decimal). Для backend'а, если ожидается `.` — потребитель должен сам сконвертировать.
88
+ - `AmountField` — альтернатива для денежного ввода с разделителями разрядов, заданной точностью и нормализованным значением с точкой.
89
+ - `TextField` — источник наследуемого контракта `ITextFieldProps`. Его приватный `TextFieldBase` задаёт раскладку поля и слотов; отдельного AI.md у базы нет.
90
+ - `FormField` — семейство, обеспечивающее размер, статус, фокус, заполненность и связь лейбла с input. `NumberFieldInput` использует его `FormFieldInput`.
91
+ - `NumberFieldInput` — приватный слой фильтрации цифр, знака и десятичного разделителя с коррекцией каретки.
92
+ - `FormFieldClear` — необязательная кнопка очистки в `postfix`; пример `Production` очищает контролируемое значение и возвращает фокус в input.
110
93
 
111
- ### `NumberField` — только `TextFieldBase`-обёртка
94
+ ---
112
95
 
113
- ```tsx
114
- export const NumberField = ({ inputProps, ...restProps }) => (
115
- <TextFieldBase {...restProps}>
116
- <NumberFieldInput {...inputProps} />
117
- </TextFieldBase>
118
- );
119
- ```
96
+ ## Stories
120
97
 
121
- - **Не `forwardRef`** на `NumberField` — но `NumberFieldInput` — `forwardRef<HTMLInputElement>`. Если нужен ref на input — потребитель должен передать его через `inputProps.ref`.
98
+ Основные истории: `stories/NumberField/NumberField.stories.tsx`
99
+ Файлы примеров: `stories/NumberField/examples/`
122
100
 
123
- ### `IFormFieldInputProps` для `inputProps`
101
+ | Story | Example file | Что демонстрирует |
102
+ |---|---|---|
103
+ | `Playground` | `Playground.tsx` | Управление размером, статусом, лейблом, активностью, postfix и description |
104
+ | `Default` | `Default.tsx` | Контролируемый ввод с лейблом и placeholder |
105
+ | `Sizes` | `Sizes.tsx` | Размеры SM / MD / LG |
106
+ | `Statuses` | `Statuses.tsx` | Статусы DEFAULT / ERROR / WARNING / DISABLED |
107
+ | `Production` | `Production.tsx` | Кнопка очистки с возвратом фокуса через `inputProps.ref`, единица измерения и подсказка в postfix, описание со ссылкой |
124
108
 
125
- - `inputProps` — стандартный для FormField API (`value`, `onChange`, `defaultValue`, `placeholder`, `disabled`, `ref`).
109
+ `Sizes` и `Statuses` покрыты существующими baseline-скриншотами для viewport xs/xl. `Playground`, `Default` и `Production` исключены из screenshot-прогона через `testRunner.skip`.
126
110
 
127
111
  ---
128
112
 
129
- ## Инварианты
113
+ ## История изменений
130
114
 
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.
115
+ | Дата | Изменение |
116
+ |---|---|
117
+ | 2026-10-08 | Создан документ (TRI-63). Добавлены ref на контейнер FormField и displayName; описаны фильтрация строкового ввода, refs, accessibility и существующие stories. Исправлен сдвиг каретки, когда фильтр удаляет символы правее неё |
139
118
 
140
119
  ---
141
120
 
142
- ## Accessibility
121
+ ## Примеры использования
143
122
 
144
- - Стандартный `<input>` (через `FormFieldInput`) — клавиатура работает как для TextField.
145
- - `inputmode` / `type` **не выставляется** на `numeric` / `decimal` — на mobile откроется обычная клавиатура. Потребитель может передать через `inputProps.inputMode = "decimal"`.
146
- - Скринридеры читают как обычное text input. Для семантики числа — потребитель добавляет `aria-*`.
123
+ ### Default
147
124
 
148
- ---
125
+ `stories/NumberField/examples/Default.tsx`
149
126
 
150
- ## Дизайн-токены
127
+ ```tsx
128
+ import React, { useState } from "react";
129
+ import { NumberField, EComponentSize, EFormFieldStatus } from "@sberbusiness/triplex-next";
130
+
131
+ export const Default = () => {
132
+ const [value, setValue] = useState<string>("");
133
+
134
+ const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
135
+ setValue(event.target.value);
136
+ };
137
+
138
+ return (
139
+ <div style={{ maxWidth: 300 }}>
140
+ <NumberField
141
+ size={EComponentSize.LG}
142
+ status={EFormFieldStatus.DEFAULT}
143
+ inputProps={{
144
+ value,
145
+ placeholder: "0",
146
+ onChange: handleInputChange,
147
+ }}
148
+ label="Label"
149
+ />
150
+ </div>
151
+ );
152
+ };
153
+ ```
151
154
 
152
- Нет собственных — наследуются от `TextField` / `FormField`.
155
+ ### Sizes
153
156
 
154
- ---
157
+ `stories/NumberField/examples/Sizes.tsx`
155
158
 
156
- ## Связанные компоненты
159
+ ```tsx
160
+ import React, { useState } from "react";
161
+ import { NumberField, EComponentSize, EFormFieldStatus } from "@sberbusiness/triplex-next";
162
+
163
+ interface ISizeItemProps {
164
+ size: EComponentSize;
165
+ }
166
+
167
+ const SizeItem = ({ size }: ISizeItemProps) => {
168
+ const [value, setValue] = useState<string>("");
169
+
170
+ const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
171
+ setValue(event.target.value);
172
+ };
173
+
174
+ return (
175
+ <div style={{ maxWidth: 300 }}>
176
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{size.toUpperCase()}</div>
177
+ <NumberField
178
+ size={size}
179
+ status={EFormFieldStatus.DEFAULT}
180
+ inputProps={{
181
+ value,
182
+ placeholder: "0",
183
+ onChange: handleInputChange,
184
+ }}
185
+ label="Label"
186
+ />
187
+ </div>
188
+ );
189
+ };
157
190
 
158
- - `TextField` / `TextFieldBase` — визуальная база.
159
- - `FormFieldInput` — нижележащий `<input>`.
160
- - `Amount` — для денежных значений (с group-separator и фиксированной точностью).
161
- - `AmountConst` — `DecimalComma`, `DecimalPoint`.
162
- - `StringUtils` — `isDigit`, `isDecimalSeparator`, `isUnaryMinus`.
163
- - `inputUtils` — `getCaretPosition`, `setCaretPosition`.
191
+ const SIZES = Object.values(EComponentSize);
164
192
 
165
- ---
193
+ export const Sizes = () => (
194
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
195
+ {SIZES.map((size) => (
196
+ <SizeItem key={size} size={size} />
197
+ ))}
198
+ </div>
199
+ );
200
+ ```
166
201
 
167
- ## Stories
202
+ ### Statuses
168
203
 
169
- `stories/NumberField/NumberField.stories.tsx`
170
- Примеры: `stories/NumberField/examples/`
204
+ `stories/NumberField/examples/Statuses.tsx`
171
205
 
172
- ---
206
+ ```tsx
207
+ import React, { useState } from "react";
208
+ import { NumberField, EComponentSize, EFormFieldStatus } from "@sberbusiness/triplex-next";
209
+
210
+ interface IStatusItemProps {
211
+ status: EFormFieldStatus;
212
+ }
213
+
214
+ const StatusItem = ({ status }: IStatusItemProps) => {
215
+ const [value, setValue] = useState<string>("");
216
+
217
+ const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
218
+ setValue(event.target.value);
219
+ };
220
+
221
+ return (
222
+ <div style={{ maxWidth: 300 }}>
223
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{status.toUpperCase()}</div>
224
+ <NumberField
225
+ size={EComponentSize.LG}
226
+ status={status}
227
+ inputProps={{
228
+ value,
229
+ placeholder: "0",
230
+ onChange: handleInputChange,
231
+ }}
232
+ label="Label"
233
+ />
234
+ </div>
235
+ );
236
+ };
173
237
 
174
- ## История изменений
238
+ const STATUSES = Object.values(EFormFieldStatus);
239
+
240
+ export const Statuses = () => (
241
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
242
+ {STATUSES.map((status) => (
243
+ <StatusItem key={status} status={status} />
244
+ ))}
245
+ </div>
246
+ );
247
+ ```
248
+
249
+ ### Production
250
+
251
+ `stories/NumberField/examples/Production.tsx`
252
+
253
+ ```tsx
254
+ import React, { useState, useRef } from "react";
255
+ import {
256
+ NumberField,
257
+ FormFieldClear,
258
+ Text,
259
+ HelpBox,
260
+ Link,
261
+ EComponentSize,
262
+ EFormFieldStatus,
263
+ ETextSize,
264
+ EFontType,
265
+ ETooltipSize,
266
+ } from "@sberbusiness/triplex-next";
267
+
268
+ export const Production = () => {
269
+ const [value, setValue] = useState<string>("");
270
+ const inputRef = useRef<HTMLInputElement>(null);
271
+
272
+ const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
273
+ setValue(event.target.value);
274
+ };
275
+
276
+ const handleClearButtonClick: React.MouseEventHandler<HTMLButtonElement> = () => {
277
+ setValue("");
278
+ inputRef.current?.focus();
279
+ };
280
+
281
+ const handleLinkClick: React.MouseEventHandler<HTMLAnchorElement> = (event) => {
282
+ event.preventDefault();
283
+ };
284
+
285
+ return (
286
+ <div style={{ maxWidth: 300 }}>
287
+ <NumberField
288
+ size={EComponentSize.LG}
289
+ status={EFormFieldStatus.DEFAULT}
290
+ inputProps={{
291
+ value,
292
+ placeholder: "0",
293
+ onChange: handleInputChange,
294
+ ref: inputRef,
295
+ }}
296
+ label="Label"
297
+ postfix={
298
+ <>
299
+ <FormFieldClear aria-label="clear value" onClick={handleClearButtonClick} />
300
+ <Text size={ETextSize.B2} type={EFontType.SECONDARY}>
301
+ мм
302
+ </Text>
303
+ <HelpBox tooltipSize={ETooltipSize.SM}>Helpful details appear here</HelpBox>
304
+ </>
305
+ }
306
+ description={
307
+ <>
308
+ <Text size={ETextSize.B4} type={EFontType.SECONDARY}>
309
+ (21) Description{" "}
310
+ <Link href="#" onClick={handleLinkClick}>
311
+ Link text
312
+ </Link>
313
+ </Text>
314
+ </>
315
+ }
316
+ />
317
+ </div>
318
+ );
319
+ };
320
+ ```
175
321
 
176
- | Дата | Изменение |
177
- |---|---|
178
- | 2026-04-18 | Создан документ |