Пошаговая форма
Сделай трёхшаговую форму регистрации: шаги «Контакты», «Адрес», «Проверка». Сверху показывай индикатор текущего шага, снизу кнопки «Назад» и «Дальше», на последнем шаге кнопка «Отправить» вызывает переданный колбэк onSubmit.
wizard__docs__claude-code__claude-opus-5__1 · 23.09.2026, 20:18:02 мск
Проверки пройдены
Доки · claude-opus-5 · Claude CodeКонтекст до задачи~22 702
Токенов на прогон49 010
Цена$0.290
Ошибок компилятора0
Первый вызов модели получил 47 358 токенов входа, включая системный промпт Claude Code. Контекст до задачи — оценка по длине текста, для русского текста она занижает число токенов в полтора-два раза.
Компилятор
Ошибок нет: все компоненты и пропсы существуют.
Линтер и покрытие
- inline-styleСтроки 45, 49, 70, 97, 99, 100, 102, 106, 107, 109, 113, 121Инлайновые стили вместо классов и токенов библиотеки
Компоненты библиотеки
JxButton, JxDivider, JxInputField, JxStepper, JxTextareaField
Ожидались JxStepper, JxButton, JxInputField · покрытие 100%
Доки (llms-full.txt, ~22548)
Вход 2 · выход 1 652 · из кэша 8 233 · в кэш 39 123 · 17 с
Рендер
Код компонента
tsx137 строк
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
import { useState } from 'react';
import {
JxStepper,
JxInputField,
JxTextareaField,
JxButton,
JxDivider,
} from '@jinx-ui/react';
interface RegistrationData {
name: string;
email: string;
city: string;
street: string;
comment: string;
}
interface RegistrationWizardProps {
onSubmit: (data: RegistrationData) => void;
}
const steps = [{ label: 'Контакты' }, { label: 'Адрес' }, { label: 'Проверка' }];
export default function RegistrationWizard({ onSubmit }: RegistrationWizardProps) {
const [step, setStep] = useState(0);
const [data, setData] = useState<RegistrationData>({
name: '',
email: '',
city: '',
street: '',
comment: '',
});
const set = <K extends keyof RegistrationData>(key: K, value: RegistrationData[K]) =>
setData((prev) => ({ ...prev, [key]: value }));
const emailError =
data.email.length > 0 && !data.email.includes('@') ? 'Укажите адрес с символом @' : undefined;
const contactsReady = data.name.trim().length > 0 && data.email.includes('@');
const addressReady = data.city.trim().length > 0 && data.street.trim().length > 0;
const canGoNext = step === 0 ? contactsReady : step === 1 ? addressReady : true;
return (
<div style={{ display: 'grid', gap: '20px', fontFamily: 'var(--jx-font-sans)', color: 'var(--jx-text)' }}>
<JxStepper steps={steps} current={step} />
{step === 0 && (
<div style={{ display: 'grid', gap: '12px' }}>
<JxInputField
label="Имя"
required
autoComplete="name"
value={data.name}
onChange={(event) => set('name', event.target.value)}
/>
<JxInputField
label="Электронная почта"
type="email"
required
autoComplete="email"
value={data.email}
onChange={(event) => set('email', event.target.value)}
errorText={emailError}
/>
</div>
)}
{step === 1 && (
<div style={{ display: 'grid', gap: '12px' }}>
<JxInputField
label="Город"
required
autoComplete="address-level2"
value={data.city}
onChange={(event) => set('city', event.target.value)}
/>
<JxInputField
label="Улица и дом"
required
autoComplete="street-address"
value={data.street}
onChange={(event) => set('street', event.target.value)}
/>
<JxTextareaField
label="Комментарий к доставке"
rows={3}
maxLength={300}
value={data.comment}
onChange={(event) => set('comment', event.target.value)}
helperText={`${data.comment.length}/300`}
/>
</div>
)}
{step === 2 && (
<div style={{ display: 'grid', gap: '8px' }}>
<JxDivider label="Контакты" />
<div style={{ display: 'grid', gap: '4px' }}>
<span style={{ color: 'var(--jx-text-2)' }}>Имя</span>
<span>{data.name}</span>
<span style={{ color: 'var(--jx-text-2)' }}>Почта</span>
<span>{data.email}</span>
</div>
<JxDivider label="Адрес" />
<div style={{ display: 'grid', gap: '4px' }}>
<span style={{ color: 'var(--jx-text-2)' }}>Город</span>
<span>{data.city}</span>
<span style={{ color: 'var(--jx-text-2)' }}>Улица и дом</span>
<span>{data.street}</span>
{data.comment && (
<>
<span style={{ color: 'var(--jx-text-2)' }}>Комментарий</span>
<span>{data.comment}</span>
</>
)}
</div>
</div>
)}
<div style={{ display: 'flex', gap: '8px' }}>
<JxButton variant="ghost" disabled={step === 0} onClick={() => setStep(step - 1)}>
Назад
</JxButton>
{step < steps.length - 1 ? (
<JxButton variant="primary" disabled={!canGoNext} onClick={() => setStep(step + 1)}>
Дальше
</JxButton>
) : (
<JxButton variant="primary" onClick={() => onSubmit(data)}>
Отправить
</JxButton>
)}
</div>
</div>
);
}