@iclips/ui 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,192 @@
1
+ # Qual overlay usar
2
+
3
+ Todos flutuam acima da página, mas resolvem problemas diferentes. A pergunta que separa é: **o conteúdo exige uma ação do usuário** (então prende o foco) ou **só complementa** (então some ao clicar fora)?
4
+
5
+ ## Tabela de decisão
6
+
7
+ | Overlay | Escolha quando | Evite quando |
8
+ | --- | --- | --- |
9
+ | Tooltip | rótulo curto para um ícone ou controle sem texto — aparece no hover/foco, some sozinho. | o conteúdo tem link, botão ou texto que o usuário precise ler com calma → `Popover`. |
10
+ | HoverCard | prévia rica e não-essencial de algo já visível (card de usuário, resumo de projeto). | a informação é necessária para a tarefa, ou o gatilho é em mobile (não há hover) → `Popover`. |
11
+ | Popover | um pequeno painel ancorado a um botão: filtro, seletor de cor, mini-formulário, menu de ações. | há mais de ~6 campos ou o fluxo tem etapas → `Dialog` ou `Sheet`. |
12
+ | Dialog | uma tarefa focada que interrompe o fluxo: editar um registro, confirmar com contexto, wizard curto. | é só um aviso de sim/não destrutivo → `AlertDialog`. Formulário longo → `Sheet`. |
13
+ | AlertDialog | confirmação de ação destrutiva ou irreversível (excluir, cancelar assinatura). Trava até o usuário decidir. | a ação não é perigosa e é desfazível → use um Toast com "Desfazer". |
14
+ | Sheet | painel lateral para formulário longo, detalhes ou configurações sem perder o contexto da lista atrás. | a tarefa é curta e centrada → `Dialog`. Navegação primária do app → não é overlay. |
15
+ | Drawer | o mesmo papel do Sheet, mas puxado de baixo — padrão em telas de toque/mobile. | desktop com espaço de sobra → `Sheet` lateral. |
16
+
17
+ ## Trilha rápida
18
+
19
+ Responda de cima para baixo e pare na primeira que servir.
20
+
21
+ 1. **A ação é destrutiva/irreversível e precisa de confirmação?** Sim: `AlertDialog`. Não: continue.
22
+ 2. **É só um rótulo de texto para um ícone?** Sim: `Tooltip`. Não: continue.
23
+ 3. **É uma prévia opcional de algo que já está na tela?** Sim: `HoverCard` (desktop) — mas garanta um caminho por clique no mobile. Não: continue.
24
+ 4. **Cabe em um painelzinho de até ~6 campos ancorado ao gatilho?** Sim: `Popover`. Não: continue.
25
+ 5. **O usuário precisa ver a lista/tela de trás enquanto preenche?** Sim: `Sheet` (desktop) ou `Drawer` (toque). Não: `Dialog`.
26
+
27
+ ## Exemplos
28
+
29
+ ### Tooltip — rótulo de ícone
30
+
31
+ Some ao tirar o mouse ou o foco. Sem conteúdo interativo dentro. Balão neutro invertido: é informação, não ação. Precisa de um `TooltipProvider` acima (uma vez, na raiz).
32
+
33
+ ```tsx
34
+ import { Button, Tooltip, TooltipContent, TooltipTrigger } from "@iclips/ui";
35
+ import { Archive } from "lucide-react";
36
+
37
+ <Tooltip>
38
+ <TooltipTrigger asChild>
39
+ <Button variant="outline" size="icon" aria-label="Arquivar">
40
+ <Archive className="size-4" />
41
+ </Button>
42
+ </TooltipTrigger>
43
+ <TooltipContent>Arquivar</TooltipContent>
44
+ </Tooltip>
45
+ ```
46
+
47
+ ### Popover — mini-formulário
48
+
49
+ Fecha ao clicar fora. Bom para 1–6 campos.
50
+
51
+ ```tsx
52
+ import { Button, Input, Label, Popover, PopoverContent, PopoverTrigger } from "@iclips/ui";
53
+
54
+ <Popover>
55
+ <PopoverTrigger asChild>
56
+ <Button variant="outline">Renomear</Button>
57
+ </PopoverTrigger>
58
+ <PopoverContent className="w-64 space-y-2">
59
+ <Label htmlFor="novo-nome">Novo nome</Label>
60
+ <Input id="novo-nome" defaultValue="Campanha Q3" />
61
+ </PopoverContent>
62
+ </Popover>
63
+ ```
64
+
65
+ ### Dialog — tarefa focada
66
+
67
+ Prende o foco. Título + descrição + ações.
68
+
69
+ ```tsx
70
+ import {
71
+ Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
72
+ DialogTrigger, Input, Label,
73
+ } from "@iclips/ui";
74
+
75
+ <Dialog>
76
+ <DialogTrigger asChild>
77
+ <Button>Editar perfil</Button>
78
+ </DialogTrigger>
79
+ <DialogContent>
80
+ <DialogHeader>
81
+ <DialogTitle>Editar perfil</DialogTitle>
82
+ <DialogDescription>As alterações são salvas ao confirmar.</DialogDescription>
83
+ </DialogHeader>
84
+ <div className="grid gap-1.5 py-2">
85
+ <Label htmlFor="nome">Nome</Label>
86
+ <Input id="nome" defaultValue="Ana Souza" />
87
+ </div>
88
+ <DialogFooter>
89
+ <DialogClose asChild><Button variant="outline">Cancelar</Button></DialogClose>
90
+ <Button>Salvar</Button>
91
+ </DialogFooter>
92
+ </DialogContent>
93
+ </Dialog>
94
+ ```
95
+
96
+ ### AlertDialog — confirmação destrutiva
97
+
98
+ Sem clicar-fora-para-fechar. Uma escolha explícita.
99
+
100
+ ```tsx
101
+ import {
102
+ AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription,
103
+ AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Button,
104
+ } from "@iclips/ui";
105
+
106
+ <AlertDialog>
107
+ <AlertDialogTrigger asChild>
108
+ <Button variant="destructive">Excluir projeto</Button>
109
+ </AlertDialogTrigger>
110
+ <AlertDialogContent>
111
+ <AlertDialogHeader>
112
+ <AlertDialogTitle>Excluir “Campanha Q3”?</AlertDialogTitle>
113
+ <AlertDialogDescription>
114
+ Esta ação não pode ser desfeita. Todos os itens do projeto serão removidos.
115
+ </AlertDialogDescription>
116
+ </AlertDialogHeader>
117
+ <AlertDialogFooter>
118
+ <AlertDialogCancel>Cancelar</AlertDialogCancel>
119
+ <AlertDialogAction>Excluir</AlertDialogAction>
120
+ </AlertDialogFooter>
121
+ </AlertDialogContent>
122
+ </AlertDialog>
123
+ ```
124
+
125
+ ### Sheet — formulário longo
126
+
127
+ A lista de trás continua visível como contexto.
128
+
129
+ ```tsx
130
+ import {
131
+ Button, Input, Label, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle,
132
+ SheetTrigger,
133
+ } from "@iclips/ui";
134
+
135
+ <Sheet>
136
+ <SheetTrigger asChild>
137
+ <Button variant="outline">Nova tarefa</Button>
138
+ </SheetTrigger>
139
+ <SheetContent className="w-full sm:max-w-md">
140
+ <SheetHeader>
141
+ <SheetTitle>Nova tarefa</SheetTitle>
142
+ <SheetDescription>Preencha os campos e salve.</SheetDescription>
143
+ </SheetHeader>
144
+ <div className="grid gap-3 px-4">
145
+ <div className="grid gap-1.5"><Label htmlFor="titulo">Título</Label><Input id="titulo" /></div>
146
+ <div className="grid gap-1.5"><Label htmlFor="responsavel">Responsável</Label><Input id="responsavel" /></div>
147
+ <div className="grid gap-1.5"><Label htmlFor="prazo">Prazo</Label><Input id="prazo" type="date" /></div>
148
+ </div>
149
+ <SheetFooter>
150
+ <Button>Criar tarefa</Button>
151
+ <SheetClose asChild><Button variant="outline">Cancelar</Button></SheetClose>
152
+ </SheetFooter>
153
+ </SheetContent>
154
+ </Sheet>
155
+ ```
156
+
157
+ ### HoverCard — prévia opcional
158
+
159
+ Só complementa. Nunca coloque aqui algo que a tarefa exige.
160
+
161
+ ```tsx
162
+ import { Button, HoverCard, HoverCardContent, HoverCardTrigger } from "@iclips/ui";
163
+
164
+ <HoverCard>
165
+ <HoverCardTrigger asChild>
166
+ <Button variant="link">@ana.souza</Button>
167
+ </HoverCardTrigger>
168
+ <HoverCardContent className="text-sm">
169
+ <p className="font-medium">Ana Souza</p>
170
+ <p className="text-muted-foreground">Designer · entrou em 2023</p>
171
+ </HoverCardContent>
172
+ </HoverCard>
173
+ ```
174
+
175
+ ## Faça / evite
176
+
177
+ #### Faça
178
+
179
+ - Dê a todo `Dialog`/`Sheet`/`AlertDialog` um título — é o rótulo que o leitor de tela anuncia.
180
+ - Reserve o `AlertDialog` para o que dói desfazer; para o resto, aja e ofereça "Desfazer" num Toast.
181
+ - No mobile, troque `Sheet` lateral por `Drawer` e `HoverCard` por `Popover` (toque não tem hover).
182
+ - Empilhe no máximo um overlay. Se precisar de outro, provavelmente o fluxo deveria ser uma página.
183
+
184
+ #### Evite
185
+
186
+ - Colocar um formulário de 15 campos num `Popover`.
187
+ - Usar `Tooltip` para conteúdo que tem link ou botão — o usuário não consegue alcançar.
188
+ - Pintar o `Tooltip` com a cor da marca (`bg-primary`) — overlay informativo não se veste de ação.
189
+ - Abrir um `Dialog` dentro de outro `Dialog`.
190
+ - Trocar toast de sucesso por `Dialog` "OK" — interrompe sem motivo.
191
+
192
+ **Acessibilidade:** `Dialog`, `AlertDialog`, `Sheet` e `Popover` vêm do Radix — prendem o foco, fecham no Esc e devolvem o foco ao gatilho de graça. O que você precisa garantir: um `Title` em todo painel modal, e `aria-label` em gatilhos que são só ícone.
package/docs/status.md ADDED
@@ -0,0 +1,71 @@
1
+ # Status
2
+
3
+ Status é **estado**: feedback, nunca decoração. Vermelho, verde, amarelo e azul só aparecem para dizer algo sobre um item. Status nunca é roxo (roxo é ação) e sempre vem com ícone ou rótulo — cor sozinha não identifica nada.
4
+
5
+ A receita é sempre suave: `bg-<status>/10 text-<status>-emphasis border-<status>/20`. Os componentes já a aplicam — use o componente em vez de montar as classes.
6
+
7
+ | Status | `variant` | Quando |
8
+ | --- | --- | --- |
9
+ | Sucesso | `success` | aprovado, pago, concluído, ativo |
10
+ | Aviso | `warning` | pendente, aguardando, vence em breve |
11
+ | Informação | `info` | em análise, rascunho enviado, novidade |
12
+ | Erro | `destructive` | recusado, vencido, falhou, cancelado |
13
+
14
+ ## Status de um item
15
+
16
+ Use `Badge` com a variante do status e um ícone ou rótulo claro.
17
+
18
+ ```tsx
19
+ import { Badge } from "@iclips/ui";
20
+ import { Check, CircleAlert, Clock, Info } from "lucide-react";
21
+
22
+ <Badge variant="success"><Check /> Aprovado</Badge>
23
+ <Badge variant="warning"><Clock /> Aguardando</Badge>
24
+ <Badge variant="info"><Info /> Em análise</Badge>
25
+ <Badge variant="destructive"><CircleAlert /> Recusado</Badge>
26
+ ```
27
+
28
+ Status que vem da API vira um mapa, não um `if` por status:
29
+
30
+ ```tsx
31
+ import { Badge } from "@iclips/ui";
32
+
33
+ const STATUS = {
34
+ pago: { variant: "success", rotulo: "Pago" },
35
+ pendente: { variant: "warning", rotulo: "Pendente" },
36
+ vencido: { variant: "destructive", rotulo: "Vencido" },
37
+ } as const;
38
+
39
+ function StatusParcela({ status }: { status: keyof typeof STATUS }) {
40
+ const { variant, rotulo } = STATUS[status];
41
+ return <Badge variant={variant}>{rotulo}</Badge>;
42
+ }
43
+ ```
44
+
45
+ Status neutro (sem juízo de bom ou ruim, como "Arquivado" ou "Inativo") usa `variant="muted"` ou `variant="outline"`, não uma cor de estado.
46
+
47
+ ## Valor positivo ou negativo
48
+
49
+ Número que sobe ou desce (variação, saldo, meta) usa o texto `-emphasis` do status, com sinal ou ícone — nunca só a cor.
50
+
51
+ ```tsx
52
+ import { TrendingDown, TrendingUp } from "lucide-react";
53
+
54
+ <span className="inline-flex items-center gap-1 text-success-emphasis">
55
+ <TrendingUp className="size-4" aria-hidden="true" /> +12,4%
56
+ </span>
57
+ <span className="inline-flex items-center gap-1 text-destructive-emphasis">
58
+ <TrendingDown className="size-4" aria-hidden="true" /> −3,1%
59
+ </span>
60
+ ```
61
+
62
+ ## Condição que vale para a tela toda
63
+
64
+ Se o status é da página e não de um item (plano expirando, modo somente-leitura), é um `Alert` — ver [Mensagens](mensagens.md).
65
+
66
+ ## Regras
67
+
68
+ - Status **nunca é roxo** e nunca é `text-<status>` cru em texto: use `text-<status>-emphasis`, que passa contraste AA nos dois temas.
69
+ - Não pinte **fundo de seção** ou card com cor de estado — o badge carrega o estado, não o card.
70
+ - Nunca fundo sólido de estado (`bg-success` sem `/10`): a cor cheia fica só no ícone e na borda de campo inválido.
71
+ - Mais regras de cor em [Linguagem visual](../DESIGN.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iclips/ui",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Design system da iClips — componentes React sobre Radix UI + Tailwind v4, paleta #7F26BF",
5
5
  "author": "iclipsbr",
6
6
  "license": "MIT",
@@ -49,6 +49,8 @@
49
49
  "LICENSE",
50
50
  "MIGRATION-v2.md",
51
51
  "MIGRATION-v3.md",
52
+ "DESIGN.md",
53
+ "docs",
52
54
  "scripts/check-colors.mjs"
53
55
  ],
54
56
  "peerDependencies": {