@sberbusiness/triplex-next-mcp-server 0.24.0-beta2 → 1.40.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +10 -0
  2. package/bundle/components/AlertContext.md +268 -0
  3. package/bundle/components/BodyPage.md +186 -0
  4. package/bundle/components/Button.md +93 -85
  5. package/bundle/components/ButtonDropdown.md +36 -70
  6. package/bundle/components/ButtonDropdownExtended.md +422 -0
  7. package/bundle/components/ButtonIcon.md +41 -48
  8. package/bundle/components/Caption.md +291 -0
  9. package/bundle/components/Checkbox.md +43 -122
  10. package/bundle/components/CheckboxXGroup.md +109 -46
  11. package/bundle/components/CheckboxYGroup.md +77 -49
  12. package/bundle/components/CodeText.md +197 -0
  13. package/bundle/components/Col.md +311 -162
  14. package/bundle/components/CollapsibleTree.md +584 -0
  15. package/bundle/components/CollapsibleTreeExtended.md +422 -0
  16. package/bundle/components/Dropdown.md +748 -346
  17. package/bundle/components/EmptyView.md +14 -15
  18. package/bundle/components/FooterPage.md +203 -0
  19. package/bundle/components/Gap.md +115 -57
  20. package/bundle/components/HeaderPage.md +226 -0
  21. package/bundle/components/HelpBox.md +45 -84
  22. package/bundle/components/ImageGallery.md +423 -0
  23. package/bundle/components/ImageGalleryExtended.md +606 -0
  24. package/bundle/components/LightBox.md +2252 -233
  25. package/bundle/components/List.md +216 -183
  26. package/bundle/components/ListActionItem.md +157 -0
  27. package/bundle/components/ListItem.md +276 -0
  28. package/bundle/components/ListItemControlsButton.md +103 -0
  29. package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
  30. package/bundle/components/ListItemSelectable.md +99 -0
  31. package/bundle/components/ListItemTable.md +390 -0
  32. package/bundle/components/ListMaster.md +876 -156
  33. package/bundle/components/ListMasterFooter.md +80 -0
  34. package/bundle/components/ListMasterHeader.md +86 -0
  35. package/bundle/components/ListSortable.md +153 -0
  36. package/bundle/components/ListSortableItem.md +175 -0
  37. package/bundle/components/ListTableItem.md +391 -0
  38. package/bundle/components/ModalWindow.md +427 -237
  39. package/bundle/components/MonthYearField.md +145 -109
  40. package/bundle/components/Notification.md +625 -155
  41. package/bundle/components/Overlay.md +271 -170
  42. package/bundle/components/Page.md +284 -186
  43. package/bundle/components/Pagination.md +206 -229
  44. package/bundle/components/Portal.md +131 -67
  45. package/bundle/components/Row.md +171 -69
  46. package/bundle/components/Text.md +320 -0
  47. package/bundle/components/TextField.md +364 -97
  48. package/bundle/components/Title.md +296 -0
  49. package/bundle/guides/codestyle.md +38 -11
  50. package/bundle/guides/commits.md +119 -26
  51. package/bundle/guides/context.md +34 -30
  52. package/bundle/guides/stories.md +110 -40
  53. package/bundle/guides/template.md +3 -7
  54. package/bundle/guides/tests.md +48 -2
  55. package/bundle/manifest.json +275 -30
  56. package/bundle/release-notes/1.26.0.mdx +33 -2
  57. package/bundle/release-notes/1.27.0.mdx +43 -0
  58. package/bundle/release-notes/1.28.0.mdx +25 -0
  59. package/bundle/release-notes/1.29.0.mdx +47 -0
  60. package/bundle/release-notes/1.30.0.mdx +56 -0
  61. package/bundle/release-notes/1.31.0.mdx +52 -0
  62. package/bundle/release-notes/1.32.0.mdx +35 -0
  63. package/bundle/release-notes/1.33.0.mdx +61 -0
  64. package/bundle/release-notes/1.34.0.mdx +35 -0
  65. package/bundle/release-notes/1.35.0.mdx +21 -0
  66. package/bundle/release-notes/1.35.1.mdx +11 -0
  67. package/bundle/release-notes/1.36.0.mdx +21 -0
  68. package/bundle/release-notes/1.37.0.mdx +71 -0
  69. package/bundle/release-notes/1.38.0.mdx +36 -0
  70. package/bundle/release-notes/1.39.0.mdx +66 -0
  71. package/bundle/release-notes/1.40.0.mdx +27 -0
  72. package/bundle/release-notes/1.41.0.mdx +7 -0
  73. package/package.json +1 -1
@@ -1,11 +1,9 @@
1
1
  ---
2
2
  component: TextField
3
- category: Form Controls
4
- figma-node: ""
5
- figma-file: ""
6
- related: [TextareaField, MaskedField, AmountField, FormField, TextFieldBase]
3
+ category: TextFields
4
+ related: [MaskedField, FormField, FormGroup, TextareaField, MonthYearField]
7
5
  tokens: []
8
- stories: stories/TextFields/TextField.stories.tsx
6
+ stories: stories/TextField/TextField.stories.tsx
9
7
  version: "1.0"
10
8
  ---
11
9
 
@@ -13,135 +11,101 @@ version: "1.0"
13
11
 
14
12
  ## Назначение
15
13
 
16
- Однострочное текстовое поле: тонкая обёртка над `TextFieldBase`,
17
- вставляющая `FormFieldInput` (`<input type="text">`). Также в этом
18
- бандле — `MaskedField` (с `FormFieldMaskedInput`), идентичная по
19
- структуре. Компактное представление поля поверх `FormGroup` + `FormField`.
14
+ Компонент текстового ввода — компактная альтернатива `FormGroup` для однострочного поля: input с плавающим лейблом, префиксом/постфиксом, описанием и счётчиком символов в одном компоненте. Композиция над семейством `FormField` (`FormGroup` → `FormField` → `FormFieldInput` + `FormFieldLabel`/`FormFieldPrefix`/`FormFieldPostfix`/`FormFieldDescription`/`FormFieldCounter`).
20
15
 
21
- Используй когда: нужен стандартный однострочный ввод с label/description/
22
- prefix/postfix/counter. Для многострочного — `TextareaField`. С маской —
23
- `MaskedField`. Для сумм — `AmountField`.
16
+ Используй когда: нужно однострочное текстовое поле с лейблом, статусом (error/warning/disabled), префиксом/постфиксом или описанием под полем.
24
17
 
25
- ---
26
-
27
- ## Файловая структура
28
-
29
- ```text
30
- src/components/TextField/
31
- ├── TextField.tsx # FC<ITextFieldProps>; TextFieldBase + FormFieldInput
32
- ├── MaskedField.tsx # FC<IMaskedFieldProps>; TextFieldBase + FormFieldMaskedInput
33
- ├── TextFieldBase.tsx # forwardRef<HTMLDivElement, ITextFieldBaseProps>; общая структура
34
- └── index.ts # export TextField, MaskedField
35
- ```
18
+ Не используй когда: нужен ввод с маской (`MaskedField`), многострочный ввод (`TextareaField`), денежная сумма (`AmountField`), выбор из подсказок (`SuggestField`) или полноформатная форма с раздельными label/field-блоками (`FormGroup` + `FormField` напрямую).
36
19
 
37
20
  ---
38
21
 
39
- ## Публичный API
22
+ ## Варианты и props
40
23
 
41
- ### `ITextFieldProps`
24
+ `TextField` — тонкая обёртка: `inputProps` уходит в `FormFieldInput`, остальные props — в `TextFieldBase` (и далее в `FormField`). Собственного state нет.
42
25
 
43
- ```ts
44
- extends Omit<ITextFieldBaseProps, "children">
45
- {
46
- inputProps: IFormFieldInputProps & { ref?: RefObject<HTMLInputElement> };
47
- }
48
- ```
26
+ ### Обязательные props
49
27
 
50
28
  | Prop | Тип | Описание |
51
29
  |---|---|---|
52
- | `inputProps` | `IFormFieldInputProps & { ref? }` | **Обязателен**. Прокидывается на `FormFieldInput`. Может содержать `ref` на `<input>`. |
53
- | `label?` | `ReactNode` | Лейбл (плавающий). |
54
- | `description?` | `ReactNode` | Описание / текст ошибки. |
55
- | `counter?` | `ReactNode` | Счётчик символов (внутри description). |
56
- | `prefix?` / `postfix?` | `ReactNode` | Префикс/постфикс (иконка, кнопка, текст). |
57
- | `...IFormFieldProps` | — | size, status, disabled, focused, error и т.д. от `FormField`. |
58
-
59
- ### `IMaskedFieldProps`
60
-
61
- ```ts
62
- extends Omit<ITextFieldBaseProps, "children">
63
- {
64
- maskedInputProps: IFormFieldMaskedInputProps & { ref?: RefObject<HTMLInputElement> };
65
- }
66
- ```
30
+ | `inputProps` | `IFormFieldInputProps & { ref? }` | Свойства input: все стандартные атрибуты `<input>` (`value`, `onChange`, `placeholder`, `maxLength`…), `ref` на `HTMLInputElement`, а также render-prop `render` для подмены инпута (кастомная валидация, маска) с сохранением стилизации. |
67
31
 
68
- Идентична `ITextFieldProps`, но input с маской.
32
+ ### Опциональные props
69
33
 
70
- ### `ITextFieldBaseProps`
34
+ | Prop | Тип | По умолчанию | Описание |
35
+ |---|---|---|---|
36
+ | `size` | `EComponentSize` | `LG` | Размер поля: SM / MD / LG. |
37
+ | `status` | `EFormFieldStatus` | `DEFAULT` | Статус: default / error / warning / disabled. `DISABLED` автоматически ставит `disabled` на input. |
38
+ | `active` | `boolean` | `false` | Принудительно активное (focused) визуальное состояние рамки. |
39
+ | `label` | `ReactNode` | — | Плавающий лейбл; связывается с input через `htmlFor`. |
40
+ | `prefix` | `ReactNode` | — | Контент слева от input (иконка и т.п.), рендерится в `FormFieldPrefix`. |
41
+ | `postfix` | `ReactNode` | — | Контент справа от input (иконка, `FormFieldClear`, `HelpBox`), рендерится в `FormFieldPostfix`. |
42
+ | `description` | `ReactNode` | — | Описание под полем (`FormFieldDescription`); цвет наследует статус. |
43
+ | `counter` | `ReactNode` | — | Счётчик символов справа под полем (`FormFieldCounter`). Блок описания рендерится, если задан `description` ИЛИ `counter`. |
71
44
 
72
- ```ts
73
- extends Omit<IFormFieldProps, "prefix" | "postfix">
74
- {
75
- children: ReactNode; // обязателен — само поле ввода
76
- description?: ReactNode;
77
- counter?: ReactNode;
78
- prefix?: ReactNode;
79
- postfix?: ReactNode;
80
- label?: ReactNode;
81
- }
82
- ```
45
+ Остальные неперечисленные props (`className`, data-атрибуты, div-атрибуты) пробрасываются на корневой `FormField` (div).
46
+
47
+ ### Особенности поведения
83
48
 
84
- `TextFieldBase` — `forwardRef<HTMLDivElement>`. Используется напрямую,
85
- если нужен кастомный input (не Input/Masked/Textarea).
49
+ - Состояние «заполнено» (floating label) вычисляется внутри `FormFieldInput` из `value`/`defaultValue`/событий, включая браузерное автозаполнение (через CSS-анимационные хуки `autofill-*`). Потребителю управлять им не нужно.
50
+ - Ограничение длины ввода (для связки с `counter`) — на стороне потребителя: `inputProps.maxLength` или контролируемый `onChange`.
51
+ - Кнопка очистки не встроена — передаётся потребителем как `postfix={<FormFieldClear onClick={...} />}`.
86
52
 
87
53
  ---
88
54
 
89
- ## Структура DOM
55
+ ## Дизайн-токены
90
56
 
91
- ```tsx
92
- <FormGroup>
93
- <FormField {...formFieldProps} ref={ref}>
94
- {prefix && <FormFieldPrefix>{prefix}</FormFieldPrefix>}
95
- {children} {/* FormFieldInput / MaskedInput / Textarea */}
96
- {label && <FormFieldLabel>{label}</FormFieldLabel>}
97
- {postfix && <FormFieldPostfix>{postfix}</FormFieldPostfix>}
98
- </FormField>
99
- {(description || counter) && (
100
- <FormFieldDescription>
101
- {description}
102
- {counter && <FormFieldCounter>{counter}</FormFieldCounter>}
103
- </FormFieldDescription>
104
- )}
105
- </FormGroup>
106
- ```
57
+ Собственных CSS-токенов и стилей нет. Внешний вид полностью наследуется от семейства `FormField` (токены `--triplex-next-FormField-*` описаны в стилях `src/components/FormField/styles/`).
107
58
 
108
59
  ---
109
60
 
110
61
  ## Инварианты
111
62
 
112
- - **`TextField` / `MaskedField` — `FC, не forwardRef`**. Ref на `<input>` — через `inputProps.ref` / `maskedInputProps.ref`. `TextFieldBase` — `forwardRef<HTMLDivElement>` (сохранять).
113
- - **`inputProps` / `maskedInputProps` обязательны** — нельзя default'ить.
114
- - **Label рендерится после children в DOM** — требование `FormField` (плавающий лейбл через CSS), не менять порядок.
115
- - **`description` и `counter` объединены в одну `FormFieldDescription`** — counter внутри `<FormFieldCounter>`. Не дублировать обёртку.
116
- - **`prefix` / `postfix` поддерживаются `TextFieldBase` напрямую** (`Omit<IFormFieldProps, "prefix" | "postfix">` → переопределяет на ReactNode).
117
- - **`displayName` выставлен** на `TextField`, `MaskedField`, `TextFieldBase`.
118
- - **`MaskedField` отличается ТОЛЬКО типом input'а** — никакой собственной логики маскирования, она внутри `FormFieldMaskedInput`.
63
+ - `forwardRef` на `TextField` и `TextFieldBase` — не убирать. Внешний `ref` указывает на корневой `<div>` `FormField`; ref на сам input — только через `inputProps.ref`.
64
+ - Публичный API (`ITextFieldProps`: `inputProps` + `label`/`prefix`/`postfix`/`description`/`counter` + унаследованные `size`/`status`/`active`) — изменение имён/типов/значений enum — breaking change.
65
+ - Barrel `index.ts` экспортирует `TextField` и `MaskedField` — состав экспортов не менять. `TextFieldBase` намеренно НЕ экспортируется — приватная база.
66
+ - Известное ограничение контракта: `inputProps.ref` типизирован как `React.RefObject<HTMLInputElement>` (не `React.Ref`), callback-ref формально не проходит по типам. Исправление — breaking change, требует отдельной задачи.
67
+ - Уникальный `id` для связки label↔input генерируется через `lodash uniqueId` в `FormFieldInput` — не заменять на `useId` (React 17 совместимость через release-0).
68
+ - `description || counter` рендерятся в общем блоке `FormFieldDescription` — не разносить по отдельным блокам (изменит DOM и скриншоты).
119
69
 
120
70
  ---
121
71
 
122
72
  ## Accessibility
123
73
 
124
- - `<input>` (или masked input) — приходит из `FormFieldInput`, отвечает за `id`, `aria-describedby`, `aria-invalid`.
125
- - `<label htmlFor>` — связь с input'ом через `FormFieldLabel`/`FormField`.
126
- - Описание/ошибка — через `description` (попадает в `FormFieldDescription`), `aria-describedby` подвязывается автоматически.
127
- - `disabled`/`readonly`/`required` — на `inputProps`.
74
+ - Лейбл — настоящий `<label htmlFor>` связанный с `id` инпута (id генерируется автоматически или берётся из `inputProps.id`).
75
+ - `status={EFormFieldStatus.DISABLED}` выставляет нативный атрибут `disabled` на input — поле выпадает из таб-обхода штатно.
76
+ - Семантика ошибки (`aria-invalid`, `aria-describedby` на description) не хардкодится — при необходимости потребитель передаёт атрибуты через `inputProps`.
77
+ - Специальной клавиатурной логики нет — стандартное поведение `<input>`.
128
78
 
129
79
  ---
130
80
 
131
81
  ## Связанные компоненты
132
82
 
133
- - `TextareaField` — многострочный аналог.
134
- - `MaskedField` — экспортируется отсюда же; ввод по маске.
135
- - `AmountField` — для денежных сумм.
136
- - `TextFieldBase` — общая база (используется напрямую при кастомном input'е).
137
- - `FormField`, `FormGroup`, `FormFieldInput`, `FormFieldMaskedInput`, `FormFieldLabel`, `FormFieldDescription`, `FormFieldCounter`, `FormFieldPrefix`, `FormFieldPostfix` — внутренние составляющие.
83
+ - `TextFieldBase` (внутренний, не в barrel) — базовая раскладка `FormGroup`/`FormField` + слоты `prefix`/`children`/`label`/`postfix` и блок `description`/`counter`. На нём построены `TextField` и `MaskedField`. Описан здесь, отдельного AI.md не имеет.
84
+ - `MaskedField` — сосед по папке: то же самое, но с `FormFieldMaskedInput` (ввод по маске) через prop `maskedInputProps`. Документируется отдельно.
85
+ - `FormField` / `FormFieldInput` и слоты семейства — низкоуровневые строительные блоки; используются напрямую, когда нужна нестандартная композиция.
86
+ - `FormGroup` — контейнер вертикальной раскладки поля и описания.
87
+ - `FormFieldClear` — кнопка очистки, передаётся в `postfix`.
88
+ - `TextareaField`, `AmountField`, `SuggestField`, `DateField`, `MonthYearField` — специализированные поля той же группы `TextFields`.
138
89
 
139
90
  ---
140
91
 
141
92
  ## Stories
142
93
 
143
- Основные истории: `stories/TextFields/TextField.stories.tsx` (а также `MaskedField.stories.tsx`, `AmountField.stories.tsx` рядом).
144
- Примеры: `stories/TextFields/examples/`.
94
+ Основные истории: `stories/TextField/TextField.stories.tsx`
95
+ Файлы примеров: `stories/TextField/examples/`
96
+
97
+ | Story | Example file | Что демонстрирует |
98
+ |---|---|---|
99
+ | `Playground` | `Playground.tsx` | Интерактивный контроль size / status / label / prefix / postfix / description / counter |
100
+ | `Default` | `Default.tsx` | Минимальное контролируемое поле с label и placeholder |
101
+ | `Sizes` | `Sizes.tsx` | Размеры SM / MD / LG |
102
+ | `Statuses` | `Statuses.tsx` | Статусы default / error / warning / disabled с description соответствующего типа |
103
+ | `WithPrefixAndPostfix` | `WithPrefixAndPostfix.tsx` | Иконки в префиксе и постфиксе |
104
+ | `WithClearButton` | `WithClearButton.tsx` | Кнопка очистки `FormFieldClear` в постфиксе |
105
+ | `WithCounter` | `WithCounter.tsx` | Описание и счётчик символов под полем |
106
+ | `PassRefToInput` | `PassRefToInput.tsx` | Проброс ref на input через `inputProps.ref` |
107
+ | `Production` | `Production.tsx` | Production-композиция (`Example: production`): `HelpBox` в постфиксе, description со ссылкой, лимит длины со счётчиком, кнопка очистки |
108
+ | `VisualTests` | `VisualTests.tsx` | Скриншот-регрессия: фокус (через `play`), заполненные размеры, prefix/postfix, description/counter, статусы |
145
109
 
146
110
  ---
147
111
 
@@ -149,4 +113,307 @@ extends Omit<IFormFieldProps, "prefix" | "postfix">
149
113
 
150
114
  | Дата | Изменение |
151
115
  |---|---|
152
- | 2026-04-18 | Создан документ |
116
+ | 2026-07-27 | Создан документ (TRI-5). AI-рефакторинг TextField/TextFieldBase, unit-тесты, миграция stories на modern pattern |
117
+
118
+ ---
119
+
120
+ ## Примеры использования
121
+
122
+ ### Default
123
+
124
+ `stories/TextField/examples/Default.tsx`
125
+
126
+ ```tsx
127
+ import React, { useState } from "react";
128
+ import { TextField } from "@sberbusiness/triplex-next";
129
+
130
+ export const Default = () => {
131
+ const [value, setValue] = useState("");
132
+
133
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
134
+
135
+ return (
136
+ <div style={{ maxWidth: "300px" }}>
137
+ <TextField label="Label" inputProps={{ value, onChange: handleChange, placeholder: "Type to proceed" }} />
138
+ </div>
139
+ );
140
+ };
141
+ ```
142
+
143
+ ### Sizes
144
+
145
+ `stories/TextField/examples/Sizes.tsx`
146
+
147
+ ```tsx
148
+ import React, { useState } from "react";
149
+ import { TextField, EComponentSize } from "@sberbusiness/triplex-next";
150
+
151
+ interface ISizeItemProps {
152
+ size: EComponentSize;
153
+ }
154
+
155
+ const SizeItem = ({ size }: ISizeItemProps) => {
156
+ const [value, setValue] = useState("");
157
+
158
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
159
+
160
+ return (
161
+ <div>
162
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>{size.toUpperCase()}</div>
163
+ <TextField
164
+ size={size}
165
+ label="Label"
166
+ inputProps={{ value, onChange: handleChange, placeholder: "Type to proceed" }}
167
+ />
168
+ </div>
169
+ );
170
+ };
171
+
172
+ const SIZES = Object.values(EComponentSize);
173
+
174
+ export const Sizes = () => (
175
+ <div style={{ maxWidth: "300px", display: "flex", flexDirection: "column", gap: "16px" }}>
176
+ {SIZES.map((size) => (
177
+ <SizeItem key={size} size={size} />
178
+ ))}
179
+ </div>
180
+ );
181
+ ```
182
+
183
+ ### Statuses
184
+
185
+ `stories/TextField/examples/Statuses.tsx`
186
+
187
+ ```tsx
188
+ import React, { useState } from "react";
189
+ import { TextField, Text, EFormFieldStatus, ETextSize, EFontType } from "@sberbusiness/triplex-next";
190
+
191
+ interface IStatusItemProps {
192
+ status: EFormFieldStatus;
193
+ description: string;
194
+ descriptionType: EFontType;
195
+ }
196
+
197
+ const StatusItem = ({ status, description, descriptionType }: IStatusItemProps) => {
198
+ const [value, setValue] = useState("");
199
+
200
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
201
+
202
+ return (
203
+ <div>
204
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>{status.toUpperCase()}</div>
205
+ <TextField
206
+ status={status}
207
+ label="Label"
208
+ description={
209
+ <Text tag="div" size={ETextSize.B4} type={descriptionType}>
210
+ {description}
211
+ </Text>
212
+ }
213
+ inputProps={{ value, onChange: handleChange, placeholder: "Type to proceed" }}
214
+ />
215
+ </div>
216
+ );
217
+ };
218
+
219
+ const STATUSES: Array<IStatusItemProps> = [
220
+ { status: EFormFieldStatus.DEFAULT, description: "(21) Description", descriptionType: EFontType.SECONDARY },
221
+ { status: EFormFieldStatus.ERROR, description: "Error text", descriptionType: EFontType.ERROR },
222
+ { status: EFormFieldStatus.WARNING, description: "Warning text", descriptionType: EFontType.WARNING },
223
+ { status: EFormFieldStatus.DISABLED, description: "(21) Description", descriptionType: EFontType.SECONDARY },
224
+ ];
225
+
226
+ export const Statuses = () => (
227
+ <div style={{ maxWidth: "300px", display: "flex", flexDirection: "column", gap: "16px" }}>
228
+ {STATUSES.map((item) => (
229
+ <StatusItem key={item.status} {...item} />
230
+ ))}
231
+ </div>
232
+ );
233
+ ```
234
+
235
+ ### WithPrefixAndPostfix
236
+
237
+ `stories/TextField/examples/WithPrefixAndPostfix.tsx`
238
+
239
+ ```tsx
240
+ import React, { useState } from "react";
241
+ import { TextField, HelpBox, ETooltipSize, ETooltipPreferPlace } from "@sberbusiness/triplex-next";
242
+ import { DefaulticonStrokePrdIcon24 } from "@sberbusiness/icons-next";
243
+
244
+ export const WithPrefixAndPostfix = () => {
245
+ const [value, setValue] = useState("");
246
+
247
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
248
+
249
+ return (
250
+ <div style={{ maxWidth: "300px" }}>
251
+ <TextField
252
+ label="Label"
253
+ prefix={<DefaulticonStrokePrdIcon24 paletteIndex={5} />}
254
+ postfix={
255
+ <HelpBox tooltipSize={ETooltipSize.SM} preferPlace={ETooltipPreferPlace.ABOVE}>
256
+ Text
257
+ </HelpBox>
258
+ }
259
+ inputProps={{ value, onChange: handleChange, placeholder: "Type to proceed" }}
260
+ />
261
+ </div>
262
+ );
263
+ };
264
+ ```
265
+
266
+ ### WithClearButton
267
+
268
+ `stories/TextField/examples/WithClearButton.tsx`
269
+
270
+ ```tsx
271
+ import React, { useState } from "react";
272
+ import { TextField, FormFieldClear } from "@sberbusiness/triplex-next";
273
+
274
+ export const WithClearButton = () => {
275
+ const [value, setValue] = useState("");
276
+
277
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
278
+
279
+ return (
280
+ <div style={{ maxWidth: "300px" }}>
281
+ <TextField
282
+ label="Label"
283
+ postfix={<FormFieldClear onClick={() => setValue("")} />}
284
+ inputProps={{ value, onChange: handleChange, placeholder: "Type to proceed" }}
285
+ />
286
+ </div>
287
+ );
288
+ };
289
+ ```
290
+
291
+ ### WithCounter
292
+
293
+ `stories/TextField/examples/WithCounter.tsx`
294
+
295
+ ```tsx
296
+ import React, { useState } from "react";
297
+ import { TextField, Text, ETextSize, EFontType } from "@sberbusiness/triplex-next";
298
+
299
+ const MAX_LENGTH = 201;
300
+
301
+ export const WithCounter = () => {
302
+ const [value, setValue] = useState("");
303
+
304
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
305
+ if (event.target.value.length <= MAX_LENGTH) {
306
+ setValue(event.target.value);
307
+ }
308
+ };
309
+
310
+ return (
311
+ <div style={{ maxWidth: "300px" }}>
312
+ <TextField
313
+ label="Label"
314
+ description={
315
+ <Text tag="div" size={ETextSize.B4} type={EFontType.SECONDARY}>
316
+ (21) Description
317
+ </Text>
318
+ }
319
+ counter={
320
+ <Text tag="div" size={ETextSize.B4} type={EFontType.SECONDARY}>
321
+ {value.length}/{MAX_LENGTH}
322
+ </Text>
323
+ }
324
+ inputProps={{ value, onChange: handleChange, maxLength: MAX_LENGTH, placeholder: "Type to proceed" }}
325
+ />
326
+ </div>
327
+ );
328
+ };
329
+ ```
330
+
331
+ ### PassRefToInput
332
+
333
+ `stories/TextField/examples/PassRefToInput.tsx`
334
+
335
+ ```tsx
336
+ import React, { useRef, useState } from "react";
337
+ import { TextField } from "@sberbusiness/triplex-next";
338
+
339
+ export const PassRefToInput = () => {
340
+ const [value, setValue] = useState("");
341
+ const ref = useRef<HTMLInputElement>(null);
342
+
343
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
344
+
345
+ return (
346
+ <div style={{ maxWidth: "300px" }}>
347
+ <TextField
348
+ label="Label"
349
+ inputProps={{ ref, value, onChange: handleChange, placeholder: "Type to proceed" }}
350
+ />
351
+ </div>
352
+ );
353
+ };
354
+ ```
355
+
356
+ ### Production
357
+
358
+ `stories/TextField/examples/Production.tsx`
359
+
360
+ ```tsx
361
+ import React, { useState } from "react";
362
+ import {
363
+ TextField,
364
+ FormFieldClear,
365
+ HelpBox,
366
+ Text,
367
+ Link,
368
+ ETooltipSize,
369
+ ETooltipPreferPlace,
370
+ ETextSize,
371
+ EFontType,
372
+ } from "@sberbusiness/triplex-next";
373
+ import { DefaulticonStrokePrdIcon24 } from "@sberbusiness/icons-next";
374
+
375
+ const MAX_LENGTH = 201;
376
+
377
+ export const Production = () => {
378
+ const [value, setValue] = useState("");
379
+
380
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
381
+ if (event.target.value.length <= MAX_LENGTH) {
382
+ setValue(event.target.value);
383
+ }
384
+ };
385
+
386
+ return (
387
+ <div style={{ maxWidth: "300px" }}>
388
+ <TextField
389
+ label="Label"
390
+ description={
391
+ <Text tag="div" size={ETextSize.B4} type={EFontType.SECONDARY}>
392
+ (21) Description{" "}
393
+ <Link href="#" onClick={(event) => event.preventDefault()}>
394
+ Link text
395
+ </Link>
396
+ </Text>
397
+ }
398
+ counter={
399
+ <Text tag="div" size={ETextSize.B4} type={EFontType.SECONDARY}>
400
+ {value.length}/{MAX_LENGTH}
401
+ </Text>
402
+ }
403
+ prefix={<DefaulticonStrokePrdIcon24 paletteIndex={5} />}
404
+ postfix={
405
+ <>
406
+ <FormFieldClear onClick={() => setValue("")} />
407
+ <DefaulticonStrokePrdIcon24 paletteIndex={5} />
408
+ <HelpBox tooltipSize={ETooltipSize.SM} preferPlace={ETooltipPreferPlace.ABOVE}>
409
+ Text
410
+ </HelpBox>
411
+ </>
412
+ }
413
+ inputProps={{ value, onChange: handleChange, placeholder: "Type to proceed" }}
414
+ />
415
+ </div>
416
+ );
417
+ };
418
+ ```
419
+