@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.
- package/README.md +10 -0
- package/bundle/components/AlertContext.md +268 -0
- package/bundle/components/BodyPage.md +186 -0
- package/bundle/components/Button.md +93 -85
- package/bundle/components/ButtonDropdown.md +36 -70
- package/bundle/components/ButtonDropdownExtended.md +422 -0
- package/bundle/components/ButtonIcon.md +41 -48
- package/bundle/components/Caption.md +291 -0
- package/bundle/components/Checkbox.md +43 -122
- package/bundle/components/CheckboxXGroup.md +109 -46
- package/bundle/components/CheckboxYGroup.md +77 -49
- package/bundle/components/CodeText.md +197 -0
- package/bundle/components/Col.md +311 -162
- package/bundle/components/CollapsibleTree.md +584 -0
- package/bundle/components/CollapsibleTreeExtended.md +422 -0
- package/bundle/components/Dropdown.md +748 -346
- package/bundle/components/EmptyView.md +14 -15
- package/bundle/components/FooterPage.md +203 -0
- package/bundle/components/Gap.md +115 -57
- package/bundle/components/HeaderPage.md +226 -0
- package/bundle/components/HelpBox.md +45 -84
- package/bundle/components/ImageGallery.md +423 -0
- package/bundle/components/ImageGalleryExtended.md +606 -0
- package/bundle/components/LightBox.md +2252 -233
- package/bundle/components/List.md +216 -183
- package/bundle/components/ListActionItem.md +157 -0
- package/bundle/components/ListItem.md +276 -0
- package/bundle/components/ListItemControlsButton.md +103 -0
- package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
- package/bundle/components/ListItemSelectable.md +99 -0
- package/bundle/components/ListItemTable.md +390 -0
- package/bundle/components/ListMaster.md +876 -156
- package/bundle/components/ListMasterFooter.md +80 -0
- package/bundle/components/ListMasterHeader.md +86 -0
- package/bundle/components/ListSortable.md +153 -0
- package/bundle/components/ListSortableItem.md +175 -0
- package/bundle/components/ListTableItem.md +391 -0
- package/bundle/components/ModalWindow.md +427 -237
- package/bundle/components/MonthYearField.md +145 -109
- package/bundle/components/Notification.md +625 -155
- package/bundle/components/Overlay.md +271 -170
- package/bundle/components/Page.md +284 -186
- package/bundle/components/Pagination.md +206 -229
- package/bundle/components/Portal.md +131 -67
- package/bundle/components/Row.md +171 -69
- package/bundle/components/Text.md +320 -0
- package/bundle/components/TextField.md +364 -97
- package/bundle/components/Title.md +296 -0
- package/bundle/guides/codestyle.md +38 -11
- package/bundle/guides/commits.md +119 -26
- package/bundle/guides/context.md +34 -30
- package/bundle/guides/stories.md +110 -40
- package/bundle/guides/template.md +3 -7
- package/bundle/guides/tests.md +48 -2
- package/bundle/manifest.json +275 -30
- package/bundle/release-notes/1.26.0.mdx +33 -2
- package/bundle/release-notes/1.27.0.mdx +43 -0
- package/bundle/release-notes/1.28.0.mdx +25 -0
- package/bundle/release-notes/1.29.0.mdx +47 -0
- package/bundle/release-notes/1.30.0.mdx +56 -0
- package/bundle/release-notes/1.31.0.mdx +52 -0
- package/bundle/release-notes/1.32.0.mdx +35 -0
- package/bundle/release-notes/1.33.0.mdx +61 -0
- package/bundle/release-notes/1.34.0.mdx +35 -0
- package/bundle/release-notes/1.35.0.mdx +21 -0
- package/bundle/release-notes/1.35.1.mdx +11 -0
- package/bundle/release-notes/1.36.0.mdx +21 -0
- package/bundle/release-notes/1.37.0.mdx +71 -0
- package/bundle/release-notes/1.38.0.mdx +36 -0
- package/bundle/release-notes/1.39.0.mdx +66 -0
- package/bundle/release-notes/1.40.0.mdx +27 -0
- package/bundle/release-notes/1.41.0.mdx +7 -0
- package/package.json +1 -1
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: TextField
|
|
3
|
-
category:
|
|
4
|
-
|
|
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/
|
|
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
|
-
|
|
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
|
-
Используй когда:
|
|
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
|
-
##
|
|
22
|
+
## Варианты и props
|
|
40
23
|
|
|
41
|
-
|
|
24
|
+
`TextField` — тонкая обёртка: `inputProps` уходит в `FormFieldInput`, остальные props — в `TextFieldBase` (и далее в `FormField`). Собственного state нет.
|
|
42
25
|
|
|
43
|
-
|
|
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? }` |
|
|
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
|
-
|
|
32
|
+
### Опциональные props
|
|
69
33
|
|
|
70
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
`
|
|
85
|
-
|
|
49
|
+
- Состояние «заполнено» (floating label) вычисляется внутри `FormFieldInput` из `value`/`defaultValue`/событий, включая браузерное автозаполнение (через CSS-анимационные хуки `autofill-*`). Потребителю управлять им не нужно.
|
|
50
|
+
- Ограничение длины ввода (для связки с `counter`) — на стороне потребителя: `inputProps.maxLength` или контролируемый `onChange`.
|
|
51
|
+
- Кнопка очистки не встроена — передаётся потребителем как `postfix={<FormFieldClear onClick={...} />}`.
|
|
86
52
|
|
|
87
53
|
---
|
|
88
54
|
|
|
89
|
-
##
|
|
55
|
+
## Дизайн-токены
|
|
90
56
|
|
|
91
|
-
|
|
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
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
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
|
-
- `<
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
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
|
-
- `
|
|
134
|
-
- `MaskedField` —
|
|
135
|
-
- `
|
|
136
|
-
- `
|
|
137
|
-
- `
|
|
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/
|
|
144
|
-
|
|
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-
|
|
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
|
+
|