fix(регистрация/моб): поля ввода 16px на мобильной ширине (iOS Safari без зума)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Public / Build + push Public (test + latest) (push) Waiting to run
Docker Public / Deploy :test → test.food-market.kz (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions

iOS Safari зумит страницу при фокусе на поле с font-size < 16px и оставляет её
увеличенной/сдвинутой. Делаем у текстовых полей text-base (16px) на мобильной
ширине и sm:text-sm (14px) на планшете+. Запрет масштабирования (user-scalable=no)
НЕ вводим — viewport-меты не трогаем.

Затронуто:
- public: SignupForm.inputCls (email/пароль/название + PhoneInput сайта);
- кабинет: общий inputClass в Field.tsx (TextInput/Textarea/Select/Money/Percent)
  + поиск внутри выпадашек, PhoneInput кабинета, инлайн-поля LoginPage.

Диапазон-слайдер конструктора тарифов не трогаем (type=range не зумится).
Проверено в браузере (Playwright): на ширине 390 все поля формы регистрации
16px, на 900 — 14px.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
nns 2026-10-13 14:11:13 +05:00
parent 043d5c0417
commit 164ad57ed7
4 changed files with 12 additions and 7 deletions

View file

@ -154,8 +154,10 @@ export default function SignupForm({ defaultPlan = 'start' }: Props) {
} finally { setBusy(false) }
}
// text-base на мобильной ширине (16px) → iOS Safari не зумит страницу при
// фокусе на поле; на sm и выше — привычные 14px. user-scalable=no НЕ ставим.
const inputCls = (hasError: boolean) =>
`w-full h-10 rounded-md border px-3 text-sm focus:outline-none focus:ring-2 ${
`w-full h-10 rounded-md border px-3 text-base sm:text-sm focus:outline-none focus:ring-2 ${
hasError ? 'border-red-400 focus:ring-red-300' : 'border-slate-300 focus:ring-brand'
}`

View file

@ -31,7 +31,9 @@ export function Field({ label, error, children, className }: FieldProps) {
)
}
const inputClass = 'w-full h-10 rounded-md border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 px-3 text-sm leading-none focus:outline-none focus:ring-2 focus:ring-[var(--color-brand)] disabled:opacity-60 disabled:bg-slate-50 dark:disabled:bg-slate-800/60'
// text-base на мобильной ширине (16px) → iOS Safari не зумит при фокусе; с sm —
// привычные 14px. Запрет масштабирования (user-scalable=no) НЕ используем.
const inputClass = 'w-full h-10 rounded-md border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 px-3 text-base sm:text-sm leading-none focus:outline-none focus:ring-2 focus:ring-[var(--color-brand)] disabled:opacity-60 disabled:bg-slate-50 dark:disabled:bg-slate-800/60'
export function TextInput(props: InputHTMLAttributes<HTMLInputElement>) {
// Подключаем локализацию нативных подсказок валидации (required, type=email,
@ -227,7 +229,7 @@ export function Select({
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Поиск…"
className="w-full h-8 rounded border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-2 text-sm focus:outline-none focus:ring-1 focus:ring-[var(--color-brand)]"
className="w-full h-8 rounded border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-2 text-base sm:text-sm focus:outline-none focus:ring-1 focus:ring-[var(--color-brand)]"
onKeyDown={(e) => {
if (e.key === 'Escape') { e.preventDefault(); setOpen(false); setQuery('') }
else if (e.key === 'ArrowDown') {
@ -412,7 +414,7 @@ export function AsyncSelect({
<div className="p-2 border-b border-slate-100 dark:border-slate-800">
<input ref={searchRef} value={query} onChange={(e) => setQuery(e.target.value)}
placeholder="Поиск…"
className="w-full h-8 rounded border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-2 text-sm focus:outline-none focus:ring-1 focus:ring-[var(--color-brand)]"
className="w-full h-8 rounded border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-2 text-base sm:text-sm focus:outline-none focus:ring-1 focus:ring-[var(--color-brand)]"
onKeyDown={(e) => {
if (e.key === 'Escape') { e.preventDefault(); setOpen(false); setQuery('') }
else if (e.key === 'ArrowDown') { e.preventDefault(); setHighlight((h) => Math.min(h + 1, Math.max(0, options.length - 1))) }

View file

@ -1,7 +1,8 @@
import { useMemo, useRef, useLayoutEffect, type InputHTMLAttributes, type FormEvent } from 'react'
import { cn } from '@/lib/utils'
const inputClass = 'w-full h-10 rounded-md border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 px-3 text-sm leading-none focus:outline-none focus:ring-2 focus:ring-[var(--color-brand)] disabled:opacity-60 disabled:bg-slate-50 dark:disabled:bg-slate-800/60 tabular-nums'
// text-base на мобильной (16px) → iOS Safari не зумит при фокусе; sm → 14px.
const inputClass = 'w-full h-10 rounded-md border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 px-3 text-base sm:text-sm leading-none focus:outline-none focus:ring-2 focus:ring-[var(--color-brand)] disabled:opacity-60 disabled:bg-slate-50 dark:disabled:bg-slate-800/60 tabular-nums'
// Код страны (+7) живёт в префиксе; оператор НЕ подставляем заранее, иначе
// при вводе полного номера «7XX…» его первая цифра налезает на префиксную «7».

View file

@ -110,7 +110,7 @@ export function LoginPage() {
onBlur={() => setEmailErr(validateEmail(email))}
aria-invalid={emailErr ? true : undefined}
aria-describedby={emailErr ? 'login-email-err' : undefined}
className={`w-full rounded-md border bg-white dark:bg-slate-900 px-3 py-2 text-sm focus:outline-none focus:ring-2 ${emailErr ? 'border-red-400 focus:ring-red-300' : 'border-slate-300 dark:border-slate-600 focus:ring-[var(--color-brand)]'}`}
className={`w-full rounded-md border bg-white dark:bg-slate-900 px-3 py-2 text-base sm:text-sm focus:outline-none focus:ring-2 ${emailErr ? 'border-red-400 focus:ring-red-300' : 'border-slate-300 dark:border-slate-600 focus:ring-[var(--color-brand)]'}`}
/>
{emailErr && <span id="login-email-err" role="alert" className="text-xs text-red-600 block mt-1">{emailErr}</span>}
</label>
@ -125,7 +125,7 @@ export function LoginPage() {
onBlur={() => setPasswordErr(password ? null : messages.required)}
aria-invalid={passwordErr ? true : undefined}
aria-describedby={passwordErr ? 'login-password-err' : undefined}
className={`w-full rounded-md border bg-white dark:bg-slate-900 px-3 py-2 text-sm focus:outline-none focus:ring-2 ${passwordErr ? 'border-red-400 focus:ring-red-300' : 'border-slate-300 dark:border-slate-600 focus:ring-[var(--color-brand)]'}`}
className={`w-full rounded-md border bg-white dark:bg-slate-900 px-3 py-2 text-base sm:text-sm focus:outline-none focus:ring-2 ${passwordErr ? 'border-red-400 focus:ring-red-300' : 'border-slate-300 dark:border-slate-600 focus:ring-[var(--color-brand)]'}`}
/>
{passwordErr && <span id="login-password-err" role="alert" className="text-xs text-red-600 block mt-1">{passwordErr}</span>}
</label>