Componentes
20. Progress
seed-componentes.md v1.43 · §20seção 22 de 9820-progress-estavel-validado-pelo-rafael-em-2026.md · MD5 c823a99aTítulo completo no canon: Progress — estável · validado pelo Rafael em 2026-08-04 (suite v0.17) · resolve a ponta do §17.5
Base: R1 — NN/g (>10s exige estimativa explícita), Carbon progress bar (handoff indeterminado→determinado; direção E→D), Material m1 PRIMÁRIO (nunca regride; uma barra para o todo) e m2 (handoff). R2 — React Aria useProgressBar (valuetext localizado; label obrigatório), Radix/shadcn (omitir value = indeterminado), Angular Material (não alterar valuemin/max padrão), MUI (aria-valuetext quando não é %). R3 — W3C ARIA25 íntegra (técnica oficial do 4.1.3: progressbar NÃO é live region; canal polite separado visually-hidden), MDN progressbar, marcos 25/50/75 (nunca cada 1%), Fiori (bloquear o mínimo). Fronteira: stepper "passo 2 de 5" é NAVEGAÇÃO → Bloco 5 (registrado no roadmap).
20.1 Decisões U1–U6#
| # | Decisão | Porquê | Descartado |
|---|---|---|---|
| U1 | Uso: fração conhecida OU >10s. Pode nascer indeterminada e CONVERTER quando o dado chega; o valor NUNCA regride (clamp); operações sequenciais = UMA barra do todo | m1 primário: "always fill from 0% to 100% and never decrease"; "the progress as a whole, not each individual operation"; Carbon/m2: handoff | Barra por sub-operação; regressão visual |
| U2 | ARIA: role="progressbar" + aria-valuenow/min/max (0/100 padrão, NÃO alterar); indeterminada = OMITIR valuenow; rótulo obrigatório (aria-labelledby no label visível); aria-valuetext quando o formato humano não é % ("7 de 12 faturas") |
MDN; Angular Material (mudar min/max quebra AT); React Aria/MUI (valuetext) | Div animada sem role |
| U3 | Anúncio = regime CONTÍNUO do §1.13 (par simétrico da 1.13-b): o progressbar NÃO anuncia sozinho — canal SEPARADO visually-hidden role="status" pré-existente anuncia MARCOS (25/50/75/100), nunca cada 1%, e a conclusão NOMEIA o objeto. O §14 (N3/N4) passa a referenciar este componente como canônico |
W3C ARIA25: os values comunicam programaticamente mas não são anunciados ao mudar — a live region polite separada é quem fala; cada 1% soterra | Anunciar todo %; confiar só no role |
| U4 | aria-busy="true" na região que a operação reconstrói (tabela em lote); controles internos desabilitados durante |
Escopo correto do aria-busy | aria-busy no body |
| U5 | >10s: barra + texto de status (percentual/etapa em JetBrains Mono — dado de medição, tokens v1.2 §tipografia); o resto da UI permanece interativo sempre que possível | Fiori: bloquear o mínimo; NN/g >10s = estimativa explícita | Overlay global em operação longa |
| U6 | Toast de processo (fecha a ponta do §17.5): operação longa em BACKGROUND vive num toast PERSISTENTE (herda Q2/Q4) contendo esta progressbar; título em gerúndio ("Enviando 12 faturas…"); aos 100% CONVERTE em toast de desfecho (sucesso, aí sim com auto-dismiss 8s). O nó-raiz do toast de processo NÃO leva role vivo — quem anuncia é o canal U3 interno (senão o atomic re-falaria o toast inteiro a cada %) | Fluent (gerúndio→substantivo; processos similares combinam num toast) + U1 (uma barra do todo) + §1.13 (uma live region por componente, do tipo certo) | Toast de processo com auto-dismiss; role="status" no raiz (re-anúncio a cada update) |
20.2 Anatomia e tokens#
Trilho 8px radius 999 em --seed-border-subtle; preenchimento --seed-action-primary-bg, transição de largura 200ms --seed-ease-out (reduced-motion: seca); label acima à esquerda, valor à direita em mono; indeterminada: segmento ~30% varrendo E→D em loop (direção reservada da barra — Carbon).
20.3 Os 7 testes#
- Preenchimento×trilho e trilho×página ≥3:1 (medir light/dark). 2. Progresso por comprimento + número + anúncio. 3. Grayscale: comprimento carrega. 4. Determinada×indeterminada a 1s (número presente × varredura). 5. Uma barra por processo (U1); um canal de anúncio (U3). 6. Estado visível: label + valor sem interação. 7. 360px: barra full-width, label/valor empilham sem truncar; toast de processo legível. (Verificado: suite v0.17, aprovado.)