@softize/opus 12.10.0 → 12.11.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/CHANGELOG.md +27 -0
- package/bin/lib/check.mjs +1103 -310
- package/bin/lib/copy.mjs +11 -0
- package/docs/adr/0003-dictionary-presentation-is-declared.md +3 -0
- package/docs/adr/0004-page-content-state-is-composed.md +65 -0
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +97 -0
- package/docs/adr/0006-semantic-context-precedes-visual-variant.md +182 -0
- package/package.json +1 -1
- package/registry/instructions/opus.md +5 -0
- package/registry/skills/build-opus-ui/SKILL.md +27 -16
- package/registry/skills/build-opus-ui/references/evaluations.md +16 -5
- package/registry/skills/build-opus-ui/references/ui-patterns.md +38 -15
- package/registry/skills/model-opus-dictionary/SKILL.md +4 -2
- package/registry/skills/model-opus-dictionary/references/evaluations.md +4 -3
- package/registry/templates/app/src/App.tsx +1 -1
- package/src/core/dictionary.ts +52 -14
- package/src/core/index.ts +10 -0
- package/src/core/ui-context.ts +29 -0
- package/src/schema/drivers/zod.ts +17 -8
- package/src/ui/components/patterns/action-form-card.tsx +18 -12
- package/src/ui/components/patterns/confirm.tsx +26 -3
- package/src/ui/components/patterns/content-header.tsx +335 -61
- package/src/ui/components/patterns/data-state.tsx +23 -10
- package/src/ui/components/patterns/list.tsx +1096 -777
- package/src/ui/components/patterns/page-state.tsx +115 -0
- package/src/ui/components/patterns/page.tsx +231 -41
- package/src/ui/components/patterns/sidebar.tsx +354 -80
- package/src/ui/components/patterns/trigger.tsx +13 -9
- package/src/ui/components/patterns/view.tsx +7 -11
- package/src/ui/components/primitives/alert-dialog.tsx +7 -5
- package/src/ui/components/primitives/alert.tsx +298 -110
- package/src/ui/components/primitives/ask.tsx +2 -1
- package/src/ui/components/primitives/badge.tsx +91 -30
- package/src/ui/components/primitives/button.tsx +99 -60
- package/src/ui/components/primitives/calendar.tsx +39 -39
- package/src/ui/components/primitives/card.tsx +96 -23
- package/src/ui/components/primitives/detail.tsx +2 -2
- package/src/ui/components/primitives/dictionary-value.tsx +9 -14
- package/src/ui/components/primitives/dot.tsx +74 -21
- package/src/ui/components/primitives/drawer.tsx +33 -20
- package/src/ui/components/primitives/item.tsx +137 -81
- package/src/ui/components/primitives/menu.tsx +11 -3
- package/src/ui/components/primitives/metric-card.tsx +133 -0
- package/src/ui/components/primitives/table.tsx +2 -2
- package/src/ui/docs/DocBrowser.tsx +3 -3
- package/src/ui/docs/changelog.tsx +1 -1
- package/src/ui/docs/content/action-form-card.md +1 -1
- package/src/ui/docs/content/alert-dialog.md +8 -8
- package/src/ui/docs/content/alert.md +49 -25
- package/src/ui/docs/content/badge.md +18 -19
- package/src/ui/docs/content/button.md +12 -9
- package/src/ui/docs/content/card.md +5 -5
- package/src/ui/docs/content/content.md +44 -0
- package/src/ui/docs/content/customization.md +2 -2
- package/src/ui/docs/content/detail.md +5 -2
- package/src/ui/docs/content/dialog.md +2 -2
- package/src/ui/docs/content/dictionary-value.md +11 -10
- package/src/ui/docs/content/dot.md +7 -7
- package/src/ui/docs/content/drawer.md +6 -3
- package/src/ui/docs/content/input-group.md +3 -2
- package/src/ui/docs/content/item.md +47 -21
- package/src/ui/docs/content/menu.md +5 -4
- package/src/ui/docs/content/metric-card.md +41 -0
- package/src/ui/docs/content/page-state.md +45 -0
- package/src/ui/docs/content/page.md +48 -10
- package/src/ui/docs/content/semantic-context.md +63 -0
- package/src/ui/docs/content/sidebar.md +4 -4
- package/src/ui/docs/content/skeleton.md +2 -2
- package/src/ui/docs/content/table.md +3 -3
- package/src/ui/docs/content/tokens.md +28 -0
- package/src/ui/docs/doc-client.tsx +2 -2
- package/src/ui/docs/registry.tsx +596 -228
- package/src/ui/lib/semantic-context.ts +30 -0
- package/src/ui/meta.ts +292 -270
- package/src/ui/react.tsx +378 -111
- package/src/ui/theme.css +66 -0
package/src/ui/meta.ts
CHANGED
|
@@ -7,427 +7,449 @@
|
|
|
7
7
|
* este subpath explicitamente (`@softize/opus/ui/meta`); o barrel de runtime (react.tsx) não
|
|
8
8
|
* o re-exporta de propósito (metadado de build-time, fora do bundle dos apps).
|
|
9
9
|
*/
|
|
10
|
-
import type { ComponentMeta } from
|
|
10
|
+
import type { ComponentMeta } from "./index.ts";
|
|
11
11
|
|
|
12
12
|
/** Todos os metas, chaveados pelo nome canônico (kebab). Fonte única — zero duplicação. */
|
|
13
13
|
export const componentMeta = {
|
|
14
|
-
|
|
15
|
-
name:
|
|
16
|
-
ancestry:
|
|
14
|
+
content: {
|
|
15
|
+
name: "content",
|
|
16
|
+
ancestry: "opus",
|
|
17
17
|
whenToUse:
|
|
18
|
-
|
|
18
|
+
"Região semântica nomeada dentro de uma página ou outra superfície. O shorthand cria ContentHeader e ContentBody; a forma explícita compõe Content > ContentHeader(ContentTitle/ContentDescription/ContentMeta/ContentActions) + ContentBody. ContentHeader nunca fica solto. Para o cabeçalho principal, use Page.",
|
|
19
19
|
},
|
|
20
|
-
|
|
21
|
-
name:
|
|
22
|
-
ancestry:
|
|
20
|
+
ask: {
|
|
21
|
+
name: "ask",
|
|
22
|
+
ancestry: "opus",
|
|
23
23
|
whenToUse:
|
|
24
|
-
|
|
24
|
+
"Elicitação estruturada controlada para 1–4 perguntas `AskQuestion`: opções single/multi em pills, texto livre opcional, validação e submit de `AskAnswer[]`. Não faz transporte, persistência nem integração automática com ChatEvent; o consumidor controla `answers`/`onChange` e conecta `onSubmit` ao canal apropriado.",
|
|
25
25
|
},
|
|
26
|
-
|
|
27
|
-
name:
|
|
28
|
-
ancestry:
|
|
26
|
+
alert: {
|
|
27
|
+
name: "alert",
|
|
28
|
+
ancestry: "opus",
|
|
29
29
|
whenToUse:
|
|
30
|
-
|
|
30
|
+
"Aviso inline no fluxo da página — `context` declara neutral/info/success/warning/danger e `variant` escolhe subtle/outline (ADR 0006). Forma curta: `<Alert title description icon context />`; para conteúdo rico, componha AlertMedia + AlertHeader (AlertTitle e AlertDescription) + AlertActions. A mídia acompanha a altura útil do header. O texto comunica o significado sem depender só da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
|
|
31
31
|
},
|
|
32
|
-
|
|
33
|
-
name:
|
|
34
|
-
ancestry:
|
|
32
|
+
badge: {
|
|
33
|
+
name: "badge",
|
|
34
|
+
ancestry: "shadcn",
|
|
35
35
|
whenToUse:
|
|
36
|
-
|
|
36
|
+
"Rótulo curto de status/categoria. `context` declara neutral/primary/info/success/warning/danger; `variant` escolhe solid/subtle/outline (ADR 0006). Não-interativo — para clique, use Button ou `asChild` num <a>. Valor de dicionário com papel declarado usa DictionaryValue em vez de escolher contexto ou variante na tela.",
|
|
37
37
|
},
|
|
38
|
-
|
|
39
|
-
name:
|
|
40
|
-
ancestry:
|
|
38
|
+
"empty-value": {
|
|
39
|
+
name: "empty-value",
|
|
40
|
+
ancestry: "opus",
|
|
41
41
|
whenToUse:
|
|
42
|
-
|
|
42
|
+
"Representação padrão de valor ausente (`null`, `undefined`, string vazia ou só espaços): em célula compacta (`compact`) mostra o travessão e reserva “Não informado” à leitura assistiva; em texto corrido mostra o rótulo. `label` troca o significado da ausência no domínio (“Nunca enviado”, “Sem vencimento”). `0` e `false` são valores, nunca ausência. Colunas de ActionList e DetailField já a usam; renderer customizado reutiliza em vez de repetir a condicional.",
|
|
43
43
|
},
|
|
44
|
-
|
|
45
|
-
name:
|
|
46
|
-
ancestry:
|
|
44
|
+
"dictionary-value": {
|
|
45
|
+
name: "dictionary-value",
|
|
46
|
+
ancestry: "opus",
|
|
47
47
|
whenToUse:
|
|
48
|
-
|
|
48
|
+
"Valor de um `t.dict` com apresentação declarada: `classification` vira Badge neutral/outline, `status` e `stage` viram Badge context/subtle, `plain` vira texto (ADRs 0003 e 0006). Ícone e tooltip vêm da metadata e o texto permanece presente. Overrides explícitos por `presentation`, `context`, `variant`, `icon`, `tooltip` e `fallback`; não inferir contexto, badge, cor ou ícone pelo nome do dicionário.",
|
|
49
49
|
},
|
|
50
|
-
|
|
51
|
-
name:
|
|
52
|
-
ancestry:
|
|
50
|
+
dot: {
|
|
51
|
+
name: "dot",
|
|
52
|
+
ancestry: "opus",
|
|
53
53
|
whenToUse:
|
|
54
|
-
|
|
54
|
+
"Sinal compacto de estado. `context` declara neutral/primary/info/success/warning/danger e `variant` escolhe solid/outline. Passe `label` quando a cor reforçar informação; sem label, o ponto é decorativo. Para texto visível, use Badge.",
|
|
55
55
|
},
|
|
56
|
-
|
|
57
|
-
name:
|
|
58
|
-
ancestry:
|
|
56
|
+
detail: {
|
|
57
|
+
name: "detail",
|
|
58
|
+
ancestry: "opus",
|
|
59
59
|
whenToUse:
|
|
60
|
-
'
|
|
60
|
+
'Dados somente leitura em pares chave/valor. Compõe DetailGroup > DetailField com semântica de lista de definições; `columns` controla a grade, `orientation` posiciona chave e valor e alinha uma coluna compartilhada de rótulos no modo horizontal, `variant="framed"` aplica moldura e `dividers` acrescenta somente as divisórias internas. Para entrada, validação e erro, use Field; para uma coleção pesquisável, use ActionList.',
|
|
61
61
|
},
|
|
62
|
-
|
|
63
|
-
name:
|
|
64
|
-
ancestry:
|
|
62
|
+
dock: {
|
|
63
|
+
name: "dock",
|
|
64
|
+
ancestry: "opus",
|
|
65
65
|
whenToUse:
|
|
66
|
-
|
|
66
|
+
"Barra de ferramentas ancorada a uma superfície de trabalho — canvas, editor, preview —, quando um cabeçalho empilharia mais uma faixa de chrome sobre a trilha. Compõe Dock > DockGroup > DockAction; o estado da superfície (salvamento, versão) fica no SurfaceStatus, que flutua num canto e não pertence à barra. `position` escolhe a aresta; a divisória entre grupos é do componente. Requer TooltipProvider na raiz. Para ações de uma PÁGINA, use as `actions` do Page; para um conjunto de toggles exclusivos, ToggleGroup.",
|
|
67
67
|
},
|
|
68
|
-
|
|
69
|
-
name:
|
|
70
|
-
ancestry:
|
|
68
|
+
button: {
|
|
69
|
+
name: "button",
|
|
70
|
+
ancestry: "shadcn",
|
|
71
71
|
whenToUse:
|
|
72
|
-
'
|
|
72
|
+
'Ação clicável. `context` declara neutral/primary/danger e `variant` escolhe solid/subtle/outline/ghost/link (ADR 0006). `size` define altura (default/sm/lg · icon/icon-sm/icon-xs) e `shape="pill"` troca somente a geometria. `busy` mostra spinner e desabilita. Ação destrutiva usa `context="danger"`; `destructive` continua sendo metadata comportamental do contrato.',
|
|
73
73
|
},
|
|
74
|
-
|
|
75
|
-
name:
|
|
76
|
-
ancestry:
|
|
74
|
+
card: {
|
|
75
|
+
name: "card",
|
|
76
|
+
ancestry: "shadcn",
|
|
77
77
|
whenToUse:
|
|
78
|
-
'
|
|
78
|
+
'Superfície da casa (bg-card + text-card-foreground + borda + rounded-xl, flat). Box simples: `<Card className="p-4">…</Card>`. Estruturado: Card > CardHeader(CardTitle/CardDescription) + CardBody + CardFooter — o padding mora nos slots (como o Dialog). `CardContent` é um alias temporário de compatibilidade. Divergência declarada vs shadcn: sem shadow e sem flex/gap forçados (o upstream brigava com card-box simples).',
|
|
79
79
|
},
|
|
80
|
-
|
|
81
|
-
name:
|
|
82
|
-
ancestry:
|
|
80
|
+
"metric-card": {
|
|
81
|
+
name: "metric-card",
|
|
82
|
+
ancestry: "opus",
|
|
83
83
|
whenToUse:
|
|
84
|
-
|
|
84
|
+
"Medida resumida com rótulo, valor em destaque e descrição opcional. `context` realça semanticamente somente o ícone; aceita ação relacionada e estado de carregamento. O consumidor calcula e formata o valor; para conteúdo geral ou estrutura livre, use Card.",
|
|
85
85
|
},
|
|
86
|
-
|
|
87
|
-
name:
|
|
88
|
-
ancestry:
|
|
86
|
+
chat: {
|
|
87
|
+
name: "chat",
|
|
88
|
+
ancestry: "opus",
|
|
89
89
|
whenToUse:
|
|
90
|
-
|
|
90
|
+
"Chat da casa (lista de mensagens + composer) que gerencia a conversa por dentro (estado/loading/auto-scroll; Enter envia, Shift+Enter quebra linha). A inteligência vem da prop `send` — resposta inteira (Promise<string>) OU streaming (AsyncIterable<ChatEvent>: texto incremental, indicador vivo do tool, artefato via renderArtifact). No Opus, o backend liga em `runtime.aiFor(base).run(...)` ou `.runStream(...)`. Estado vazio por `greeting` (frase) ou `empty` (nó composto com os slots de Empty). Dê altura ao container (ex.: `h-full`).",
|
|
91
91
|
},
|
|
92
|
-
|
|
93
|
-
name:
|
|
94
|
-
ancestry:
|
|
92
|
+
checkbox: {
|
|
93
|
+
name: "checkbox",
|
|
94
|
+
ancestry: "shadcn",
|
|
95
95
|
whenToUse:
|
|
96
|
-
|
|
96
|
+
"Caixa de marcação booleana (Radix). Controlado por `checked`/`onCheckedChange`. Parear com Label. Pra escolha única de várias opções, use Select/RadioGroup.",
|
|
97
97
|
},
|
|
98
|
-
|
|
99
|
-
name:
|
|
100
|
-
ancestry:
|
|
98
|
+
"icon-picker": {
|
|
99
|
+
name: "icon-picker",
|
|
100
|
+
ancestry: "opus",
|
|
101
101
|
whenToUse:
|
|
102
|
-
|
|
102
|
+
"Seletor de ícone: gatilho com o ícone corrente + lista buscável (mesma receita Popover+Command do Select buscável). O value é o NOME do ícone (kebab-case) — renderize com a mesma paleta (iconPickerIcons[name] ?? fallback). Paleta default curada (~40, lucide); vocabulário próprio via prop icons. Pra personalização de item criado pelo usuário (relatório, projeto, pasta).",
|
|
103
103
|
},
|
|
104
|
-
|
|
105
|
-
name:
|
|
106
|
-
ancestry:
|
|
104
|
+
command: {
|
|
105
|
+
name: "command",
|
|
106
|
+
ancestry: "shadcn",
|
|
107
107
|
whenToUse:
|
|
108
|
-
|
|
108
|
+
"Lista filtrável com teclado (cmdk) — base de command-palettes. Use CommandDialog pra palette modal (⌘K). Pra escolha simples, use o Select direto.",
|
|
109
109
|
},
|
|
110
|
-
|
|
111
|
-
name:
|
|
112
|
-
ancestry:
|
|
110
|
+
composer: {
|
|
111
|
+
name: "composer",
|
|
112
|
+
ancestry: "opus",
|
|
113
113
|
whenToUse:
|
|
114
|
-
|
|
114
|
+
"A caixa de escrever da casa (o composer do Chat, extraído): textarea numa pílula elevada, Enter envia / Shift+Enter quebra linha, enviar dentro. Use SOZINHO quando há entrada de texto mas não um chat — ex.: o composer de criação de sessão do Maestro (sem histórico). Com `actions`, ganha uma barra embaixo pra seletores discretos à esquerda (app, agente, contexto…) — o mesmo lugar onde o Maestro põe app/task e a GB poria o agente. Sem `actions`, é a linha única de sempre. Controlado (`value`/`onChange`/`onSubmit`); `submitDisabled` gateia além de vazio/busy. Pra um chat completo (mensagens + este composer), use Chat.",
|
|
115
115
|
},
|
|
116
|
-
|
|
117
|
-
name:
|
|
118
|
-
ancestry:
|
|
116
|
+
"content-header": {
|
|
117
|
+
name: "content-header",
|
|
118
|
+
ancestry: "opus",
|
|
119
|
+
whenToUse:
|
|
120
|
+
"Header estrutural de Content: agrupa ContentTitle, ContentDescription, ContentMeta e ContentActions. Não use solto. Para o caso comum, declare title, description, meta e actions diretamente em Content; o level controla a hierarquia semântica do heading.",
|
|
121
|
+
},
|
|
122
|
+
copyable: {
|
|
123
|
+
name: "copyable",
|
|
124
|
+
ancestry: "opus",
|
|
125
|
+
whenToUse:
|
|
126
|
+
"Clicar-pra-copiar com feedback: copia `value` pro clipboard e o ícone vira check por ~1.5s. Sem filhos é um botão-ícone (toolbar/célula); com filhos, o rótulo visível + o ícone. Pra IDs, tokens, slugs, URLs. No-op silencioso se o clipboard não existir (contexto inseguro/SSR).",
|
|
127
|
+
},
|
|
128
|
+
dialog: {
|
|
129
|
+
name: "dialog",
|
|
130
|
+
ancestry: "shadcn",
|
|
119
131
|
whenToUse:
|
|
120
132
|
'Janela modal com overlay e trap de foco (Radix). O DialogContent é a superfície PURA (sem padding); o espaço mora nos slots: DialogHeader (fixo) > DialogTitle/Description, DialogBody (rola; opcional) e DialogFooter (faixa de ação; opcional). `showCloseButton={false}` no DialogContent esconde o "X" (modal que exige ação). Pra menu de ações, use Menu; pra ancorado sem modal, Popover.',
|
|
121
133
|
},
|
|
122
|
-
|
|
123
|
-
name:
|
|
124
|
-
ancestry:
|
|
134
|
+
input: {
|
|
135
|
+
name: "input",
|
|
136
|
+
ancestry: "shadcn",
|
|
125
137
|
whenToUse:
|
|
126
|
-
|
|
138
|
+
"Campo de texto de uma linha. Aceita todos os atributos nativos de <input> (type, placeholder, disabled). `icon` (ícone leading, identidade) e `trailing` (ação no fim — limpar, mostrar senha) são adornos por PROP, as mesmas do Select (adorno de campo é prop, não composição). Pra rótulo, parear com Label; pra addon rico (botão no fim, prefixo de texto, múltiplos), InputGroup.",
|
|
127
139
|
},
|
|
128
|
-
|
|
129
|
-
name:
|
|
130
|
-
ancestry:
|
|
131
|
-
whenToUse:
|
|
140
|
+
label: {
|
|
141
|
+
name: "label",
|
|
142
|
+
ancestry: "shadcn",
|
|
143
|
+
whenToUse:
|
|
144
|
+
"Rótulo acessível de um campo. `htmlFor` aponta pro id do controle. Parear com Input/Textarea/Select.",
|
|
132
145
|
},
|
|
133
|
-
|
|
134
|
-
name:
|
|
135
|
-
ancestry:
|
|
146
|
+
markdown: {
|
|
147
|
+
name: "markdown",
|
|
148
|
+
ancestry: "opus",
|
|
136
149
|
whenToUse:
|
|
137
|
-
|
|
150
|
+
"Renderiza markdown como HTML semântico (motor markdown-it — o MESMO da doc; o parser de regex saiu em 7.1.0). `html: false`: tag no fonte é escapada, então serve pra texto de gente e de modelo. A tipografia vem do `prose` mapeado nos tokens da casa (theme.css) — não passe classe de tipografia por fora; o 1º/último bloco já não empurram a caixa em volta. Pra código com destaque e cópia, CodeBlock.",
|
|
138
151
|
},
|
|
139
|
-
|
|
140
|
-
name:
|
|
141
|
-
ancestry:
|
|
152
|
+
menu: {
|
|
153
|
+
name: "menu",
|
|
154
|
+
ancestry: "opus",
|
|
142
155
|
whenToUse:
|
|
143
|
-
'O menu de
|
|
156
|
+
'O menu de ações da casa: lista flutuante ancorada num gatilho (Radix DropdownMenu). Compõe Menu > MenuTrigger + MenuContent e seus itens. `context="danger"` sinaliza item com consequência perigosa; `destructive` permanece alias de migração. Para escolher um valor, use Select; para busca por teclado, Command; para conteúdo livre ancorado, Popover.',
|
|
144
157
|
},
|
|
145
|
-
|
|
146
|
-
name:
|
|
147
|
-
ancestry:
|
|
158
|
+
popover: {
|
|
159
|
+
name: "popover",
|
|
160
|
+
ancestry: "shadcn",
|
|
148
161
|
whenToUse:
|
|
149
|
-
|
|
162
|
+
"Painel flutuante ancorado num gatilho, sem modal (Radix). Pra conteúdo livre (form curto, detalhes). Use PopoverHeader/PopoverTitle/PopoverDescription pra estruturar. Pra lista de ações, use Menu; pra modal, Dialog.",
|
|
150
163
|
},
|
|
151
|
-
|
|
152
|
-
name:
|
|
153
|
-
ancestry:
|
|
164
|
+
select: {
|
|
165
|
+
name: "select",
|
|
166
|
+
ancestry: "opus",
|
|
154
167
|
whenToUse:
|
|
155
168
|
'Seletor para escolhas em lista. Recebe `options` no formato { value, label, hint?, content?, group? }, sem JSX por item. Os modos são definidos por `searchable`, `multiple`, `onSearch` e `native`. `variant="default"` funciona como campo de formulário; `outline` envolve o conteúdo com borda; `ghost` o envolve sem borda. `size` segue a régua inline (default 2.25rem/sm 2rem), e `shape="pill"` altera somente a geometria. Também aceita `icon`, `trailing`, `triggerLabel` e `clearable`.',
|
|
156
169
|
},
|
|
157
|
-
|
|
158
|
-
name:
|
|
159
|
-
ancestry:
|
|
160
|
-
whenToUse:
|
|
170
|
+
separator: {
|
|
171
|
+
name: "separator",
|
|
172
|
+
ancestry: "shadcn",
|
|
173
|
+
whenToUse:
|
|
174
|
+
"Linha divisória entre seções/itens (Radix). `orientation` horizontal|vertical. Decorativa por padrão (a11y).",
|
|
161
175
|
},
|
|
162
|
-
|
|
163
|
-
name:
|
|
164
|
-
ancestry:
|
|
165
|
-
whenToUse:
|
|
176
|
+
skeleton: {
|
|
177
|
+
name: "skeleton",
|
|
178
|
+
ancestry: "shadcn",
|
|
179
|
+
whenToUse:
|
|
180
|
+
"Placeholder pulsante de carregamento. Dê o tamanho via className (h-4 w-32). Pra estado de loading antes do conteúdo chegar.",
|
|
166
181
|
},
|
|
167
|
-
|
|
168
|
-
name:
|
|
169
|
-
ancestry:
|
|
170
|
-
whenToUse:
|
|
182
|
+
spinner: {
|
|
183
|
+
name: "spinner",
|
|
184
|
+
ancestry: "shadcn",
|
|
185
|
+
whenToUse:
|
|
186
|
+
"Loading girando (ação em andamento: botão, fetch). Pra placeholder com forma de conteúdo, use Skeleton.",
|
|
171
187
|
},
|
|
172
|
-
|
|
173
|
-
name:
|
|
174
|
-
ancestry:
|
|
188
|
+
table: {
|
|
189
|
+
name: "table",
|
|
190
|
+
ancestry: "shadcn",
|
|
175
191
|
whenToUse:
|
|
176
192
|
'Tabela de dados. Compõe Table > (TableHeader > TableRow > TableHead, TableBody > TableRow > TableCell). `variant="plain"` vem sem borda externa; `variant="framed"` aplica a moldura canônica, recorta o scroll e destaca o cabeçalho. Pra listagem tabular — pro pattern de search use ActionList.',
|
|
177
193
|
},
|
|
178
|
-
|
|
179
|
-
name:
|
|
180
|
-
ancestry:
|
|
194
|
+
tabs: {
|
|
195
|
+
name: "tabs",
|
|
196
|
+
ancestry: "shadcn",
|
|
181
197
|
whenToUse:
|
|
182
|
-
|
|
198
|
+
"Abas pra alternar entre painéis de conteúdo (Radix). Compõe Tabs > (TabsList > TabsTrigger + TabsContent), pareando `value` do trigger com o do content. `variant` na TabsList: `default` (pill) ou `line` (barra sublinhada, ancorada na borda da lista). `size` no Tabs (default h-9 / sm h-8 — o par do sm de Button/Select, pra fileira densa); a altura pode ser substituída em `TabsList`. `orientation` (horizontal/vertical).",
|
|
183
199
|
},
|
|
184
|
-
|
|
185
|
-
name:
|
|
186
|
-
ancestry:
|
|
200
|
+
textarea: {
|
|
201
|
+
name: "textarea",
|
|
202
|
+
ancestry: "shadcn",
|
|
187
203
|
whenToUse:
|
|
188
|
-
|
|
204
|
+
"Campo de texto multilinha. Aceita os atributos nativos de <textarea> (rows, placeholder, disabled). Cresce com o conteúdo via `field-sizing-content`.",
|
|
189
205
|
},
|
|
190
|
-
|
|
191
|
-
name:
|
|
192
|
-
ancestry:
|
|
206
|
+
toast: {
|
|
207
|
+
name: "toast",
|
|
208
|
+
ancestry: "shadcn",
|
|
193
209
|
whenToUse:
|
|
194
|
-
|
|
210
|
+
"Notificação efêmera (sonner). Monte `<Toaster />` 1x no root e dispare com `toast.success/error/message(...)`. Pra mensagem persistente inline, use Alert.",
|
|
195
211
|
},
|
|
196
|
-
|
|
197
|
-
name:
|
|
198
|
-
ancestry:
|
|
212
|
+
tooltip: {
|
|
213
|
+
name: "tooltip",
|
|
214
|
+
ancestry: "shadcn",
|
|
199
215
|
whenToUse:
|
|
200
|
-
|
|
216
|
+
"Dica curta no hover/foco de um elemento (Radix). Envolver a árvore num TooltipProvider. Só texto auxiliar — nunca pôr ação ou conteúdo essencial aqui.",
|
|
201
217
|
},
|
|
202
|
-
|
|
203
|
-
name:
|
|
204
|
-
ancestry:
|
|
218
|
+
truncate: {
|
|
219
|
+
name: "truncate",
|
|
220
|
+
ancestry: "opus",
|
|
205
221
|
whenToUse:
|
|
206
|
-
|
|
222
|
+
"Texto truncado com tooltip SÓ quando transborda (medição do overflow, re-medida em resize) — substitui a composição `block truncate` + `title` sempre presente, que mostra dica até em texto que não corta. `tooltip` sobrepõe o conteúdo da dica (default: os children); `fade` troca as reticências por um esmaecimento até a borda, ligado pela mesma medição. Requer TooltipProvider na raiz. Pra célula de tabela, nome de arquivo, URL — qualquer linha única que pode estourar.",
|
|
207
223
|
},
|
|
208
|
-
|
|
209
|
-
name:
|
|
210
|
-
ancestry:
|
|
224
|
+
accordion: {
|
|
225
|
+
name: "accordion",
|
|
226
|
+
ancestry: "shadcn",
|
|
211
227
|
whenToUse:
|
|
212
|
-
|
|
228
|
+
"Lista de seções empilhadas que abrem/fecham (Radix). `type` single (um painel por vez — combine com `collapsible` pra permitir fechar todos) ou multiple (vários abertos). Cada AccordionItem precisa de `value`; o chevron já vem no AccordionTrigger. Pra alternar conteúdo lado a lado, use Tabs; pra um único bloco recolhível solto, use Collapsible.",
|
|
213
229
|
},
|
|
214
|
-
|
|
215
|
-
name:
|
|
216
|
-
ancestry:
|
|
230
|
+
"alert-dialog": {
|
|
231
|
+
name: "alert-dialog",
|
|
232
|
+
ancestry: "opus",
|
|
217
233
|
whenToUse:
|
|
218
234
|
'Diálogo modal que INTERROMPE pra cobrar decisão e NÃO fecha clicando fora (`role="alertdialog"`) — a confirmação destrutiva. Desenho ÚNICO e compacto (6.0.0: a prop `size` saiu, o largo não existe mais). Compõe AlertDialog > AlertDialogTrigger (asChild) + AlertDialogContent > AlertDialogHeader(AlertDialogMedia? + AlertDialogTitle/Description) + AlertDialogFooter(Cancel/Action). ATENÇÃO: Action e Cancel do Radix FECHAM ao clicar — pra ação async que só some no sucesso, use Button no footer. Na prática você quase nunca monta isto à mão: `confirm()` já faz, e o DeleteButton/ActionTrigger vêm prontos.',
|
|
219
235
|
},
|
|
220
|
-
|
|
221
|
-
name:
|
|
222
|
-
ancestry:
|
|
236
|
+
"aspect-ratio": {
|
|
237
|
+
name: "aspect-ratio",
|
|
238
|
+
ancestry: "shadcn",
|
|
223
239
|
whenToUse:
|
|
224
|
-
|
|
240
|
+
"Trava a proporção de um bloco (Radix) — a largura vem do pai e a altura é derivada de `ratio` (16/9 pra vídeo/preview, 1 pra quadrado, 4/3 clássico). Use pra mídia, thumbnails e previews de worktree não pularem o layout enquanto carregam. Borda/rounded/overflow-hidden moram no AspectRatio; o filho preenche com h-full w-full object-cover. Pra largura fixa em si, é o contêiner que decide, não este componente.",
|
|
225
241
|
},
|
|
226
|
-
|
|
227
|
-
name:
|
|
228
|
-
ancestry:
|
|
242
|
+
avatar: {
|
|
243
|
+
name: "avatar",
|
|
244
|
+
ancestry: "shadcn",
|
|
229
245
|
whenToUse:
|
|
230
246
|
'Retrato de uma pessoa ou agente (Radix). AvatarImage (src/alt) + AvatarFallback (iniciais ou ícone) — o fallback cobre o carregamento e a falha da imagem. `size` sm/default/lg. AvatarBadge é o selo de status no canto (tinja o fundo). Pra a pilha de membros, envolva os Avatar num AvatarGroup e feche o excedente com AvatarGroupCount ("+N").',
|
|
231
247
|
},
|
|
232
|
-
|
|
233
|
-
name:
|
|
234
|
-
ancestry:
|
|
248
|
+
breadcrumb: {
|
|
249
|
+
name: "breadcrumb",
|
|
250
|
+
ancestry: "shadcn",
|
|
235
251
|
whenToUse:
|
|
236
|
-
|
|
252
|
+
"Trilha de navegação hierárquica (workspace → repositório → sessão): mostra onde o usuário está e o caminho de volta. `BreadcrumbLink` pros níveis navegáveis, `BreadcrumbPage` pro atual (não clicável), `BreadcrumbSeparator` entre eles e `BreadcrumbEllipsis` pra colapsar trilhas longas. Pra alternar painéis no mesmo nível, use Tabs.",
|
|
237
253
|
},
|
|
238
|
-
|
|
239
|
-
name:
|
|
240
|
-
ancestry:
|
|
254
|
+
"button-group": {
|
|
255
|
+
name: "button-group",
|
|
256
|
+
ancestry: "shadcn",
|
|
241
257
|
whenToUse:
|
|
242
258
|
'Junta botões (e Select) num bloco coeso — bordas internas colapsadas e cantos arredondados só nas pontas. `orientation` define o eixo e `shape="pill"` arredonda as extremidades externas sem reabrir a junção interna. ButtonGroupText adiciona rótulo/prefixo; ButtonGroupSeparator corta visualmente entre ações.',
|
|
243
259
|
},
|
|
244
|
-
|
|
245
|
-
name:
|
|
246
|
-
ancestry:
|
|
260
|
+
calendar: {
|
|
261
|
+
name: "calendar",
|
|
262
|
+
ancestry: "shadcn",
|
|
247
263
|
whenToUse:
|
|
248
264
|
'Grade de datas (react-day-picker) pra escolher um dia ou um intervalo. `mode` define a seleção (single/multiple/range) e o formato de `selected`/`onSelect` (Date, Date[] ou { from, to }). `captionLayout="dropdown"` troca o título do mês por seletores de mês/ano (pular pra um período distante); `numberOfMonths` mostra meses lado a lado; `disabled` (Matcher) corta datas. Pra exibir num popover de campo, ancore no Popover.',
|
|
249
265
|
},
|
|
250
|
-
|
|
251
|
-
name:
|
|
252
|
-
ancestry:
|
|
266
|
+
carousel: {
|
|
267
|
+
name: "carousel",
|
|
268
|
+
ancestry: "shadcn",
|
|
253
269
|
whenToUse:
|
|
254
|
-
|
|
270
|
+
"Trilho de slides deslizáveis (embla). Compõe Carousel > CarouselContent > CarouselItem + CarouselPrevious/CarouselNext; o `basis` do item controla quantos cabem na vista. `orientation` (horizontal/vertical), `opts` repassa o embla (loop, align), `setApi` expõe a instância. Pra lista paginada de dados, use Table; pra navegação entre painéis, Tabs.",
|
|
255
271
|
},
|
|
256
|
-
|
|
257
|
-
name:
|
|
258
|
-
ancestry:
|
|
272
|
+
collapsible: {
|
|
273
|
+
name: "collapsible",
|
|
274
|
+
ancestry: "shadcn",
|
|
259
275
|
whenToUse:
|
|
260
|
-
|
|
276
|
+
"Seção que abre e fecha (Radix): um CollapsibleTrigger revela ou esconde o CollapsibleContent. Compõe Collapsible > (CollapsibleTrigger + CollapsibleContent) — o Trigger já é o `<button>`. `defaultOpen` pro modo não controlado; `open`/`onOpenChange` pro controlado (ex.: girar o chevron); `disabled` trava o gatilho. Pra alternar entre vários painéis, use Tabs; pra menu de ações ancorado, Menu.",
|
|
261
277
|
},
|
|
262
|
-
|
|
263
|
-
name:
|
|
264
|
-
ancestry:
|
|
278
|
+
drawer: {
|
|
279
|
+
name: "drawer",
|
|
280
|
+
ancestry: "opus",
|
|
265
281
|
whenToUse:
|
|
266
|
-
'O painel que desliza de uma borda da tela (Radix Dialog: overlay + trap de foco + ESC), pra detalhe/edição lateral sem trocar de tela. Compõe Drawer > DrawerTrigger + DrawerContent (side="right|left|top|bottom") > (
|
|
282
|
+
'O painel que desliza de uma borda da tela (Radix Dialog: overlay + trap de foco + ESC), pra detalhe/edição lateral sem trocar de tela. Compõe Drawer > DrawerTrigger + DrawerContent (side="right|left|top|bottom") > DrawerHeader(DrawerTitle/DrawerDescription) + DrawerBody + DrawerFooter; DrawerClose fecha, `asChild` funde no Button. É o port do `sheet` do shadcn com o nome que o ecossistema React usa — o `drawer` do registry (vaul, com gesto de arrastar) foi removido em 4.0.0: mesmo papel, zero uso. Pra modal centrado, Dialog; pra menu de ações, Menu.',
|
|
267
283
|
},
|
|
268
|
-
|
|
269
|
-
name:
|
|
270
|
-
ancestry:
|
|
284
|
+
empty: {
|
|
285
|
+
name: "empty",
|
|
286
|
+
ancestry: "shadcn",
|
|
271
287
|
whenToUse:
|
|
272
|
-
|
|
288
|
+
"Região disponível para receber ou criar conteúdo: moldura tracejada centrada com `EmptyHeader` (mídia + `EmptyTitle` + `EmptyDescription`) e `EmptyContent` pras ações. Para lista ou tabela carregada sem registros, use DataState ou ActionList, que preservam a moldura sólida da estrutura. `EmptyMedia variant` icon (quadrado muted) ou default (sem fundo). Pra erro inline use Alert; pra carregamento, Skeleton.",
|
|
273
289
|
},
|
|
274
|
-
|
|
275
|
-
name:
|
|
276
|
-
ancestry:
|
|
290
|
+
field: {
|
|
291
|
+
name: "field",
|
|
292
|
+
ancestry: "shadcn",
|
|
277
293
|
whenToUse:
|
|
278
|
-
|
|
294
|
+
"O esqueleto de um campo de formulário: rótulo, controle, descrição e erro compostos com espaçamento consistente. Field empilha (orientation vertical) ou põe o controle ao lado (horizontal/responsive, bom pra toggle); FieldLabel (htmlFor↔id), FieldDescription (ajuda) e FieldError (mensagem só quando há erro, ou uma lista de errors) preenchem. Agrupe campos relacionados num FieldSet > FieldLegend + FieldGroup, com FieldSeparator entre eles; FieldContent + FieldTitle dão o bloco texto quando o controle não é um <label>. É layout — o estado e a validação ficam no seu form (ou no ActionForm, que já monta tudo isto).",
|
|
279
295
|
},
|
|
280
|
-
|
|
281
|
-
name:
|
|
282
|
-
ancestry:
|
|
296
|
+
"input-group": {
|
|
297
|
+
name: "input-group",
|
|
298
|
+
ancestry: "shadcn",
|
|
283
299
|
whenToUse:
|
|
284
300
|
'Campo composto: cola ícones, texto e botões a um InputGroupInput/InputGroupTextarea numa única moldura (foco e erro propagam pro grupo todo). `shape="pill"` aplica a geometria arredondada à moldura. InputGroupAddon ancora adornos; InputGroupText é rótulo inerte; InputGroupButton é o botão embutido. Pra agrupar botões soltos, use ButtonGroup.',
|
|
285
301
|
},
|
|
286
|
-
|
|
287
|
-
name:
|
|
288
|
-
ancestry:
|
|
302
|
+
"input-otp": {
|
|
303
|
+
name: "input-otp",
|
|
304
|
+
ancestry: "shadcn",
|
|
289
305
|
whenToUse:
|
|
290
|
-
|
|
306
|
+
"Campo de código em casas (one-time password) montado sobre input-otp: InputOTP define `maxLength`, cada InputOTPSlot recebe seu `index`, InputOTPGroup agrupa as casas e InputOTPSeparator divide em blocos. Controle por `value`/`onChange`. Use pra confirmar acesso/2FA com código numérico; pra texto livre, use Input.",
|
|
291
307
|
},
|
|
292
|
-
|
|
293
|
-
name:
|
|
294
|
-
ancestry:
|
|
308
|
+
item: {
|
|
309
|
+
name: "item",
|
|
310
|
+
ancestry: "shadcn",
|
|
295
311
|
whenToUse:
|
|
296
|
-
'Linha de conteúdo composta —
|
|
312
|
+
'Linha de conteúdo composta — ItemMedia + ItemHeader (ItemTitle e ItemDescription) + ItemBody ou ItemActions, com ItemFooter opcional. A mídia acompanha a altura útil do header. Item é o container (`variant` default/outline/muted, `size` default/sm, `asChild` pra virar link/botão); `ItemContent` permanece só como alias legado. Empilhe vários num ItemGroup: `variant="framed"` aplica a moldura e a superfície; ItemSeparator declara os divisores internos. É o padrão pra listas de workspaces, agentes, repositórios e sessões.',
|
|
297
313
|
},
|
|
298
|
-
|
|
299
|
-
name:
|
|
300
|
-
ancestry:
|
|
314
|
+
kbd: {
|
|
315
|
+
name: "kbd",
|
|
316
|
+
ancestry: "shadcn",
|
|
301
317
|
whenToUse:
|
|
302
318
|
'Tecla ou combinação de teclas num atalho (renderiza `<kbd>`). `Kbd` é uma tecla; envolva várias num `KbdGroup` pra formar o combo (ex.: ⌘ + K), com o conector ("+") como texto entre elas. Estiliza, não captura — o handler do atalho é seu. Aceita ícone (lucide) como filho. Dentro de um TooltipContent ganha o tom invertido automaticamente.',
|
|
303
319
|
},
|
|
304
|
-
|
|
305
|
-
name:
|
|
306
|
-
ancestry:
|
|
320
|
+
pagination: {
|
|
321
|
+
name: "pagination",
|
|
322
|
+
ancestry: "shadcn",
|
|
307
323
|
whenToUse:
|
|
308
|
-
|
|
324
|
+
"Navegação entre páginas montada por composição: Pagination › PaginationContent › PaginationItem com PaginationLink, mais PaginationPrevious/PaginationNext e PaginationEllipsis. `page` dá o número e o nome acessível (“Página N”); `isActive` marca a atual. Com `href` o link é `<a>`; sem `href` vira `<button>` (modo controlado, com foco e `disabled`). Os números têm largura mínima quadrada e crescem com os dígitos; as setas seguem quadradas (`iconOnly`). `label` localiza as setas. É o único paginador: ActionList compõe esta primitiva na escala densa do rodapé. Pra rolagem infinita ou listas curtas, dispense a barra.",
|
|
309
325
|
},
|
|
310
|
-
|
|
311
|
-
name:
|
|
312
|
-
ancestry:
|
|
326
|
+
progress: {
|
|
327
|
+
name: "progress",
|
|
328
|
+
ancestry: "shadcn",
|
|
313
329
|
whenToUse:
|
|
314
|
-
|
|
330
|
+
"Barra de progresso determinada (Radix): mostra o quanto de uma tarefa já foi feito num valor de 0 a 100 em `value`. Pra etapas de um processo conhecido — opus check, sincronização, cobertura. O preenchimento anima a cada mudança de `value`; sem `value` (ou null) fica vazia. Pra carga sem percentual (girando até chegar), use Spinner; pra placeholder com forma de conteúdo, Skeleton.",
|
|
315
331
|
},
|
|
316
|
-
|
|
317
|
-
name:
|
|
318
|
-
ancestry:
|
|
332
|
+
"radio-group": {
|
|
333
|
+
name: "radio-group",
|
|
334
|
+
ancestry: "shadcn",
|
|
319
335
|
whenToUse:
|
|
320
|
-
|
|
336
|
+
"Escolha única entre opções mutuamente exclusivas, todas visíveis ao mesmo tempo (Radix). Cada RadioGroupItem tem um `value`; o item escolhido vira o `value` do RadioGroup, controlado por `value`/`onValueChange` (ou `defaultValue` no modo não controlado). Pareie cada item com um Label. Pra poucas opções que cabem na tela; com muitas, prefira Select; pra ligar/desligar um único item, Checkbox ou Switch.",
|
|
321
337
|
},
|
|
322
|
-
|
|
323
|
-
name:
|
|
324
|
-
ancestry:
|
|
338
|
+
split: {
|
|
339
|
+
name: "split",
|
|
340
|
+
ancestry: "opus",
|
|
325
341
|
whenToUse:
|
|
326
|
-
|
|
342
|
+
"Divide uma área em panes em sequência horizontal ou vertical. Use `resizable` quando a pessoa deve ajustar a fronteira; o mesmo `<Split>` vira flex simples sem ele. Cada `<Pane>` declara tamanho inicial/mínimo e inset. É o mecanismo espacial para sidebar, conteúdo e rail.",
|
|
327
343
|
},
|
|
328
|
-
|
|
329
|
-
name:
|
|
330
|
-
ancestry:
|
|
344
|
+
sidebar: {
|
|
345
|
+
name: "sidebar",
|
|
346
|
+
ancestry: "opus",
|
|
331
347
|
whenToUse:
|
|
332
|
-
|
|
348
|
+
"Chrome e navegação de uma coluna lateral, encaixada onde um Split decidir. `Sidebar` possui o colapso; `PaneHeader`, `PaneBody` e `PaneFooter` estruturam qualquer pane, e `SidebarNav`/`SidebarItem` apresentam navegação com grupos e subgrupos. `PaneContent` é um alias temporário de compatibilidade. Serve tanto a barra global quanto uma nav contextual; em Split redimensionável passe `divider={false}` para não duplicar a divisória.",
|
|
333
349
|
},
|
|
334
|
-
|
|
335
|
-
name:
|
|
336
|
-
ancestry:
|
|
350
|
+
"scroll-area": {
|
|
351
|
+
name: "scroll-area",
|
|
352
|
+
ancestry: "shadcn",
|
|
337
353
|
whenToUse:
|
|
338
354
|
'Região rolável com barra estilizada da casa (Radix), no lugar da scrollbar do sistema. Dê altura (ou largura) ao ScrollArea via className e ponha o conteúdo dentro; a barra vertical já vem por padrão. Pra rolagem horizontal, acrescente `<ScrollBar orientation="horizontal" />` como filho. Pra a página inteira rolar, deixe o navegador cuidar — isto é pra um painel com altura fixa (lista de sessões, log, trilho de skills).',
|
|
339
355
|
},
|
|
340
|
-
|
|
341
|
-
name:
|
|
342
|
-
ancestry:
|
|
356
|
+
slider: {
|
|
357
|
+
name: "slider",
|
|
358
|
+
ancestry: "shadcn",
|
|
343
359
|
whenToUse:
|
|
344
|
-
|
|
360
|
+
"Controle de valor numa faixa contínua, arrastado pelo thumb (Radix). `min`/`max`/`step` delimitam a faixa; `value`/`onValueChange` controlam (array de números — `[n]` pra um thumb, `[a, b]` pra um intervalo) ou `defaultValue` no modo não controlado. `orientation` horizontal/vertical, `disabled` esmaece. Pra um número exato digitado, use Input type=number; pra ligar/desligar, Switch.",
|
|
345
361
|
},
|
|
346
|
-
|
|
347
|
-
name:
|
|
348
|
-
ancestry:
|
|
362
|
+
switch: {
|
|
363
|
+
name: "switch",
|
|
364
|
+
ancestry: "shadcn",
|
|
349
365
|
whenToUse:
|
|
350
|
-
|
|
366
|
+
"Liga/desliga imediato de uma preferência booleana (Radix). Controlado por `checked`/`onCheckedChange` (boolean) e em par com Label. Use pra estado que vale na hora (ativar agente, sincronizar); pra confirmar dentro de um formulário, prefira Checkbox.",
|
|
351
367
|
},
|
|
352
|
-
|
|
353
|
-
name:
|
|
354
|
-
ancestry:
|
|
368
|
+
toggle: {
|
|
369
|
+
name: "toggle",
|
|
370
|
+
ancestry: "shadcn",
|
|
355
371
|
whenToUse:
|
|
356
|
-
|
|
372
|
+
"Botão de duas posições — liga/desliga um estado in-loco, sem sair da tela (Radix). `variant` default (fundo só quando ativo) ou outline (com borda); `size` sm/default/lg. Controlado por `pressed`/`onPressedChange` (ou `defaultPressed` no modo não controlado); ótimo pra alternar uma opção numa toolbar (negrito, quebra de linha, modo somente-leitura). Pra um conjunto de toggles mutuamente exclusivos ou um grupo de formatação, use ToggleGroup; pra um booleano com rótulo num formulário, prefira Switch ou Checkbox.",
|
|
357
373
|
},
|
|
358
|
-
|
|
359
|
-
name:
|
|
360
|
-
ancestry:
|
|
374
|
+
"toggle-group": {
|
|
375
|
+
name: "toggle-group",
|
|
376
|
+
ancestry: "shadcn",
|
|
361
377
|
whenToUse:
|
|
362
|
-
|
|
378
|
+
"Grupo de botões de alternância (Radix). `type` single (um ativo, value: string) ou multiple (vários, value: string[]). Controlado por `value`/`onValueChange`. `variant` default|outline, `size` default|sm|lg e `spacing` descem pros itens via contexto. Serve para alternar a visão de uma seção, montar uma barra de formatação ou apresentar escolhas ricas em cards pelo `ActionForm` com `widget: toggle-group`. Para uma escolha textual comum em formulário, especialmente com rótulos longos sem conteúdo de apoio, prefira RadioGroup.",
|
|
363
379
|
},
|
|
364
380
|
|
|
365
|
-
|
|
366
|
-
name:
|
|
367
|
-
ancestry:
|
|
381
|
+
confirm: {
|
|
382
|
+
name: "dialog",
|
|
383
|
+
ancestry: "opus",
|
|
384
|
+
whenToUse:
|
|
385
|
+
"O trio imperativo `dialog.alert` (Promise<void>, reconhecimento obrigatório) · `dialog.confirm` (Promise<boolean>, com slot `body` pra corpo próprio) · `dialog.prompt` (Promise<string|null>, um input). Superfície imperativa como o `toast`, mas que RESPONDE — exige `<DialogHost />` no shell (sem ele LANÇA, em vez de pendurar a promise). Namespace de propósito: `window.alert/confirm/prompt` são globais do browser e um import esquecido cai no nativo; `window.dialog` não existe. Por baixo é o AlertDialog (role=alertdialog, não fecha fora); fila de uma por vez. `confirm()`/`<ConfirmHost/>` seguem como aliases. Pra excluir por contrato, ActionTrigger; pra form de verdade, ActionFormDialog; mais de duas ações, componha o AlertDialog.",
|
|
386
|
+
},
|
|
387
|
+
"action-form": {
|
|
388
|
+
name: "action-form",
|
|
389
|
+
ancestry: "opus",
|
|
368
390
|
whenToUse:
|
|
369
|
-
|
|
391
|
+
"Form de uma FormAction do Opus — submit + validação + toast encapsulados. AUTO (sem children): campos auto-detectados do Zod na ordem do contrato. COMPOSIÇÃO (children): diagrame com <ActionFormField name/> — label/widget/erro/asterisco vêm do contrato, o layout é seu. Pra ação sem form, ActionTrigger.",
|
|
370
392
|
},
|
|
371
|
-
|
|
372
|
-
name:
|
|
373
|
-
ancestry:
|
|
393
|
+
"action-form-dialog": {
|
|
394
|
+
name: "action-form-dialog",
|
|
395
|
+
ancestry: "opus",
|
|
374
396
|
whenToUse:
|
|
375
|
-
|
|
397
|
+
"ActionForm dentro de um Dialog (form em modal) — controla open/onOpenChange + title; fecha no sucesso. Aceita children (modo composição) como o ActionForm. Pra form inline numa página, use ActionForm direto.",
|
|
376
398
|
},
|
|
377
|
-
|
|
378
|
-
name:
|
|
379
|
-
ancestry:
|
|
399
|
+
"action-form-card": {
|
|
400
|
+
name: "action-form-card",
|
|
401
|
+
ancestry: "opus",
|
|
380
402
|
whenToUse:
|
|
381
|
-
|
|
403
|
+
"O ActionForm dentro de um Card do Opus (header/conteúdo/rodapé) — pra estruturar uma seção da página como painel. Segue o padrão do Card (sem divisor nem faixa de modal, com o respiro do Card). Pra form em overlay, ActionFormDialog; pra form cru sem chrome, ActionForm direto.",
|
|
382
404
|
},
|
|
383
|
-
|
|
384
|
-
name:
|
|
385
|
-
ancestry:
|
|
405
|
+
"action-list": {
|
|
406
|
+
name: "action-list",
|
|
407
|
+
ancestry: "opus",
|
|
386
408
|
whenToUse:
|
|
387
|
-
|
|
409
|
+
"A listagem padronizada de uma ListAction — DECLARATIVA pelo contrato: `columns` (tipos, sortable, hidden) vira a tabela (com column picker); `filters` vira a toolbar (inline + `advanced` em modal + chips); `periods` vira o controle de período (presets + Personalizado com calendário → from/to); `text` liga a busca (q, à direita); sort escreve `sort: chave:dir`. `views` = renderers alternativos (board/galeria/lista) com segment — mesma fonte e filtros. Paginação server-driven (limit/page → total no rodapé + pager) e `batch` = multi-seleção com `can` (elegibilidade por item governa checkbox, selecionar-todos e o run). Células via `cells`; URL sync com listParamsToState/listStateToParams. Pra detalhe de 1 recurso, ActionView.",
|
|
388
410
|
},
|
|
389
|
-
|
|
390
|
-
name:
|
|
391
|
-
ancestry:
|
|
411
|
+
"action-trigger": {
|
|
412
|
+
name: "action-trigger",
|
|
413
|
+
ancestry: "opus",
|
|
392
414
|
whenToUse:
|
|
393
|
-
|
|
415
|
+
"Botão que dispara uma SimpleAction do Opus (sem form): assign, close, archive, excluir. Loading + toast + confirmação (do `action.confirm` do contrato, ou pela prop). `icon` faz o botão virar icon-only com tooltip — a ação que mora NO item (linha, card), sem vazar o clique pro item; `itemLabel` nomeia o alvo na pergunta. Erro de NEGÓCIO (conflict/validation/not_found) mostra a frase do servidor; o resto cai no rótulo do contrato, pra não vazar texto técnico. ATENÇÃO: contrato sem `confirm` dispara DIRETO — a confirmação de ação destrutiva se declara no contrato. Absorveu o DeleteButton (7.0.0). Pra mutação com campos, ActionForm.",
|
|
394
416
|
},
|
|
395
|
-
|
|
396
|
-
name:
|
|
397
|
-
ancestry:
|
|
417
|
+
"action-view": {
|
|
418
|
+
name: "action-view",
|
|
419
|
+
ancestry: "opus",
|
|
398
420
|
whenToUse:
|
|
399
|
-
|
|
421
|
+
"Carrega e exibe 1 recurso de uma ViewAction do Opus — loading/error/empty encapsulados; o layout vem por children `(data, refetch) => nó` (render segue como alias). Pra listagem, ActionList.",
|
|
400
422
|
},
|
|
401
|
-
|
|
402
|
-
name:
|
|
403
|
-
ancestry:
|
|
423
|
+
page: {
|
|
424
|
+
name: "page",
|
|
425
|
+
ancestry: "opus",
|
|
404
426
|
whenToUse:
|
|
405
|
-
|
|
427
|
+
"O esqueleto de página do back-office: <main> + container centralizado com teto padrão de 80rem (`max-w-7xl`). O shorthand com title, description, count e actions cria a mesma anatomia de PageHeader(PageTitle/PageDescription/PageMeta/PageActions) + PageBody disponível na forma explícita. `className` substitui o teto quando a composição pede outra largura. Quando todo o body estiver carregando, falhar ou estiver vazio, use PageState. Pra listagem em modal, ActionListDialog.",
|
|
406
428
|
},
|
|
407
|
-
|
|
408
|
-
name:
|
|
409
|
-
ancestry:
|
|
429
|
+
"page-state": {
|
|
430
|
+
name: "page-state",
|
|
431
|
+
ancestry: "opus",
|
|
410
432
|
whenToUse:
|
|
411
|
-
|
|
433
|
+
"Estado integral da área de conteúdo de Page: loading centralizado, error em Alert com recuperação aplicável, empty em Empty com contexto/ação e ready sem moldura adicional. Use como filho direto de Page somente quando o estado substitui TODO o conteúdo principal; pra seção ou coleção parcial, use DataState, ActionView ou ActionList.",
|
|
412
434
|
},
|
|
413
|
-
|
|
414
|
-
name:
|
|
415
|
-
ancestry:
|
|
435
|
+
router: {
|
|
436
|
+
name: "router",
|
|
437
|
+
ancestry: "opus",
|
|
416
438
|
whenToUse:
|
|
417
439
|
'Roteamento history-based sem dependência: `usePathname`/`useSegments`/`useSearchParams` (leitura reativa da URL) + `navigate(path, { replace? })`. O pathname É o estado, então deep-link, reload e o botão voltar funcionam sem um segundo lugar guardando "onde estou". Escopo PEQUENO de propósito: não há tabela de rotas, params tipados nem data loader — quem decide o que renderizar é o app, com if/switch sobre os segmentos. Precisa casar padrão (`/users/:id/posts/:postId`) ou carregar dado por rota? O caso pede uma biblioteca de rotas, não isto. `navigate` é no-op em destino igual (senão o "voltar" não sai do lugar) e usa useSyncExternalStore (useState sofre tearing em concurrent).',
|
|
418
440
|
},
|
|
419
|
-
|
|
420
|
-
name:
|
|
421
|
-
ancestry:
|
|
441
|
+
"data-state": {
|
|
442
|
+
name: "data-state",
|
|
443
|
+
ancestry: "opus",
|
|
422
444
|
whenToUse:
|
|
423
445
|
'O estado "carregando" (ANTES do conteúdo): orquestra erro/carregando/vazio/conteúdo de uma carga assíncrona num só lugar — Spinner centralizado no loading, texto em moldura sólida no vazio em bloco e aviso calmo no erro. Em tabela emoldurada, `colSpan` mantém a borda somente no pai. Pra uma região disponível para criação ou vínculo, use Empty, cuja moldura é tracejada. Pra "processando" (ação em andamento DEPOIS do clique), use o `busy` do Button. Pra placeholder com forma, Skeleton.',
|
|
424
446
|
},
|
|
425
|
-
|
|
426
|
-
name:
|
|
427
|
-
ancestry:
|
|
447
|
+
"action-list-dialog": {
|
|
448
|
+
name: "action-list-dialog",
|
|
449
|
+
ancestry: "opus",
|
|
428
450
|
whenToUse:
|
|
429
451
|
'Uma ListAction em modal: lista query-backed (busca no mount, refaz via invalidates) + chrome padronizado (título/descrição, toolbar com nota "N no total" derivada + ação de criar). Children (items, refetch) diagrama os itens. `loading` agrega a query irmã; `empty` sobrepõe o vazio derivado (ex.: form inline aberto). Pra tabela numa página, ActionList; pra form em modal, ActionFormDialog.',
|
|
430
452
|
},
|
|
431
|
-
} as const satisfies Record<string, ComponentMeta
|
|
453
|
+
} as const satisfies Record<string, ComponentMeta>;
|
|
432
454
|
|
|
433
|
-
export type ComponentMetaKey = keyof typeof componentMeta
|
|
455
|
+
export type ComponentMetaKey = keyof typeof componentMeta;
|