Regra CSS única em styles.css — @media (pointer: coarse) and (hover: none) + [data-theme='campaign'] :is(input, select, textarea, [contenteditable]) a 16px (limiar do Safari iOS). Cobre omnibox B127, Command search, native-select e textareas em qualquer orientação do iPhone; desktop intocado. E2E campaignIosInputZoom: emulação iPhone 13 pina 16px na omnibox de /campanha/municipios; control desktop pina 14px. Closes #501
6.6 KiB
Impl: PWA iOS: foco na omnibox de filtros aplica auto-zoom que não volta
Status: aprovado Atualizado em: 2026-08-09 Issue: #501 Intenção: docs/plans/pwa-ios-autozoom-input-foco.md Appetite restante: herdado (~0,5–1 dia eng) — cabe com folga
Leitura da intenção
- Outcome: nenhum input do PWA
/campanha(omnibox, login, formulários, wizard) dispara o auto-zoom do Safari iOS ao receber foco; desktop e telas grandes mantêm a aparência atual. - O que NÃO negociar: regra única (gate decidido: "todos de uma vez", inclui
contenteditable/select); nada demaximum-scaleglobal; anti-goal "subir para 16px no desktop". - O que reavaliar: a hipótese de "fix campo a campo" — confirmado que é sistêmico: regra CSS única cobre. O ponto de escopo ("onde o trigger do iOS existe") pede decisão de engenharia (abaixo).
Abordagem recomendada
flowchart LR
A[styles.css: media query touch] --> B[regra unlayered 16px em inputs do data-theme=campaign]
B --> C[omnibox / Command input / native-select / textarea / contenteditable]
D[e2e iPhone emulation: computed font-size 16px] --> E[desktop control: 14px intacto]
Opções consideradas:
- A — Regra CSS global no touch (recomendada): bloco em
src/app/(frontend)/styles.css(arquivo compartilhado frontend+campanha) dentro de@media (pointer: coarse) and (hover: none), seletor[data-theme='campaign'] :is(input, select, textarea, [contenteditable='true'])comfont-size: 1rem. Um bloco cobre omnibox (B127), Command search (uiCommand.tsxdata-slot=command-input),native-select, textareas e futuros contenteditable — nenhuma mudança de componente. - B — Bump por componente (
text-base md:text-smno omnibox, CommandInput, native-select, …): o padrão queInput/Textareajá seguem, mas estendido caso a caso. - C — Regra global por largura (
max-width: 767.98px, espelhando omd:do repo).
Recomendação: A — a intenção mandou regra única (gate 2026-08-09), e ela é a única que cobre o trigger em todas as orientações do iPhone: o auto-zoom do Safari existe também em landscape (larguras 844–932px em iPhones modernos), que a opção C perderia. (pointer: coarse) and (hover: none) é a expressão CSS canônica de "telefone touch" — o repo já usa variantes pointer (pointer-fine:/pointer-coarse: em RelationChipCell). Desktop/laptop (pointer fine) fica intocado — aceite 3 preservado. Como a regra é unlayered, ela vence as utilities text-sm em camada (cascata), mesmo com especificidade menor — sem !important.
Rejeitadas:
- B porque é whack-a-mole (rabbit hole nº 1 da intenção): hoje já há 3+ bespoke offenders e o trigger é regra do navegador, não do componente; um
<input>novo emtext-smreintroduz o bug silenciosamente. - C porque perde o iPhone landscape (bug permanece vivo no aparelho do usuário) e cria dois regimes de fonte (16px portrait / 14px landscape) sem ganho.
maximum-scale=1/viewport fixo — rejeitado pela própria intenção (degrada acessibilidade; vive no B182 como fallback se for preciso).
Componentes / mudanças
styles.css(src/app/(frontend)/styles.css, junto ao bloco[data-theme='campaign'] :is([data-slot=…])de bordas): um bloco@media (pointer: coarse) and (hover: none)com[data-theme='campaign'] :is(input, select, textarea, [contenteditable='true']) { font-size: 1rem; }+ comentário curto explicando o limiar de 16px do Safari iOS (precedente de comentários explicativos no arquivo).Input/Textarea/InputGroup(src/components/ui/): intocados — já sãotext-base md:text-sm; a regra é no-op para eles no touch (16px) e não vaza para desktop.- Migration: nenhuma. Access / Consent: nenhum.
- UI: Impeccable A (bug fix, sem redesenho).
- Verificação: e2e novo com emulação de device (abaixo).
Fases verificáveis
- Regra CSS — editar
styles.css; conferir com o dev server que a omnibox em emulação touch computa 16px e desktop 14px. - E2E —
tests/e2e/campaignIosInputZoom.e2e.spec.ts:- describe com
test.use({ ...devices['iPhone 13'] })(390×664,isMobile+hasTouch→pointer: coarse,hover: none): fixturecampaigncria coordinator → login →/campanha/municipios→getByRole('combobox', { name: 'Filtrar municípios' })→expect.poll(computed font-size) === '16px'. Falha hoje (14px), passa com a regra. - describe desktop (projeto campaign padrão): mesma omnibox permanece 14px — pina o aceite "desktop continua como hoje".
- describe com
- Gates —
pnpm gate:fast;pnpm test:e2e(spec novo + vizinhos de lista para regressão);pnpm format:check,pnpm exec knip,pnpm check:cycles,pnpm build. Entrega compnpm push. - CHANGELOG — entrada curta em
docs/CHANGELOG-AGENTS.md.
Rabbit holes / Não escopo (engenharia)
- Inventário exaustivo de inputs (intenção já cortou; a regra cobre todos por definição).
maximum-scale/ política de escala global (vive no B182).- Público site (
(frontend)): fora do escopo, o seletor exigedata-theme='campaign'. - Bump de fonte em buttons (Select/Combobox triggers são botões — iOS não zooma botões).
RelationChipCellinline input: épointer-fine:block(oculto no touch) — a regra não o afeta, e não é preciso.
Riscos e mitigação
- iPad (touch, ≥768px) passa a 16px (hoje
md:text-sm= 14px): o iPadOS não tem o trigger de zoom; é mudança cosmética no tamanho padrão de formulário do iOS. Não afeta desktop. Mitigação documentada no impl plan — aceite "telas maiores" refere-se a desktop, que fica intacto. - Inputs com fonte > 16px em touch seriam reduzidos para 1rem: nenhum no codebase hoje (varredura por
text-lg|xl|2xlem inputs não achou nada); se um dia houver, a regra é o limite inferior correto (16px é o teto do trigger). - E2E mobile depende de emulação Chromium (
devices['iPhone 13']), não de Safari real: valida o contrato CSS (pointer/hover) que o Safari iOS avalia; a regra é a padrão da indústria (West-Wind/t3code/BookStack). - Layout reflow no touch: 16px em inputs raros (ex. chips) — os chips da omnibox não são inputs; o campo em si cresce ~2px de altura (min-h fixos absorvem).
Aceite de engenharia
- Aceite de produto da intenção ainda coberto (regra única; desktop intacto; sem maximum-scale)
- Invariantes AGENTS/engineering-standards (sem migration/access/Consent; copy pt-BR intacta; identificadores em inglês)
- Testes previstos: e2e touch (16px) + e2e desktop (14px) — comportamento pina o aceite
- Depth check: zero módulos novos; um bloco CSS no arquivo dono do theming