Onde o DS está hoje,
e como vira o melhor do Brasil.
Cinco analistas sênior varreram o DS e as telas — heurísticas de Nielsen, benchmark dos melhores DS do mundo, acessibilidade WCAG, microinterações e densidade de dados. Cada achado virou um de-para hoje→ideal; uma parte já foi aplicada nesta rodada, o resto está priorizado pra V2.
De-para componente a componente
18 achados na avaliação heurística. Os de maior severidade já entraram nesta rodada; o resto está priorizado.
| Área | Hoje | Ideal | Status |
|---|---|---|---|
Tabela — estado de loading severidade 3 | Sem skeleton: em rede real, tela vazia ou flash de conteúdo. | Prop loading → linhas-esqueleto que preservam colunas/altura. | Aplicado |
Tabela — estado vazio severidade 3 | rows=[] renderiza tbody vazio; cada tela improvisava o vazio. | emptyState nativo (P2Empty) dentro do frame quando 0 linhas. | Aplicado |
Ordenação falsa severidade 2 | Ícone "sortable" era decorativo — não ordenava (engana o usuário). | Ordenação real asc/desc + aria-sort no header. | Aplicado |
A11y de controles severidade 2 | Checkbox/switch/seleção eram <span onClick> sem role nem teclado. | role + aria-checked/pressed + foco + operação por teclado. | Aplicado |
Feedback de ação severidade 3 | Conferir/Classificar mudavam estado em silêncio, sem confirmação. | P2Toast de sucesso/erro (com "Desfazer" no reversível). | Aplicado |
Movimento severidade 2 | Sem prefers-reduced-motion; só 2 keyframes, sem tokens de motion. | Escala de duração/easing + reduced-motion global. | Aplicado |
Confirmação destrutiva severidade 3 | "Devolver"/lote disparam direto, sem confirmar. | P2ConfirmDialog obrigatório p/ danger/irreversível. | V2 |
Drawer acessível severidade 2 | Sem Esc, foco-trap nem lock de scroll. | Radix Dialog: Esc, foco-trap, aria-modal, restaura foco. | V2 |
Paginação severidade 2 | Footer diz "12 de 128" mas não há como ver além. | P2Pagination / "carregar mais" plugado no footer. | V2 |
Estado de erro severidade 3 | Sem P2ErrorState; input não pinta borda no erro. | P2ErrorState (retry) + border-danger + aria-invalid. | V2 |
Acessibilidade — contraste & breakpoints
| Par | Ratio | AA |
|---|---|---|
ink → branco texto principal | 14,6:1 | |
ink-muted → branco apoio | 4,76:1 | |
ink-subtle → branco header de tabela / labels — REPROVAVA | 2,56:1 | corrigido |
branco → primary botão primário | 6,29:1 | |
branco → canal-vermelho danger / cancelar | 6,47:1 | |
canal-verde (texto) → branco delta "positivo" — REPROVAVA | 3,30:1 | corrigido |
tags semânticas (fg→bg) sucesso/aviso/perigo/info | 8,2:1 | |
slate-500 → ds-surface legenda na casca escura — REPROVAVA | 3,87:1 | corrigido |
ds-accent → ds-ink marcador "ideal" | 10,8:1 |
4 pares reprovavam (texto pequeno < 4,5:1). Todos corrigidos: labels/headers subiram p/ ink-muted, delta verde e legendas da casca ajustados.
Ring primary visível em todo controle interativo.
role + aria-* em check/switch/tabs/seleção; card do Kanban opera por Enter/Espaço.
Microinterações
| Processo | Canal | |
|---|---|---|
| SKT0469-SCDI | Verde | USD 48.250 |
| CHB0086-ESDI | Amarelo | USD 12.900 |
| RCH0002-SCDU | Vermelho | USD 91.430 |
| Nome | Gatilho · regra | Tempo | Defesa | reduced |
|---|---|---|---|---|
| btn-press | pointerdown · hover troca tom; press recua scale 0.98 | 120ms ease-out | feedback tátil confirma o clique antes da ação responder (Doherty). | mantém cor, corta scale |
| input-focus | focus · borda primary + ring 2px cresce 0→2 | 120ms ease-out | marca inequívoca de onde o cursor está — crítico p/ teclado. | mantém (é affordance de foco) |
| row-hover | enter na linha clicável · fundo vira primary-50/40 | 120ms ease-out | em tabela densa, diz "é esta linha que vou abrir" (Fitts). | mantém cor |
| col-sort | clique no header · ArrowUpDown vira seta asc/desc; linhas reordenam | 150ms ease-standard | continuidade: mostra para onde cada linha foi. | reorder corta; ícone mantém |
| check-pop | marcar · check entra com overshoot leve (scale 0.6→1.12→1) | 200ms ease-spring | sensação tátil de "encaixou"; restrito a confirmações. | corta (estado final) |
| tab-underline | trocar aba · sublinhado realça a aba ativa | 200ms ease-standard | continuidade — liga o clique ao conteúdo trocado. | corta |
| drawer-in | abrir · painel desliza da direita; backdrop faz fade | 240ms ease-standard | a direção mapeia "entrou pela borda"; não tira o foco do board. | vira fade |
| toast-in | fim da ação · entra de baixo + fade; auto-some | 200ms ease-out | fecha o loop ação→confirmação sem bloquear o fluxo. | reduz (fade curto) |
| card-lift | hover no card · sobe 2px + sombra cardHover | 150ms ease-out | affordance de "clicável" + profundidade leve. | corta o translate |
| skeleton | loading · shimmer horizontal contínuo no bloco | 1.4s loop linear | comunica "carregando" preservando layout (sem shift). | para o shimmer |
| progress-fill | mudança de valor · barra cresce até o % | 300/500ms ease-out | semântica de progresso contínuo — só aqui o "lento" cabe. | corta a transição |
| chevron-rotate | abrir select · chevron gira 180° | 150ms ease-standard | confirma o estado aberto/fechado. | corta |
- Stagger de cards no Kanban — atrasa a leitura de quem varre o board.
- Reorder animado em lista > ~30 linhas — vira janky e não ajuda.
- Loops decorativos e page transitions — ferramenta de trabalho, não vitrine.
- Hover com bounce/elastic — só o check usa overshoot, e com parcimônia.
Benchmark
- Tokenização real (zero hex na lógica) com paridade Tailwind ↔ CSS var ↔ catálogo.
- Token de domínio (DI Canal) como cidadão de 1ª classe — raro e certo.
- Uma P2Table<T> tipada e única reaproveitada em todas as telas.
- Foco visível por padrão; documentação viva em camadas (Storybook + /ds-final).
| Lacuna | Referência | Como aplicar |
|---|---|---|
| Tokens em 3 camadas (primitive → semantic → component) | Material 3 · Carbon · ADS | A V2 (novas cores) muda só a camada semântica — sem caçar usos. Destrava dark + densidade de uma vez. |
| Modo de densidade global (compact/comfortable) | Carbon · Linear · Ant | data-density no shell → tabela, inputs, ícones e paddings reagem juntos. Casa com a marca anti-scroll. |
| Tabela de classe mundial | Ant · Carbon · AG Grid | header sticky + coluna processo congelada + resize + bulk bar + tríade vazio/loading/erro. |
| Theming light/dark | Material 3 · Radix · shadcn | darkMode por seletor; como o kit só lê tokens semânticos, o dark "cai" sem tocar componente. |
| Changelog versionado do DS | Linear · Carbon · Polaris | gerar de components.json history[]; marcar breaking changes. (release-notes.json está vazio.) |
| Code Connect publicado (Figma↔código) | Carbon · Primer · ADS | figmaNodeId já existe; publicar liga o nó do Dev Mode ao snippet P2* real. |
| Diretrizes de conteúdo / UX writing | Polaris (referência mundial) | voz/tom, sentence case, formato de processo/moeda, microcopy de erro/vazio com glossário Razac. |
Telas atuais
- Faltam 3 das 8 etapas reais (Entrega, Aguardando Nac., Fechamento).
- Contador da coluna mente sob filtro — mostrar "X de TOTAL".
- Sem paginação/"ver mais" — board trava no volume real.
- Atraso deveria herdar danger (vermelho), não warning.
- Filtros/segmented eram estado morto — não filtravam a tabela.
- Seleção sem ação em lote (bulk bar).
- Incoterm duplicado (chip + coluna).
- Toggle "grade" morto.
- "Bloqueia DI" bem visível, mas "Conferir" ignorava o bloqueio.
- Divergência precisa aparecer na linha do item, não só na aba.
- Alíquota editável que não recalcula — erro fiscal latente.
- Painel mais raso que o baseline (sem regime por tributo, sem nac × venda).
- Números de demo desalinhados (KPI ↔ fila ↔ subtítulo).
O que já foi aplicado no DS
Tudo isso vive no kit @/components/portal2/kit — propaga pro Kanban, Invoices, Detalhe, Triagem e Sala de Testes de uma vez.