Пошаговая форма

Сделай трёхшаговую форму регистрации: шаги «Контакты», «Адрес», «Проверка». Сверху показывай индикатор текущего шага, снизу кнопки «Назад» и «Дальше», на последнем шаге кнопка «Отправить» вызывает переданный колбэк 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>
  );
}