Компонент · рівень 1

OTP-комірка

Шість комірок для коду з SMS. Єдиний спосіб увійти в Stack: рішення 5 - вхід без пароля.

рівень 1design/system/components/otp.css35 рядківрендериться JS
Анатомія
Помилка - .err на всіх шести
Код діє 5 хвилин. Введеться автоматично, якщо телефон його підставить.
1Комірка - одна цифра, моношрифт, 60 заввишки
2Заповнена - .on - рамка чорнильна, бо цифра вже стоїть
3Активна - :focus - рамка акценту плюс кільце; клацніть будь-яку комірку вище, це жива розмітка
4Помилка - .err - усі шість червоніють разом, бо неправильний код цілий
5Пояснення - .otp-err - що сталось і скільки спроб лишилось. Рамка сама по собі не каже ні того, ні того
6Підпис - .otp-note - строк дії коду і обіцянка автопідставлення, яку autocomplete="one-time-code" і виконує

Комірки вище - розмітка продукту: шість <input class="box">, які будує wfOtp(), і жодного власного стилю. До кроку 7.13 тут стояли чотири <span> з дев'ятьма інлайн-властивостями кожен, і всі три виміряні числа розходились із файлом, який сторінка документує: висота 52 проти 60, радіус 10px проти --radius-12, кегль 20 проти --fs-24. Плюс width:44px програвав flex:1 з otp.css, тож комірка розтягувалась до 221px - специмен показував прямокутники там, де продукт показує квадрати. Ширину тепер тримає обгортка на 320, як діалог входу, а не інлайн на комірці.

Варіанти і розміри

Матриця осей, а не перелік входжень: кожен рядок це питання, на яке відповідає розмітка, і правило, за яким обирають.

ВісьЗначенняПравило вибору
Довжинашість комірокДовжина коду - рішення бекенда, а не дизайну; шість зафіксовано в IA.
Станпорожня · заповнена · активна · помилкаПомилка ставиться на всю групу.
Коли вживати

Тільки в Діалог входу. Один діалог на всі ролі - окремого входу для коуча немає.

Правило і антиправило

Правило

Помилка на всю групу. Неправильна не третя цифра, а код цілком.

Антиправило

Не роби з цього шість окремих Поле. Тоді браузер запропонує автозаповнення в кожне і зламає вставку коду з SMS.
Стани, що є в коді

У коді є заповнена, активна і .err.

Холостий контроль

Сторінка звіряє себе з файлом: 7 власних класів і 1 станів оголошено в otp.css. Нижче - ті, яких на цій сторінці немає ні в демо, ні в розмітці. Чужий контекст (.uiv-ic) не рахується: у цих селекторах компонент не є підметом, він лише стоїть усередині когось.

Рух

Робота: ВІДПОВІДЬ. Рухається: border-color, box-shadow, background. Тривалість --dur-fast (150ms), крива --ease-standard. Значення читаються через var() з tokens.css: підміна токена в браузері веде за собою кожне з них, тобто числа у файлі немає. При prefers-reduced-motion рух зникає, а стан лишається.

Токени

Прочитані з otp.css, не переписані руками. Колір іде лише через роль, геометрія - напряму з примітива.

Семантичні ролі (11)Примітиви (14)
--bg-danger --bg-page --line-action --line-danger --line-danger-soft --line-inverse --line-strong --ring-focus --text-body --text-danger --text-secondary--font-mono --fs-12 --fs-14 --fs-16 --fs-24 --fw-medium --fw-semibold --lh-flat --radius-12 --space-12 --space-16 --space-2 --space-4 --space-8
–--dur-fast --ease-standard
Розмітка
<div class="otp" role="group" aria-label="Код із шести цифр"> <input class="box on" maxlength="1" inputmode="numeric" value="4" aria-label="Цифра 1"> <input class="box" maxlength="1" inputmode="numeric" aria-label="Цифра 2"> </div>

Комірка це <input>, і саме тому maxlength="1" та inputmode="numeric" стоять у розмітці, а не в скрипті: перший тримає одну цифру навіть без JS, другий піднімає цифрову клавіатуру на телефоні. До кроку 7.13 у цьому блоці стояли <span> - розмітка, у яку неможливо набрати.

Де вживається

Якорі: .otp

У розмітці екранів не зустрічається: компонент будує рендер-функція в wireframes/_nav.js, тому сканування класів дає нуль, а на екранах він є.

Немає в коді -> етап 09

Крок 7.15: шість комірок це одне поле

Код із SMS - одне значення. Розмітка мусить бути шістьма інпутами, бо саме по одній цифрі людину просять перечитати, але це не робить із них шість полів. А поки контрол поводився як шість, набір виглядав так: цифра - миша - клац - цифра - миша - клац. Шість цифр, п'ять кліків.

Виміряно до кроку: автоперехід був, одним рядком усередині wfAuthDigits(), прив'язаним до #wf-auth. Тобто працював рівно на одному екрані з тих, де компонент стоїть, а на обох сторінках стенду не рухалось нічого. Поведінка була правильна, адреса - ні. Тепер правило живе в design/system/fields.js, який вантажать і крамниця, і всі 32 сторінки стенду.

ДіяЩо робить
Набрали цифруфокус іде в наступну вільну комірку, а не просто в сусідню
Клацнули порожню коміркупотрапляєте в першу порожню: у порожній групі клац по шостій веде в першу
Клацнули комірку з цифроюлишаєтесь у ній, цифра виділена - це хтось править саме її
Backspaceкомірка з цифрою чиститься й лишається; порожня передає натиск сусідці зліва
Стрілкиходять по комірках
Вставили «Ваш код 482197»розкладається по всіх шести, слова відкидаються
ОС підставила код із SMSте саме: autocomplete="one-time-code" ставить правило 1, а приходить воно як вставка в одну комірку

Пройдено руками на трьох поверхнях кольорового шару - цей стенд, демо на сторінці Поля і живий діалог входу - і всі три дали однакове до символу. Демо в анатомії вище живе: наберіть у ньому код, жодного разу не клацнувши в другу комірку.

Чого бракує

  • Немає стану очікування поки код перевіряється - шість комірок стоять заповнені, і нічого не каже, що код уже пішов на перевірку
  • Помилка не знімається, коли її починають виправляти - .err ставить рантайм на всі шість, і жоден дотик до комірки його не прибирає. Коли саме гасити червоне - на першому натисканні чи на новій відправці - це рішення, а не правка
  • Знак ⚠ у банері малює шрифт, а не набір - у крамниці його міняє uivAuthPolish() в design/_nav.js (errm.innerHTML = uivWrap('alert')), а стенд того файлу не вантажить. marks.js сюди не дістає навмисно: він ходить по контролах, а це текстовий блок. Третій випадок того самого шва - після серця і кошика - і вирішувати треба не окремим милицем, а тим, чи проходить пас по не-контролах
  • Сірий прототип лишився на старій поведінці - він не вантажить system/fields.js, тож там працює тільки автоперехід уперед. Це та сама відома пара, що й з форматуванням телефону: поки сірий шар заморожений, два коди на одну роботу

Не домальовано наперед і не замовчано: етап 09 стартує з цього списку, зведеного в design/kit/docs/architecture.md.