Progress
templates/components/Progress
É o único componente cujo significado é um número em movimento (0–100) representando o avanço de uma operação temporal/assíncrona — upload, processamento, quota, arrecadação, força de senha. Por isso os enriquecedores giram em torno de LER, interpretar e reagir a esse número e ao ciclo de vida da operação — nunca de reestilizar a barra.
Base congelada
Capacidades 8
Conteúdo
Rótulo de valor
Exibe a leitura numérica do progresso…
Marcador de meta
Fixa um traço de referência num…
Buffer (progresso secundário)
Camada secundária no mesmo token primary…
Selo de conclusão
Ao chegar a 100%, acrescenta uma…
Tempo restante (ETA)
Deriva do ritmo de avanço uma…
Legenda / rótulo descritivo
Texto livre descrevendo a operação em…
Cor por faixa (limiar semântico) ⚠️
Troca o preenchimento por tokens semânticos…
Comportamento
Indeterminado
Quando o valor é desconhecido, o…
Claude Code
Cole no Claude Code — ele acerta de primeira.
Progress (UI) — Design System (Symfony UX Toolkit / shadcn)
BASE CONGELADA (não mude por instância): Estrutura de dois slots congelada: track `div[role=progressbar]` + `div[data-slot=progress-indicator]`, com altura `h-1`, largura `w-full`, cantos `rounded-full`, track `bg-muted`, indicador `bg-primary`, `overflow-x-hidden` e `transition-all`. O preenchimento é sempre `translateX(-(100-value)%)`. Prop única `value` (0–100). a11y imutável: `role=progressbar`, `aria-valuemin=0`, `aria-valuemax=100`, `aria-valuenow=value`. Altura, cor primária, cantos e tipografia são intocáveis — consequência direta: "tamanho da barra" (h-1 → h-2/h-3) NÃO é enricher, é decisão de base (muda para todos em app.css). Rótulos textuais adotam a tipografia congelada do DS e ficam FORA da barra (a h-1 é fina demais para texto interno).
USO: <twig:Progress />
CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Rótulo de valor: Exibe a leitura numérica do progresso como texto ao lado da barra, sem tocar na barra. [select → Porcentagem (56%) / Fração (56/100) / Medida (5,6/10 MB) / Sem rótulo]- Indeterminado: Quando o valor é desconhecido, o indicador vira uma animação em laço; a a11y remove aria-valuenow. [toggle]- Marcador de meta: Fixa um traço de referência num alvo (ex.: 80%) para usar a barra como medidor de objetivo — orçamento, arrecadação, KPI. [number]- Buffer (progresso secundário): Camada secundária no mesmo token primary com menor ênfase, para dois níveis: 'carregado vs. processado' ou buffer de streaming. [toggle]- Selo de conclusão: Ao chegar a 100%, acrescenta uma marca de conclusão (ícone check e/ou texto 'Concluído') — conteúdo aditivo do ciclo de vida. [select → Sem selo / Ícone (check) / Texto (Concluído) / Ícone + texto]- Tempo restante (ETA): Deriva do ritmo de avanço uma estimativa de tempo ('~2 min restantes') exibida como texto — comportamental e aditivo. [toggle]- Legenda / rótulo descritivo: Texto livre descrevendo a operação em curso ('Enviando relatório…', '3 de 5 etapas'), acima ou abaixo da barra. [text]- Cor por faixa (limiar semântico): Troca o preenchimento por tokens semânticos de estado conforme a faixa de valor (risco/atenção/sucesso) — útil em força de senha/quota. Honestamente TOCA na cor: a paleta de estado é decisão de base (definida uma vez em app.css); só o gatilho por faixa seria o opt-in. [multi → Faixa de risco (baixo) / Faixa de atenção (médio) / Faixa de sucesso (alto)] (⚠️ borderline: revisar se não é decisão de base)FAÇA:
- Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.
- Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.
- Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}.
NÃO FAÇA:
- Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.
- Não crie variante/fork para a mesma coisa — existe UMA base por componente.
- Não reimplemente o componente nem adicione toolchain Node.
TESTE ANTES DE MUDAR: "é função ou é base?" — função = capacidade opt-in; base = mude o token na fonte única (assets/styles/app.css), para todos.
A11Y (herdada da base): Estrutura de dois slots congelada: track `div[role=progressbar]` + `div[data-slot=progress-indicator]`, com altura `h-1`, largura `w-full`, cantos `rounded-full`, track `bg-muted`, indicador `bg-primary`, `overflow-x-hidden` e `transition-all`. a11y imutável: `role=progressbar`, `aria-valuemin=0`, `aria-valuemax=100`, `aria-valuenow=value`
LLM / MCP
Via MCP: tool get_component com {"id": "progress"} · list_capabilities("progress").
Spec crua: config/ds-specs/progress.json · Conectar o MCP.
Spec machine-readable (JSON)
{
"$schema_version": "1.0",
"id": "progress",
"component": "Progress",
"eixo": "ui",
"particularidade": "É o único componente cujo significado é um número em movimento (0–100) representando o avanço de uma operação temporal/assíncrona — upload, processamento, quota, arrecadação, força de senha. Por isso os enriquecedores giram em torno de LER, interpretar e reagir a esse número e ao ciclo de vida da operação — nunca de reestilizar a barra.",
"base_congelada": "Estrutura de dois slots congelada: track `div[role=progressbar]` + `div[data-slot=progress-indicator]`, com altura `h-1`, largura `w-full`, cantos `rounded-full`, track `bg-muted`, indicador `bg-primary`, `overflow-x-hidden` e `transition-all`. O preenchimento é sempre `translateX(-(100-value)%)`. Prop única `value` (0–100). a11y imutável: `role=progressbar`, `aria-valuemin=0`, `aria-valuemax=100`, `aria-valuenow=value`. Altura, cor primária, cantos e tipografia são intocáveis — consequência direta: \"tamanho da barra\" (h-1 → h-2/h-3) NÃO é enricher, é decisão de base (muda para todos em app.css). Rótulos textuais adotam a tipografia congelada do DS e ficam FORA da barra (a h-1 é fina demais para texto interno).",
"props": [
{
"name": "value",
"type": "integer",
"default": "0",
"description": "The progress percentage (0-100). Defaults to `0` #}"
}
],
"capacidades": [
{
"id": "r-tulo-de-valor",
"nome": "Rótulo de valor",
"descricao": "Exibe a leitura numérica do progresso como texto ao lado da barra, sem tocar na barra.",
"controle": "select",
"opcoes": [
"Porcentagem (56%)",
"Fração (56/100)",
"Medida (5,6/10 MB)",
"Sem rótulo"
],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "indeterminado",
"nome": "Indeterminado",
"descricao": "Quando o valor é desconhecido, o indicador vira uma animação em laço; a a11y remove aria-valuenow.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "marcador-de-meta",
"nome": "Marcador de meta",
"descricao": "Fixa um traço de referência num alvo (ex.: 80%) para usar a barra como medidor de objetivo — orçamento, arrecadação, KPI.",
"controle": "number",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "buffer-progresso-secund-rio",
"nome": "Buffer (progresso secundário)",
"descricao": "Camada secundária no mesmo token primary com menor ênfase, para dois níveis: 'carregado vs. processado' ou buffer de streaming.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "selo-de-conclus-o",
"nome": "Selo de conclusão",
"descricao": "Ao chegar a 100%, acrescenta uma marca de conclusão (ícone check e/ou texto 'Concluído') — conteúdo aditivo do ciclo de vida.",
"controle": "select",
"opcoes": [
"Sem selo",
"Ícone (check)",
"Texto (Concluído)",
"Ícone + texto"
],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "tempo-restante-eta",
"nome": "Tempo restante (ETA)",
"descricao": "Deriva do ritmo de avanço uma estimativa de tempo ('~2 min restantes') exibida como texto — comportamental e aditivo.",
"controle": "toggle",
"opcoes": [],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "legenda-r-tulo-descritivo",
"nome": "Legenda / rótulo descritivo",
"descricao": "Texto livre descrevendo a operação em curso ('Enviando relatório…', '3 de 5 etapas'), acima ou abaixo da barra.",
"controle": "text",
"opcoes": [],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/progress; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "cor-por-faixa-limiar-sem-ntico",
"nome": "Cor por faixa (limiar semântico)",
"descricao": "Troca o preenchimento por tokens semânticos de estado conforme a faixa de valor (risco/atenção/sucesso) — útil em força de senha/quota. Honestamente TOCA na cor: a paleta de estado é decisão de base (definida uma vez em app.css); só o gatilho por faixa seria o opt-in.",
"controle": "multi",
"opcoes": [
"Faixa de risco (baixo)",
"Faixa de atenção (médio)",
"Faixa de sucesso (alto)"
],
"posicionavel": false,
"e_funcao": false,
"como_plugar": "REPROVADO no teste 'é função ou é base' — NÃO plugar como capacidade. É decisão de BASE: mude o token na fonte única assets/styles/app.css, valendo para TODOS os componentes."
}
],
"snippet_uso": "<twig:Progress />",
"exemplo_demo": "<twig:Progress value=\"56\" class=\"w-[60%]\" />",
"regras": {
"faca": [
"Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.",
"Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.",
"Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}."
],
"nao_faca": [
"Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.",
"Não crie variante/fork para a mesma coisa — existe UMA base por componente.",
"Não reimplemente o componente nem adicione toolchain Node."
]
},
"a11y": "Estrutura de dois slots congelada: track `div[role=progressbar]` + `div[data-slot=progress-indicator]`, com altura `h-1`, largura `w-full`, cantos `rounded-full`, track `bg-muted`, indicador `bg-primary`, `overflow-x-hidden` e `transition-all`. a11y imutável: `role=progressbar`, `aria-valuemin=0`, `aria-valuemax=100`, `aria-valuenow=value`",
"mcp": {
"tool": "get_component",
"args": {
"id": "progress"
}
}
}