@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.
- package/DESIGN.md +246 -0
- package/README.md +4 -0
- package/dist/components/ui/primitives/badge.cjs +1 -1
- package/dist/components/ui/primitives/badge.cjs.map +1 -1
- package/dist/components/ui/primitives/badge.js +16 -13
- package/dist/components/ui/primitives/badge.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/docs/README.md +44 -0
- package/docs/acoes.md +103 -0
- package/docs/escolha.md +171 -0
- package/docs/formularios.md +137 -0
- package/docs/mensagens.md +114 -0
- package/docs/overlays.md +192 -0
- package/docs/status.md +71 -0
- package/package.json +3 -1
package/docs/overlays.md
ADDED
|
@@ -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.
|
|
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": {
|