fix: aria-label nos dois X de SplitSection.tsx (closes #129) - #145
Draft
Guiroos wants to merge 1 commit into
Draft
fix: aria-label nos dois X de SplitSection.tsx (closes #129)#145Guiroos wants to merge 1 commit into
Guiroos wants to merge 1 commit into
Conversation
Os botões de fechar divisão e remover pessoa usam o mesmo ícone X do lucide-react sem nome acessível — role=button sem fonte de nome, já que lucide-react@1.8.0 marca o svg como aria-hidden quando não recebe filho nem prop de a11y. Rótulos distintos para os dois estados. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L2ttiXUNPukdqzYnnmuzw7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O que mudou
components/forms/transaction/SplitSection.tsxtem dois<Button size="icon" variant="ghost">cujo único filho é um<X>dolucide-react, semaria-label,aria-labelledby,titleousr-only:onClick={handleClose})onClick={() => removePerson(entry.uid)})lucide-reactestá pinado em1.8.0(package.json), cujoIconmarca o<svg>comoaria-hidden="true"quando não recebe filho nem prop de a11y — orole=buttonchega ao leitor de tela sem nenhuma fonte de nome (WCAG 4.1.2 Name, Role, Value, nível A). Os dois botões são visualmente e semanticamente idênticos (mesmo ícone, mesmovariant/size), o que torna a ambiguidade especialmente perigosa:handleClosedescarta todas as linhas já preenchidas, enquantoremovePersonafeta só uma linha.<Button type="button" variant="ghost" size="icon" onClick={handleClose} + aria-label="Fechar divisão" className="text-text-tertiary hover:text-text-primary"> <X className="h-4 w-4" /> </Button> <Button type="button" variant="ghost" size="icon" onClick={() => removePerson(entry.uid)} + aria-label="Remover pessoa da divisão" className="mb-0.5 flex-shrink-0 text-text-tertiary hover:text-negative"> <X className="h-4 w-4" /> </Button>Mudança puramente aditiva, sem alteração visual ou de comportamento.
Por que dessa forma
Segui a proposta da issue #129 à risca:
<X aria-label="...">também desligaria oaria-hidden(viahasA11yPropdo lucide), mas poria o nome no<svg>em vez do controle clicável — divergindo dos outros 20 controles do repo que rotulam o<Button>.personIdpode estar vazio (linha recém-adicionada) e o nome vem doCombobox— montar a string dinamicamente acoplaria o rótulo ao estado de seleção sem ganho real, e um nome vazio produziria texto truncado.Como testei
npm ci && npm run lint && npm run format:check && npm run typecheck && npm test && npm run build— todos verdes (35 arquivos, 529 testes).ds-reviewerrodado sobre o diff: aprovado sem violações — a mudança é só a proparia-label, ortogonal às 6 regras do DS.npm run test:integrationnão foi executado (exige credenciais Neon e só roda em push paramain) — não se aplica, a mudança não toca camada de dados.Novo arquivo
__tests__/unit/a11y-nomes-acessiveis.test.ts(não existia emmainno momento deste PR — issues irmãs como #126/#127/#128 também o criam em paralelo; conflito esperado, resolvido somando osdescribeblocks). A asserção não usatoMatch(/aria-label/)genérico:SplitSection.tsxtem 5<Button>no total e os dois sites em risco usam o mesmo ícone<X>, então o gate precisa (1) achar exatamente os dois<Button>que envolvem um<X>, (2) exigiraria-labelem ambos, e (3) exigir rótulos distintos — o defeito original é a ambiguidade entre os dois estados, não a ausência isolada de nome.Risco e o que NÃO foi coberto
Risco baixo: mudança aditiva de um atributo ARIA, sem impacto em lógica, estilo ou dados. Não cobre os outros 7 sites do achado original (#106) — issues próprias: #126 (
DeleteButtondo DS), #127 e #128 (lápis de editar).Conflito de arquivo esperado.
__tests__/unit/a11y-nomes-acessiveis.test.tsestá sendo criado do zero em paralelo por #126, #127, #128 e esta PR. Quem mergear por último resolve somando osdescribeblocks, não descartando um lado.Arquivos tocados
components/forms/transaction/SplitSection.tsx__tests__/unit/a11y-nomes-acessiveis.test.ts(novo)🤖 Generated with Claude Code
https://claude.ai/code/session_01L2ttiXUNPukdqzYnnmuzw7
Generated by Claude Code