# Contrato · Icon

> Segue o modelo de `contratos/ruler.md`. Implementado em
> `app/src/componentes/Icon/Icon.tsx`, registro de path em
> `estilo/icones.mjs` (apelido `@estilo`). Único componente dos 18 sem
> contrato até 17/set/2026 — existia código, stories e teste, faltava só
> este documento.
>
> **Renomeado de `icone.md` em 21/set/2026**: o identificador de código virou
> `Icon`/`name`/`label`/`size` (era `Icone`/`nome`/`rotulo`/`tamanho`),
> mesma leva do `Botao`→`Button` — ver `contratos/button.md` pro motivo
> (feedback do Abner, front-end sênior do `bridge`).

**Pré-requisito dos outros, não um dos 7 da Fase 1.** Documento, Option,
Popover e Button (ícone-só) todos dependem dele.

## Biblioteca — decisão confirmada, não aberta

**Tabler** (tabler.io/icons), outline 24×24. Confirmado pelo Alessandro em
17/set/2026: mesmo set que o shadcnblocks usa, preferência explícita, não só
"o que já estava lá".

Achado revisando `landbank-prototipo/landbank.html` na mesma rodada: o
comentário do arquivo dizia "Do lucide, verbatim" — **estava errado**.
Conferido byte a byte (`chevron-right`, `search`): os paths são idênticos
aos deste registro. É Tabler nos dois lugares, só o comentário lá estava
com o nome trocado. Corrigido no arquivo de origem.

`estilo/icones.mjs` é a **fonte única**: 51 ícones, extraídos do `<script>`
clássico que vivia em `prototipo/index.html`, incluindo uma chave duplicada
achada e corrigida na extração (`map-2` e `file-text` — a última declaração
silenciosamente vencia, a primeira nunca executava). Os NOMES dos ícones em
si (as chaves, tipo `"check"`/`"chevron-down"`) não mudaram nesta leva — já
são inglês, vêm direto do Tabler.

## Props

| Prop | Tipo | Observação |
|---|---|---|
| `name` | `IconName` (chave de `ICONES`) | obrigatória. Nome errado **quebra em desenvolvimento**, não renderiza vazio em silêncio |
| `label` | `string` (opcional) | só quando o ícone carrega sentido sozinho, sem texto nem `aria-label` no pai (mesma convenção de `Button`/`Badge`) |
| `size` | `number` (opcional) | px. Sem isto, herda `--is` do componente pai — só definir quando o ícone estiver solto |

## Path vem do registro, cor e tamanho não são do componente

Zero valor de `path`, `viewBox` ou cor neste arquivo — path vem de
`estilo/icones.mjs`, cor vem de `currentColor` (o consumidor decide via CSS,
igual texto), tamanho vem de `--is`. Mesma disciplina de token da Regra 3.

## Escala de tamanho

`--icon-xs:8px · --icon-sm:12px · --icon-md:14px · --icon-lg:16px ·
--icon-xl:20px`. Button e Badge já fixam `--is` sozinhos por variant/tamanho —
`Icon` só herda.

**Pendência aberta, achada nesta rodada**: `.navi` (rail de navegação, ver
`extracao-componentes-landbank.md`) usa `--is:17px` — não bate em nenhum
degrau da escala (o mais próximo é `--icon-lg`, 16px). 1px de deriva sem
registro do porquê. Perguntar antes de "corrigir": pode ser nudge óptico
proposital (mesma categoria da Regra 10, seção "nudge óptico de menos de
4px"), não erro de arredondamento.

## Variante por sufixo do nome, não por prop

`name.endsWith('-f')` → preenchido (`fill:currentColor`, sem stroke).
`name.endsWith('-s')` → sólido (`fill` + `stroke-width:2.2`, mais grosso que
o outline padrão). Nenhuma das duas é prop — é o nome do ícone que decide,
mesma convenção de `hidrataIcones()` no protótipo, pra visual não divergir
entre os dois lugares.

**Stroke do outline é 1.8, não o 2 "oficial" do Tabler** — decisão já
tomada antes deste contrato existir (ver `Icon.tsx`), consistente com o
resto do sistema (mesmo valor usado nos ícones da narração de carregamento,
`componentes-para-reuso.md`). Não é erro, é o stroke padrão daqui.

## Acessibilidade

- Sem `label`: `aria-hidden`, decorativo — a peça que envolve já diz o que
  significa.
- Com `label`: `role="img"` + `aria-label`. Decisão de qual caso se aplica
  é de quem usa o componente, não um default arriscado (mesmo texto do
  contrato do `Avatar`).

## Fora do contrato

- **Sem ícone fora do registro.** Se faltar um ícone, ele entra em
  `estilo/icones.mjs` primeiro — não se cola um SVG solto num componente
  pra não esperar a extração.
- **Sem animação própria.** Ícone que gira/pulsa (como `.cv` do `NavGroup`)
  é CSS de quem consome, não comportamento do `Icon`.

## Pendências deste componente

- Os 17px do `.navi` (ver acima) — decisão pendente, não travando nada.
- Sem página de documentação própria — não é um dos 7 da Fase 1.
