Planos para Voltar/Android back/skeleton no Início, município sem título + sticky + skeleton, e autofocus/destaque de votos no wizard.
8.6 KiB
Wizard — autofocus do primeiro input + destaque do último cenário focado
Status: registrado
Atualizado em: 2026-08-01
Issue: #143
Priority: P1
Model: composer-2.5
Impeccable: B — encaixe em CampaignWizardShell + steps com input + VoteEstimateScenarioInputs compact
Appetite: ~0,5–0,75d eng; foco/a11y + CSS de active scenario; sem migration
Responsável: —
Design (Impeccable)
Âncoras: PRODUCT.md (Feel the action; Clarity under pressure) / DESIGN.md · B59 shell · B61 votos · tema campaign.
Na implementação: craft compacto → critique → polish (teclado mobile ao abrir cada step).
Brief compacto:
- Persona / contexto: assessor avança steps do wizard no celular; espera digitar na hora sem tocar de novo no campo.
- Job principal: ao abrir um step com input, o primeiro campo já está focado (e selecionado se numérico); no ajuste de votos, o input visualmente destacado é o último focado, não o central fixo — alinhado aos atalhos (+50, 2×) que já seguem
focusedScenario. - Estratégia de cor: Restrained — reusar
border-primary/50 bg-primary/5 ring-primary/15no ativo; muted nos demais. - Edit where you see: sim no sentido de affordance do cenário ativo (já existe strip); não abre editor novo.
- Anti-goals: autofocus em steps só de escolha (grid de tendência/tipo) sem input de texto; mudar validação
getWizardVoteViolation; spreadsheet mode.
Wireframe (texto)
┌─ step município (após B107 sem h1) ─────────────────┐
│ ┌─ Nome do município… │← foco + teclado ao abrir │
│ hits… │
└─────────────────────────────────────────────────────┘
┌─ step votos estimados ──────────────────────────────┐
│ [strip marker sob o ativo] │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ 80 │ │ 100 │ │ 120 │ ← destaque = last focused │
│ └─────┘ └─────┘ └─────┘ │
│ (ex.: foco em otimista → anel primary nele, │
│ não no central) │
│ [+50] [2×] … aplicam ao focusedScenario │
└─────────────────────────────────────────────────────┘
Dados → decisão → apresentação
Dados: N/A — affordance de edição; números já existentes.
Contexto
CampaignWizardShell faz titleRef.focus() em todo stepTitle change — útil para screen readers em steps de escolha, mas rouba o foco do primeiro input.
WizardExpectedVotesStep já mantém focusedScenario (default central) e passa activeScenario / onFocusScenario para atalhos e strip (markerMode: 'active-only'). Porém em VoteEstimateScenarioInputs compact, a classe primary está hardcoded em scenario === 'central', então o meio parece sempre “o” ativo mesmo quando o foco (e os botões) estão noutro cenário.
Pedido de produto (2026-08-01): autofocus do primeiro input em cada step com input; no votos, destaque = último focado.
Objetivos
- Steps com
<input>/ textarea / search: ao montar (ou ao mudar de step), focar o primeiro campo editável; em campos numéricos de votos, manterselect()no focus (já existe). - Shell não foca o
h1quando o step declara que vai autofocusar um input (ou quandostepTitleé null — B107). - Compact votes: highlight primary segue
activeScenario(últimoonFocus), nãocentralfixo; erro (errorScenarios) continua a ganhar da highlight de foco. - Default inicial inalterado: monta com
centralfocado +autoFocusScenario="central"→ meio destacado até o usuário focar outro. - Sem migration / mudança de schema de pledge.
- Pins: unit na regra de classe compact (
activeScenariovs central); RTL leve de autofocus no municipality step se barato.
Decisões travadas
- Um item para autofocus + highlight de votos. Mesmo eixo “foco = sinal do controle ativo”; appetite cabe. Rejeitado: duas Issues cosméticas.
- Opt-in por step (
autoFocusFieldId/focusMode: 'title' | 'first-input'), não heurística DOM genérica no shell. Cada step sabe seu primeiro input. Rejeitado:querySelector('input')no shell (frágil com hidden fields). - Highlight compact =
activeScenario, em todos os call sites compact (wizard + lista B42). Consistência; lista já passa foco. Rejeitado: prophighlightCentralAlwayslegacy. - Steps só de botões/grid (tendência, tipo de sinal): mantêm foco no título (ou primeiro radio/button se já existir). Fora do “com input”. Rejeitado: forçar foco no primeiro botão do grid neste item (pode ser follow-up a11y).
- i18n: ids existentes; sem copy nova obrigatória.
Questões em aberto
- Município:
autoFocusnativo vsuseEffect+ ref após paint? Opções: AautoFocusnoCampaignSearchInput| B effect no step. Recomendação: A se o shell parar de focar o h1; B se race com navegação pending. (assumido — craft) - Labeled variant (não compact) também destaca por foco? Opções: A só compact | B ambos. Recomendação: A — pedido é o wizard/strip compact; labeled já tem labels por campo. (assumido)
Abordagem proposta
flowchart LR
Shell["CampaignWizardShell focusMode"]
Mun["MunicipalitySearch autoFocus"]
Votes["ExpectedVotes autoFocus central"]
Note["TrendNote / SignalBody / Leadership autoFocus"]
Compact["VoteEstimateScenarioInputs highlight=activeScenario"]
Shell -->|"title ou none"| Mun
Shell --> Votes --> Compact
Shell --> Note
Componentes:
CampaignWizardShell: propcontentFocus?: 'title' | 'none'(default'title'para não regredir grids); quando'none', skiptitleRef.focus(). Steps com input passam'none'.WizardMunicipalitySearchStep:contentFocus="none"+autoFocusno search input (coordena com B107 sem h1).WizardExpectedVotesStep/WizardTrendNoteStep/WizardSignalBodyStep/WizardLeadershipStep:contentFocus="none"+ autofocus no primeiro campo.VoteEstimateScenarioInputscompact: trocarscenario === 'central'porscenario === activeScenariona classe primary (erro destrutivo prevalece).- Testes: unit da classe compact; smoke se houver spec do wizard votos.
- Migration: Sem migration.
Dependências
- Soft: B59 ✓, ajuste votos wizard ✓. Coordena com B107 (shell sem h1 no município) — se B107 landar antes,
contentFocusno município é trivial; se este landar antes, funciona com h1 ainda presente desde que shell não foque o título. serializes: nenhum schema; preferir não editarCampaignWizardShellem paralelo com B107 no mesmo instante — se ambos claimed, B107 primeiro (título) ou um PR único se o mesmo agente pegar os dois.
Não escopo
- Remover título / sticky busca → B107.
- Voltar/skeleton Início → B106.
- Mudar defaults de cenário (pessimista vs central) ou atalhos.
Rabbit holes
- Autofocus + leitores de tela (WCAG 2.4.3). Mitigação: steps de escolha continuam no título; só steps de formulário movem foco para o campo — padrão de wizards mobile.
- Autofocus em toda navegação client do wizard dispara teclado em loop. Mitigação: focus só no mount do step / mudança de
stepTitle+slug, não a cada re-render de pending.
Adiado com gatilho
- Foco no primeiro controle de steps só-grid. Revisitar com auditoria a11y se VoiceOver reclamar do h1 sem atalho para o grid.
- Sincronizar highlight da variant labeled. Se a lista desktop compactar tudo em compact.
Referências
- GitHub Issue #143
src/components/campaign/shared/CampaignWizardShell.tsxsrc/components/campaign/shared/WizardMunicipalitySearchStep.tsxsrc/components/campaign/shared/WizardExpectedVotesStep.tsxsrc/components/campaign/votePledge/VoteEstimateScenarioInputs.tsxsrc/components/campaign/municipality/WizardTrendNoteStep.tsxsrc/components/campaign/municipality/WizardSignalBodyStep.tsxsrc/components/campaign/leadership/WizardLeadershipStep.tsx- chassis-wizard-campanha.md (B59) · ajuste-votos-wizard.md
PRODUCT.md/DESIGN.md
Qualidade de decisão: 5/5