Repository navigation
Description
Contexto
docs/UI-AAA-OVERHAUL.md §VII.4, bloco Respeito ao usuário (binário): "WCAG AA". O canal de
feedback do produto inteiro é mudo para leitor de tela.
Verificado em origin/main@31c1c2d: o ToastProvider renderiza a pilha num <div className="fixed bottom-4 right-4 ..."> (Toast.tsx:22) sem aria-live e sem role. Um nó
que aparece no DOM sem região live não é anunciado — nenhum dos avisos do produto chega a quem
não olha para o canto inferior direito da tela.
São 15 push em 4 componentes de produção (HomeView 8 · RoomView 3 · Lobby 2 ·
Results 2), 12 deles kind: "error". Entre os mudos estão exatamente os que travam o
jogador na porta de entrada:
"Sala não encontrada"(HomeView.tsx:158)"Partida em andamento, aguarda terminar"(HomeView.tsx:163)"Sem conexão com o servidor"(HomeView.tsx:168)
O fluxo real: o jogador cola o código, aperta Enter (HomeView.tsx:351), nada acontece do
ponto de vista dele — a página não muda, o input não muda, e o único sinal de que a sala não
existe some sozinho em 3,5s (Toast.tsx:17).
Segundo defeito no mesmo componente: o único diferenciador entre info, success e error é a
cor da borda e do texto (Toast.tsx:32-36). Sem ícone, sem prefixo, sem texto. WCAG 1.4.1
(uso de cor) — vale também para daltônicos, que enxergam o toast e não sabem se é confirmação ou
erro.
Acceptance criteria
- Existem duas regiões live permanentes no DOM (montadas com o provider, mesmo sem nenhum
toast): umarole="status"/aria-live="polite"parainfoesuccess, outrarole="alert"
/aria-live="assertive"paraerror. Duas regiões porque orolede um nó não pode mudar
dinamicamente e ainda ser anunciado de forma confiável. - O texto do toast entra numa região que já existia no DOM — criar a região junto com a
mensagem não é anunciado de forma confiável em NVDA/VoiceOver. - Cada toast carrega um indicador não-cromático do
kind: ícone + rótulo textual (visível ou
sr-only, ex.:"Erro: Sala não encontrada"). A cor deixa de ser o único canal. - O mapeamento
kind → { role, ariaLive, prefixo }é uma função pura exportada e coberta por
teste (segue o padrão dossrc/lib/*.test.ts, vitest em node env). - Nenhum toast é anunciado duas vezes (cuidado com o nó duplicado se optar por região
sr-only
espelhando o visual). - Gate verde:
pnpm typecheck·pnpm test·pnpm build.
Dica de abordagem
- Sem dependência nova (§7.3). O caminho mais curto: aplicar os atributos direto nos wrappers em
Toast.tsx:22— dois<div>irmãos sempre montados (um polite, um assertive), cada um com seu
AnimatePresencefiltrando os toasts do seu grupo. - Se preferir uma região
sr-onlyseparada do visual, cuide da duplicação: o texto visível
também é lido no modo de navegação; prefiraaria-hiddenno visual ou não duplique. AnimatePresencemantém o nó durante a saída (Toast.tsx:23); o anúncio acontece na entrada e
isso é o que importa — não tente ligar anúncio à remoção.- Ponha o helper puro em
src/lib/(ex.:toastA11y.ts) para o AC 4 sair barato. Não adicione
@testing-library/react: o projeto não tem, e dep nova é §7.2. - Verificação: dá para provar por DOM, não por interação —
read_pageno Browser pane devolve
a árvore de acessibilidade, ejavascript_toolconfirma os atributos. Não dependa de
computer{key}(não entregakeydown).
Escopo
§7.3 (UI/componentes). Não toca API, banco, engine nem a área sagrada. Fora de escopo
deliberado: o setTimeout fixo de 3500ms (Toast.tsx:17) fere WCAG 2.2.1 (controle de tempo) —
pausar/estender no hover e no foco é uma fatia própria, fica para outra rodada para esta caber numa
só. prefers-reduced-motion é a #108.
Activity