Pular para conteúdo

0001 — Borda e placeholder dos campos de formulário fora dos tokens

Status CORRIGIDO
Branch fix/0001-borda-placeholder-campos-formulario
Aberto em 2026-07-29
Severidade MÉDIA
Apps afetados web (api · e2e sem impacto)

Status: RASCUNHO → DIAGNOSTICADO → EM CORREÇÃO → CORRIGIDO

1. Sintoma

Nos formulários de cadastro (imobiliárias, imóveis, inquilinos, etc.), no tema claro, os campos (TextField MUI outlined, size="small") têm:

  • Borda genérica e fraca, que não é o cinza da marca.
  • Placeholder apagado, com aparência de desabilitado / pouca legibilidade.

O conjunto destoa dos tokens de design e passa impressão de acabamento pobre.

2. Reprodução

  1. Abrir qualquer formulário no tema claro — ex.: /app/renters/create, /app/properties/create, /app/agencies/create.
  2. Observar a borda dos campos em repouso e o texto de placeholder.

  3. Ambiente: web, tema claro (dev-remote ou local). Qualquer papel com acesso a cadastro.

  4. Pré-condições: nenhuma — vale para todo TextField outlined.

3. Esperado × Atual

  • Esperado: borda na cor border.subtle dos tokens (#E2E8F0 no claro), com hover/foco na cor da marca (primary); placeholder legível, derivado de text.secondary.
  • Atual: borda no default do MUI (rgba(0,0,0,0.23)) e placeholder no default do MUI (opacity ~0.42 sobre text.primary) — nenhum dos dois segue os tokens.

4. Causa raiz

apps/web/src/contexts/color-mode/index.tsx — o objeto sharedComponents (compartilhado pelos temas claro e escuro) só customiza MuiButton. Não há override de MuiOutlinedInput, MuiInputBase nem MuiInputLabel, então borda e placeholder caem inteiramente no default do MUI, que não conhece os tokens da marca.

Não é regressão de uma mudança específica: nunca houve tema de input — o gap existe desde a criação do tema. Confirmado por leitura: sharedComponents (linhas ~42–57) não referencia input algum; o palette também não define divider, então até os FormPanel (que usam borderColor: "divider") herdam o divider default.

5. Correção

apps/api

Sem impacto — é estilo de UI.

apps/web

  • Onde: src/contexts/color-mode/index.tsx, no sharedComponents (ou, se for preciso divergir por modo, no components de cada tema).
  • O quê: adicionar override de input alinhada aos tokens —
  • MuiOutlinedInput → .MuiOutlinedInput-notchedOutline borderColor = border.subtle (#E2E8F0 no claro); :hover num tom mais escuro; .Mui-focused na cor primary.
  • input::placeholder → color derivado de text.secondary, opacity: 1 (o default do MUI aplica opacity baixa que "apaga" o texto).
  • avaliar MuiInputLabel para consistência do label.
  • Escopo: foco no tema claro (conforme triagem). Se a override no sharedComponents usar callback ({ theme }) => com cores derivadas do palette, ela naturalmente serve os dois modos — nesse caso, conferir que o escuro não regride (ver seção 6). Tratar o escuro é fora de escopo deste fix.
  • data-testid: nenhum novo (mudança puramente de estilo).

apps/e2e

Sem teste de regressão automatizado: o Playwright não afere cor/borda de forma robusta e barata. Validação por screenshot manual de 2–3 formulários no tema claro (ver Plano). Registrar o antes/depois no fechamento.

6. Risco / impacto colateral

Baixo, mas global: uma override de MuiOutlinedInput/MuiInputBase afeta todos os inputs do app — login, onboarding, filtros de lista, campos do admin, e os campos compostos (DateField, CepField, autocompletes). Ao aplicar:

  • Conferir que campos com sx próprio não colidem com a override.
  • Conferir login/onboarding e os filtros de lista, não só os cadastros.
  • Se a override for theme-aware (serve os dois modos), garantir que o tema escuro não fica pior que hoje.

Sem qualquer impacto em regra de negócio, cálculo (pricing/billing/sinistro) ou dados.

7. Critérios de aceite

  • [x] CA1. Em /app/renters/create no tema claro, a borda dos campos usa o cinza do design system e o placeholder está legível. Estilo computado em repouso: rgb(148,163,184) = #94A3B8 (ver assets/0001-borda-placeholder-campos-formulario/final.png).
  • [x] CA2. O foco de um campo mostra a cor da marca (primary): estilo computado rgb(0,85,119) = #005577, borda 2px.
  • [x] CA3. Login e cadastros renderizam sem regressão (claro em assets/0001-borda-placeholder-campos-formulario/final.png, escuro em assets/0001-borda-placeholder-campos-formulario/dark-login.png); a override é aditiva e uniforme para MuiOutlinedInput.

8. Plano

  • [x] Reproduzir: assets/0001-borda-placeholder-campos-formulario/before.png (borda lavada / default do MUI no tema claro)
  • [x] Corrigir no tema (apps/web, color-mode/index.tsx) — MuiOutlinedInput + input/textarea::placeholder
  • [x] Validar no browser: cadastro no claro (assets/0001-borda-placeholder-campos-formulario/final.png) + login no escuro (assets/0001-borda-placeholder-campos-formulario/dark-login.png) + estilo computado
  • [x] Build de produção do web (roda tsc) sem erro; sem apontamento novo
  • [x] Screenshots anexados ao registro (não há regressão automatizada de cor)

9. Decisões em aberto

Nenhuma — triagem resolvida (borda + placeholder, tema claro, alinhar aos tokens).

  • ~~(nota) Tema escuro fora de escopo~~ → incluído após feedback: no mobile PWA o login/signup "não alterou" porque o app estava no tema escuro (o claro já tinha o fix). O escuro passou a ter o mesmo tratamento (ver Registro).

10. Registro

O que era: nenhuma override de input no tema (sharedComponents só cobria MuiButton) → borda e placeholder no default do MUI, fora da paleta.

O que virou (apps/web/src/contexts/color-mode/index.tsx, components do tema claro): override de MuiOutlinedInput —

  • borda em repouso #94A3B8 (slate-400), hover #64748B (slate-500)
  • foco em primary (#005577), 2px
  • input/textarea::placeholder em #5f6878 (text.secondary), opacity: 1

Desvio do plano + iteração: o plano previa border.subtle (#E2E8F0), que é o tom de divisor e reproduziria a borda lavada. A 1ª tentativa usou #CBD5E1 (slate-300), mas o usuário achou ainda fraca demais; comparei 4 intensidades (slate-350→600) e ele escolheu slate-400 #94A3B8 no repouso, com hover #64748B (slate-500). Família slate do design system, agora com contraste claro.

Escopo: só o tema claro, conforme triagem. O escuro segue no default (fix próprio se incomodar).

Deploy: container web do dev-remote rebuildado e no ar (https://dev.garantora.com.br/app).

Evidências (nesta pasta): assets/0001-borda-placeholder-campos-formulario/before.png, after.png, after-focus.png, after-login.png. Estilo computado (claro): repouso rgb(203,213,225), foco rgb(0,85,119).

Adendo — tema escuro (feedback: mobile PWA)

O usuário reportou que no mobile PWA o login/signup não alterou. Investigação:

  • O bundle no ar já continha o fix (login/register usam TextField outlined) — não era deploy.
  • No tema escuro a borda seguia no default do MUI (rgba(255,255,255,0.23)), porque a correção inicial foi só no claro. Celulares costumam estar em dark → daí o "não alterou".

Correção: adicionada override equivalente no garantoraDarkTheme (color-mode/index.tsx): borda repouso #3a4657, hover #4b5a70, foco #4da6cc (primary do dark) 2px, placeholder rgba(232,234,240,0.7) opacity 1. Rebuild + redeploy do web; borda do login no escuro agora mede rgb(58,70,87) = #3a4657 (assets/0001-borda-placeholder-campos-formulario/dark-login.png).

Ressalva de PWA (não é bug de código): o PWA usa registerType: "autoUpdate" (vite-plugin-pwa) com precache do bundle. Um app já instalado serve o bundle cacheado até o service worker atualizar — então, no aparelho, é preciso fechar e reabrir o PWA (uma vez para baixar o novo SW, e ele aplica no load seguinte). Não há mudança de código para isso; é o comportamento esperado do cache.

Adendo 2 — labels claros na card de auth (dark)

Após o SW atualizar, o usuário reportou que no mobile os labels dos campos de login/signup continuavam claros. Causa: login/index.tsx e register/index.tsx hardcodam a card branca (#ffffff), mas com o app em dark os TextField usavam a cor de texto do tema escuro (clara) → label claro sobre branco, ilegível.

Correção: login e register agora renderizam sempre no tema claro, envolvendo o conteúdo num <ThemeProvider theme={garantoraLightTheme}> (a card sempre foi branca por design). Label do e-mail no dark passou de claro para rgb(95,104,120) = #5f6878, legível (assets/0001-borda-placeholder-campos-formulario/auth-dark.png).

Resolvido (mesma armadilha): verify-email e accept-invite tinham a mesma card branca e o mesmo bug em dark — receberam o mesmo wrap em garantoraLightTheme. Confirmado em assets/0001-borda-placeholder-campos-formulario/verify-dark.png (card branca, heading/label escuros e legíveis, foco na marca) com o app em dark. onboarding é multi-step, estrutura diferente — não apresentou o problema.