Tema
BaseToast
Aviso curto que confirma uma ação logo depois dela, como "Medição aprovada", e pode oferecer um jeito de voltar atrás ("Desfazer"). Aparece no canto inferior direito, fica 6 segundos e some sozinho.
Uso
- Use o aviso para confirmar o que a pessoa acabou de fazer: salvar, aprovar, enviar, excluir. O título diz o resultado com as palavras da tela; o texto, se houver, diz o que acontece depois.
- Uma ação no máximo, com um verbo curto: "Desfazer", "Ver medição". Ao clicar, o aviso fecha e a ação roda.
- O aviso some. Tudo o que ele diz precisa estar também na tela ou no histórico, e o "Desfazer" precisa de outro caminho (por exemplo, no histórico da medição). Ninguém pode depender de pegar o aviso a tempo.
- Não use o aviso para erro que impede seguir, para pedir confirmação ou para validação de campo. Erro de formulário fica no campo (
BaseField); confirmação fica num diálogo. - Cabem 3 avisos ao mesmo tempo. Um quarto aviso tira o mais antigo, a não ser que o mouse ou o foco esteja nele; nesse caso sai o mais antigo seguinte.
- Monte um único
<BaseToast />na raiz do app, perto do fim da página. Qualquer componente mostra um aviso comuseToast().show(). Se houver mais de um montado, só o primeiro mostra os avisos, para que nada apareça nem seja anunciado duas vezes.
Tons
O tom padrão é success. Cada tom tem um ícone de forma própria, e o leitor de tela ouve o tom antes do título ("Erro: Medição não enviada"). O tom neutral não tem prefixo falado.
Tempo na tela
- Cada aviso fica 6 segundos. A contagem de todos para enquanto o mouse está sobre um aviso ou o foco está dentro de um deles, e continua do ponto onde parou quando os dois saem.
- A tecla F8 leva o foco, de qualquer ponto da página, ao primeiro botão do aviso mais novo, e com isso a contagem para. Esc fecha o aviso e devolve o foco a onde estava.
- No celular, tocar no aviso não para a contagem; quem usa toque fecha o aviso pelo botão ou usa a ação a tempo.
- Cada aviso tem um botão de fechar.
Estilo
| Propriedade | Token |
|---|---|
| Fundo | --tj-background-inverse |
| Título e botões | --tj-text-inverse, título em --tj-weight-semibold |
| Texto | --tj-text-inverse a 72 %, --tj-text-sm |
| Ícone do tom | Par de BaseBadge: --tj-support-*-subtle com --tj-support-*-text, num círculo de --tj-icon-lg (24 px). Ver nota abaixo |
Ícone neutral | --tj-layer-accent-01 com --tj-text-secondary |
| Raio | --tj-radius-lg (12 px) |
| Elevação | --tj-shadow-3 (modal e aviso) |
| Espaço interno | --tj-space-4; entre ícone, texto e botões --tj-space-3; entre avisos --tj-space-2 |
| Largura | 380 px; no celular, a largura da tela menos --tj-space-4 de cada lado |
| Distância da borda | --tj-space-6 (celular --tj-space-4); embaixo, --tj-toast-offset quando a tela tem barra fixa |
| Foco | Linha interna de 2 px em --tj-text-inverse mais --tj-ring |
| Entrada | Sobe 8 px com --tj-duration-moderate-02 e --tj-easing-entrance; sem animação com prefers-reduced-motion |
O ícone do tom é diferente do protótipo v3. O protótipo desenhava só o ícone de sucesso, solto, em --tj-icon-md (20 px) com --tj-support-success-on-inverse. Só o tom de sucesso tem um token on-inverse, então os quatro tons ficam num círculo com o par de cores do BaseBadge, que mantém o contraste sobre o fundo invertido nos dois temas. Essa troca ainda precisa do aceite do dono do protótipo.
Numa tela com barra fixa no rodapé, como a barra de aprovação, suba a pilha com a variável --tj-toast-offset. Como o <BaseToast /> fica na raiz do app, fora da página, defina a variável na raiz do documento enquanto a página estiver aberta. No celular a barra é mais alta, então a distância muda:
css
:root:has(.measurement-page) { --tj-toast-offset: 96px; }
@media (max-width: 575.98px) {
:root:has(.measurement-page) { --tj-toast-offset: 168px; }
}Código
vue
<!-- App.vue, uma vez -->
<BaseToast />ts
import { useToast } from '@lab-inovacao/design-system'
const { show } = useToast()
show({
title: 'Medição aprovada',
text: 'Medição 29 · vai para assinatura',
action: { label: 'Desfazer', onClick: undoApproval },
})BaseToast não tem propriedades nem eventos. useToast() devolve:
| Função | Descrição |
|---|---|
show(options) | Mostra um aviso e devolve o id dele |
dismiss(id) | Fecha um aviso |
dismissAll() | Fecha todos os avisos |
Opções de show:
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
title | string | — | Resultado da ação, obrigatório |
text | string | — | Detalhe ou o que acontece depois |
tone | 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'success' | Significado do aviso |
action | { label: string, onClick: () => void } | — | Uma ação; o aviso fecha antes de ela rodar |
Os tipos ToastOptions e ToastAction são exportados junto com o componente.
Acessibilidade
- Usa o papel
statusdo WAI-ARIA (WCAG 4.1.3, técnica ARIA22). A região viva é um elemento oculto, comrole="status",aria-live="polite"earia-atomic="false", que fica na página mesmo vazia: uma região viva só anuncia o que entra depois que ela existe. Ela recebe só o texto do aviso novo, por exemplo "Sucesso: Medição aprovada. Vai para assinatura. F8 leva ao botão Desfazer.", sem os nomes dos botões, sem interromper a pessoa e sem repetir os outros avisos. - Todo tom é anunciado de forma educada, inclusive
error: o leitor de tela pode ler "Medição não enviada" só depois do que estiver lendo. Erro que pede atenção imediata usaBaseAlertBannercomrole="alert". - A pilha visível é uma região chamada "Avisos (F8)". Cada aviso é um grupo com o título como nome, e o botão de ação tem o título como descrição. O botão de fechar se chama "Fechar aviso: " seguido do título. Assim, com dois avisos na tela, cada "Desfazer" e cada "Fechar" se distingue (WCAG 1.3.1 e 2.4.6).
- O aviso não rouba o foco. A tecla F8 leva o foco ao aviso mais novo, de qualquer ponto da página; dentro dele, Tab passa entre os botões, que são
<button>nativos, com Enter e Espaço. Avise sobre o F8 na ajuda do sistema. - A contagem para com o mouse sobre um aviso ou o foco dentro de um deles (WCAG 2.2.1). O aviso com o foco ou com o mouse nunca é tirado por um aviso novo.
- Se o aviso fecha com o foco dentro dele, o foco volta ao elemento que estava focado quando o aviso apareceu, sem rolar a página; se ele saiu da página, vai para o botão de fechar do aviso vizinho; sem nenhum dos dois, o foco volta ao corpo da página. O foco nunca fica num elemento removido.
- A cor nunca está sozinha: cada tom tem um ícone de forma diferente e um prefixo falado. O ícone fica num círculo com o par de cores do
BaseBadge, que mantém o contraste nos dois temas. - Os botões têm 32 px de altura, acima do alvo mínimo de 24 px (WCAG 2.5.8).
- No modo de alto contraste do Windows, cada aviso ganha borda e o foco ganha contorno
Highlight. - Testado com axe na região vazia, em todos os tons, com e sem texto e ação, e com a pilha cheia e o foco dentro dela. Os testes também cobrem o F8, os nomes distintos dos botões, o texto anunciado e o toque que não pausa a contagem.