FieldStepper
Числовое поле для выбора значения шагами через кнопки − / + и/или прямой ввод. Базируется на FieldDecorator поверх <input type="number"> без нативных стрелочек. Кнопки − и + — buttonField-слоты по краям поля, отделённые от значения вертикальными разделителями; фон (acrylic) общий для кнопок и инпута.
Когда использовать
- Количество товара в корзине, кол-во гостей, штучные параметры.
- Числовые настройки с понятным шагом (вес, объём, время в минутах).
- Когда дискретные значения уместнее ползунка
Slider(есть осмысленный «один тик»).
Анатомия
Size (default m)
| Значение | Когда |
|---|---|
s | Inline-формы и таблицы |
m | Стандартные формы (по умолчанию) |
l | Лендинги, primary-формы |
ValidationState (default default)
Через проп error форсится error.
| Значение | Когда |
|---|---|
default | Нет валидации — нейтральный baseline без подсветки и иконки; зелёный сигнал даёт только success |
error | Не прошло валидацию |
warning | Предупреждение |
success | Подтверждение |
Кнопки −/+
Кнопки шага — buttonField-слоты по краям поля, а не отдельные элементы вне инпута.
−— слот слева, отделён от значения вертикальнымDivider.+— слот справа, отделён от значения вертикальнымDivider.
Кнопки не участвуют в табуляции (tabIndex={-1}) — фокус принимает сам инпут. Фон (acrylic) общий для кнопок, разделителей и инпута: на hover/focus подсвечивается единым слоем.
Поведение
| Проп | Поведение |
|---|---|
min / max | Ограничивают кнопки − / +; кнопки становятся disabled на границе |
step | Шаг изменения (default 1); поддерживает дробные значения через fixed-precision |
allowMoreThanLimits | false — клампит значение к min/max на blur после ручного ввода |
prefix / postfix | Произвольная нода рядом со значением (валюта, единица измерения) |
Тултипы
minusButtonTooltip/plusButtonTooltip—TooltipPropsдля подсказки над соответствующей кнопкой шага.clampTooltipText— тексты тултипа клампа. Показывается на 2 секунды после blur, когда вручную введённое значение вышло заmin(clampTooltipText.min(value)) илиmax(clampTooltipText.max(value)) приallowMoreThanLimits={false}. По умолчанию —Значение должно быть больше либо равно {value}для нижней границы иЗначение должно быть меньше либо равно {value}для верхней.
Установка
pnpm add @cloud-ru/ds-fields
import { FieldStepper } from '@cloud-ru/ds-fields'
Controlled vs uncontrolled
FieldStepper работает в двух режимах:
- Controlled — передаётся
value+onChange. Состояние держит потребитель, компонент только отображает текущее значение. - Uncontrolled — передаётся
defaultValue(или ничего; тогда начальное значение выводится изmin/max). Компонент держит состояние внутри,onChangeостаётся опциональным для наблюдения.
Не смешивайте режимы: либо value, либо defaultValue.
Примеры использования
Базовый stepper
tsx
import { FieldStepper } from '@cloud-ru/ds-fields';
import { useState } from 'react';
export function Stepper() {
const [value, setValue] = useState(1);
return <FieldStepper label='Количество' value={value} onChange={setValue} />;
}Uncontrolled
шт
tsx
import { FieldStepper } from '@cloud-ru/ds-fields';
export function StepperUncontrolled() {
return <FieldStepper label='Количество' postfix='шт' defaultValue={3} min={0} max={10} />;
}С единицей измерения
шт
tsx
import { FieldStepper } from '@cloud-ru/ds-fields';
import { useState } from 'react';
export function StepperWithPostfix() {
const [value, setValue] = useState(12);
return <FieldStepper label='Количество' postfix='шт' value={value} onChange={setValue} />;
}Min/Max с клампом
От 0 до 120
tsx
import { FieldStepper } from '@cloud-ru/ds-fields';
import { useState } from 'react';
export function StepperLimits() {
const [value, setValue] = useState(0);
return (
<FieldStepper
label='Возраст'
hint='От 0 до 120'
min={0}
max={120}
allowMoreThanLimits={false}
value={value}
onChange={setValue}
/>
);
}Дробный шаг
кг
tsx
import { FieldStepper } from '@cloud-ru/ds-fields';
import { useState } from 'react';
export function StepperFractional() {
const [value, setValue] = useState(1.5);
return <FieldStepper label='Вес' postfix='кг' step={0.5} min={0} max={20} value={value} onChange={setValue} />;
}Тултипы кнопок и клампа
Наведите на кнопки −/+; превышение границ показывает тултип на blur
tsx
import { FieldStepper } from '@cloud-ru/ds-fields';
import { useState } from 'react';
export function StepperTooltips() {
const [value, setValue] = useState(3);
return (
<FieldStepper
label='Количество'
hint='Наведите на кнопки −/+; превышение границ показывает тултип на blur'
min={0}
max={10}
allowMoreThanLimits={false}
value={value}
onChange={setValue}
minusButtonTooltip={{ tip: 'Уменьшить' }}
plusButtonTooltip={{ tip: 'Увеличить' }}
clampTooltipText={{
min: limit => `Не меньше ${limit}`,
max: limit => `Не больше ${limit}`,
}}
/>
);
}Props
Types
Props
FieldStepperProps| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
allowMoreThanLimits | boolean | true | no | Разрешить ввод значений вне `min`/`max`. Если `false`, на blur значение клампится. |
autoFocus | boolean | — | no | Автофокус. На mobile выключается адаптивно (см. `layoutPresets`) |
background | boolean | true | no | Фон поля (acrylic) |
caption | string | — | no | Вторичная подпись справа |
clampTooltipText | { min?: ((value: number) => string); max?: ((value: number) => string); } | undefined | { min: 'Значен ие должно быть больше либо равно {value}', max: 'Значение должно быть меньше либо равно {value}' } | no | Тексты тултипа клампа (показывается на 2с после blur с выходом за `min`/`max`). |
className | string | — | no | CSS-класс CSS-класс корня `FieldDecorator` |
data-test-id | string | — | no | |
defaultValue | number | — | no | Начальное значение (uncontrolled-режим). По умолчанию выводится из `min`/`max`. |
disabled | boolean | — | no | Поле выключено |
error | string | — | no | Ошибка (приоритетнее `hint`; форсит `validationState=error`) |
fieldClassName | string | — | no | CSS-класс оболочки поля |
hint | string | — | no | Подсказка |
id | string | — | no | HTML id |
innerRef | Ref<HTMLDivElement> | — | no | Ref на корневой DOM-элемент |
label | string | | no | Заголовок |
labelFor | string | — | no | HTML-атрибут `for` для `<label>` |
labelTooltip | QuestionTooltipProps | — | no | Подсказка (question-tooltip) у заголовка |
layoutPresets | Partial<Record<LayoutType, Partial<{ autoFocus: boolean; }>>> | — | no | Переопределение адаптивных дефолтов по раскладке. Участвует `autoFocus`: на mobile он выключен (открывает клавиатуру без действия). Вернуть на mobile — `layoutPresets={{ mobile: { autoFocus: true } }}`. |
length | FieldLength | — | no | Счётчик длины `current/max` |
max | number | — | no | Максимум |
min | number | — | no | Минимум |
minusButtonTooltip | TooltipProps | — | no | Тултип над кнопкой `−` |
name | string | — | no | HTML name |
onBlur | ((event: FocusEvent<HTMLInputElement, Element>) => void) | — | no | Колбек блюра |
onChange | ((value: number, event?: ChangeEvent<HTMLInputElement>) => void) | — | no | Колбек смены значения. Второй аргумент — событие, если изменение пришло из ручного ввода. |
onCopyButtonClick | (() => void) | — | no | Колбек после успешного копирования значения. |
onFocus | ((event: FocusEvent<HTMLInputElement, Element>) => void) | — | no | Колбек фокуса |
plusButtonTooltip | TooltipProps | — | no | Тултип над кнопкой `+` |
postfix | ReactNode | — | no | Постфикс — текст или иконка справа от значения (например, единица измерения) |
prefix | ReactNode | — | no | Префикс — текст или иконка слева от значения |
readonly | boolean | — | no | Только для чтения |
required | boolean | — | no | Показать знак обязательности `*` |
showCopyButton | boolean | true | no | Показывать кнопку копирования значения (видна в readonly, при `!disabled`). |
showHintIcon | boolean | — | no | Отображение статус-иконки у подсказки (по умолчанию `true`) |
size | "l" | "m" | "s" | m | no | Размер |
step | number | 1 | no | Шаг приращения |
validationState | "default" | "error" | "success" | "warning" | default | no | Состояние валидации |
value | number | — | no | Значение (controlled-режим) |