@softize/opus 12.10.0 → 13.0.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.
Files changed (154) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/bin/lib/check.mjs +1098 -310
  3. package/bin/lib/copy.mjs +12 -5
  4. package/docs/adr/0003-dictionary-presentation-is-declared.md +3 -0
  5. package/docs/adr/0004-page-content-state-is-composed.md +65 -0
  6. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +180 -0
  7. package/docs/adr/0006-semantic-context-precedes-visual-variant.md +182 -0
  8. package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
  9. package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
  10. package/docs/radius-scale.md +1 -1
  11. package/package.json +1 -1
  12. package/registry/instructions/opus.md +5 -0
  13. package/registry/skills/build-opus-ui/SKILL.md +27 -16
  14. package/registry/skills/build-opus-ui/references/evaluations.md +16 -5
  15. package/registry/skills/build-opus-ui/references/ui-patterns.md +38 -15
  16. package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
  17. package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
  18. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
  19. package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
  20. package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
  21. package/registry/skills/model-opus-dictionary/SKILL.md +4 -2
  22. package/registry/skills/model-opus-dictionary/references/evaluations.md +4 -3
  23. package/registry/templates/app/src/App.tsx +1 -1
  24. package/src/core/dictionary.ts +52 -14
  25. package/src/core/index.ts +10 -0
  26. package/src/core/ui-context.ts +29 -0
  27. package/src/schema/drivers/zod.ts +17 -8
  28. package/src/ui/components/patterns/action-form-card.tsx +18 -12
  29. package/src/ui/components/patterns/confirm.tsx +163 -40
  30. package/src/ui/components/patterns/content-header.tsx +335 -61
  31. package/src/ui/components/patterns/data-state.tsx +23 -10
  32. package/src/ui/components/patterns/list.tsx +1097 -783
  33. package/src/ui/components/patterns/page-state.tsx +115 -0
  34. package/src/ui/components/patterns/page.tsx +231 -41
  35. package/src/ui/components/patterns/sidebar.tsx +357 -83
  36. package/src/ui/components/patterns/trigger.tsx +37 -30
  37. package/src/ui/components/patterns/view.tsx +7 -11
  38. package/src/ui/components/primitives/alert.tsx +298 -110
  39. package/src/ui/components/primitives/ask.tsx +2 -1
  40. package/src/ui/components/primitives/badge.tsx +91 -30
  41. package/src/ui/components/primitives/button.tsx +99 -60
  42. package/src/ui/components/primitives/calendar.tsx +39 -39
  43. package/src/ui/components/primitives/card.tsx +96 -23
  44. package/src/ui/components/primitives/detail.tsx +2 -2
  45. package/src/ui/components/primitives/dialog.tsx +196 -39
  46. package/src/ui/components/primitives/dictionary-value.tsx +9 -14
  47. package/src/ui/components/primitives/dot.tsx +74 -21
  48. package/src/ui/components/primitives/drawer.tsx +40 -24
  49. package/src/ui/components/primitives/empty.tsx +3 -3
  50. package/src/ui/components/primitives/item.tsx +135 -79
  51. package/src/ui/components/primitives/menu.tsx +11 -3
  52. package/src/ui/components/primitives/metric-card.tsx +133 -0
  53. package/src/ui/components/primitives/sonner.tsx +187 -8
  54. package/src/ui/components/primitives/table.tsx +2 -2
  55. package/src/ui/docs/DocBrowser.tsx +104 -25
  56. package/src/ui/docs/changelog.tsx +1 -1
  57. package/src/ui/docs/content/accordion.md +22 -16
  58. package/src/ui/docs/content/action-form-card.md +8 -8
  59. package/src/ui/docs/content/action-form-dialog.md +9 -9
  60. package/src/ui/docs/content/action-form.md +28 -34
  61. package/src/ui/docs/content/action-list-dialog.md +11 -6
  62. package/src/ui/docs/content/action-list.md +64 -39
  63. package/src/ui/docs/content/action-trigger.md +21 -14
  64. package/src/ui/docs/content/action-view.md +8 -8
  65. package/src/ui/docs/content/actions.md +9 -9
  66. package/src/ui/docs/content/ai.md +3 -3
  67. package/src/ui/docs/content/alert.md +54 -28
  68. package/src/ui/docs/content/aspect-ratio.md +4 -4
  69. package/src/ui/docs/content/audit.md +2 -2
  70. package/src/ui/docs/content/auth.md +3 -3
  71. package/src/ui/docs/content/avatar.md +34 -14
  72. package/src/ui/docs/content/badge.md +21 -22
  73. package/src/ui/docs/content/breadcrumb.md +13 -8
  74. package/src/ui/docs/content/button.md +93 -15
  75. package/src/ui/docs/content/calendar.md +5 -5
  76. package/src/ui/docs/content/card.md +6 -6
  77. package/src/ui/docs/content/carousel.md +16 -11
  78. package/src/ui/docs/content/chat.md +3 -3
  79. package/src/ui/docs/content/checkbox.md +7 -7
  80. package/src/ui/docs/content/cli.md +5 -5
  81. package/src/ui/docs/content/collapsible.md +8 -8
  82. package/src/ui/docs/content/command.md +16 -8
  83. package/src/ui/docs/content/composer.md +2 -2
  84. package/src/ui/docs/content/content.md +44 -0
  85. package/src/ui/docs/content/copyable.md +4 -3
  86. package/src/ui/docs/content/customization.md +7 -7
  87. package/src/ui/docs/content/cycle.md +3 -3
  88. package/src/ui/docs/content/data-state.md +11 -12
  89. package/src/ui/docs/content/data.md +26 -33
  90. package/src/ui/docs/content/detail.md +8 -5
  91. package/src/ui/docs/content/dialog.md +339 -31
  92. package/src/ui/docs/content/dictionary-value.md +19 -18
  93. package/src/ui/docs/content/dock.md +3 -3
  94. package/src/ui/docs/content/dot.md +7 -7
  95. package/src/ui/docs/content/drawer.md +32 -16
  96. package/src/ui/docs/content/empty-value.md +2 -2
  97. package/src/ui/docs/content/empty.md +19 -12
  98. package/src/ui/docs/content/events.md +4 -4
  99. package/src/ui/docs/content/field.md +34 -12
  100. package/src/ui/docs/content/getting-started.md +1 -1
  101. package/src/ui/docs/content/icon-picker.md +8 -4
  102. package/src/ui/docs/content/input-otp.md +20 -12
  103. package/src/ui/docs/content/input.md +121 -9
  104. package/src/ui/docs/content/item.md +64 -24
  105. package/src/ui/docs/content/kbd.md +19 -11
  106. package/src/ui/docs/content/label.md +5 -3
  107. package/src/ui/docs/content/log.md +4 -4
  108. package/src/ui/docs/content/markdown.md +7 -6
  109. package/src/ui/docs/content/mcp.md +13 -15
  110. package/src/ui/docs/content/menu.md +36 -17
  111. package/src/ui/docs/content/metric-card.md +41 -0
  112. package/src/ui/docs/content/observability.md +2 -2
  113. package/src/ui/docs/content/page.md +93 -10
  114. package/src/ui/docs/content/pagination.md +22 -17
  115. package/src/ui/docs/content/popover.md +16 -8
  116. package/src/ui/docs/content/progress.md +7 -5
  117. package/src/ui/docs/content/queue.md +5 -5
  118. package/src/ui/docs/content/radio-group.md +20 -12
  119. package/src/ui/docs/content/router.md +11 -6
  120. package/src/ui/docs/content/scheduler.md +4 -5
  121. package/src/ui/docs/content/scroll-area.md +12 -7
  122. package/src/ui/docs/content/select.md +42 -29
  123. package/src/ui/docs/content/semantic-context.md +63 -0
  124. package/src/ui/docs/content/separator.md +5 -5
  125. package/src/ui/docs/content/sidebar.md +325 -56
  126. package/src/ui/docs/content/skeleton.md +5 -4
  127. package/src/ui/docs/content/slider.md +8 -7
  128. package/src/ui/docs/content/spinner.md +8 -8
  129. package/src/ui/docs/content/split.md +8 -5
  130. package/src/ui/docs/content/storage.md +6 -8
  131. package/src/ui/docs/content/switch.md +8 -7
  132. package/src/ui/docs/content/table.md +16 -6
  133. package/src/ui/docs/content/tabs.md +28 -14
  134. package/src/ui/docs/content/testing.md +9 -11
  135. package/src/ui/docs/content/textarea.md +5 -4
  136. package/src/ui/docs/content/toast.md +47 -13
  137. package/src/ui/docs/content/toggle.md +75 -7
  138. package/src/ui/docs/content/tokens.md +31 -3
  139. package/src/ui/docs/content/tooltip.md +19 -11
  140. package/src/ui/docs/content/truncate.md +7 -8
  141. package/src/ui/docs/content/ui.md +10 -9
  142. package/src/ui/docs/content/upgrading.md +7 -8
  143. package/src/ui/docs/doc-client.tsx +2 -2
  144. package/src/ui/docs/registry.tsx +580 -229
  145. package/src/ui/lib/semantic-context.ts +30 -0
  146. package/src/ui/meta.ts +278 -286
  147. package/src/ui/react.tsx +377 -111
  148. package/src/ui/theme.css +116 -0
  149. package/src/ui/components/primitives/alert-dialog.tsx +0 -190
  150. package/src/ui/docs/content/alert-dialog.md +0 -73
  151. package/src/ui/docs/content/button-group.md +0 -71
  152. package/src/ui/docs/content/confirm.md +0 -120
  153. package/src/ui/docs/content/input-group.md +0 -78
  154. package/src/ui/docs/content/toggle-group.md +0 -81
package/src/ui/meta.ts CHANGED
@@ -1,433 +1,425 @@
1
1
  /**
2
2
  * @softize/opus/ui/meta — o mapa CENTRAL de `meta` de todos os componentes.
3
3
  *
4
- * O componente portado é byte-fiel ao shadcn (sem `meta` co-localizado, pra re-sincronizar
4
+ * O componente portado é byte-fiel ao shadcn (sem `meta` co-localizado, para re-sincronizar
5
5
  * limpo); o metadado de descoberta (whenToUse/ancestry) mora AQUI, fora do arquivo. Quem
6
6
  * precisa do meta em RUNTIME — a doc de UI (DocBrowser), o manifesto, ferramentas — importa
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 './index.ts'
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
- 'ask': {
15
- name: 'ask',
16
- ancestry: 'opus',
14
+ content: {
15
+ name: "content",
16
+ ancestry: "opus",
17
17
  whenToUse:
18
- '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.',
18
+ "Organize uma região nomeada dentro de uma página ou de outra superfície. Use as propriedades de Content no caso comum e componha seus slots quando precisar controlar a estrutura. Para o cabeçalho principal da tela, use Page.",
19
19
  },
20
- 'alert': {
21
- name: 'alert',
22
- ancestry: 'opus',
20
+ ask: {
21
+ name: "ask",
22
+ ancestry: "opus",
23
23
  whenToUse:
24
- 'Aviso INLINE no fluxo da página (o erro do login, o "sincronizado" da lista) `role="alert"`, então o leitor de tela anuncia sozinho. Forma CURTA (o caso comum): `<Alert title description icon variant />` numa linha; composição (`AlertTitle`/`AlertDescription`) só quando o conteúdo é rico (parágrafos, link, ação). `variant` default/destructive/success/warning; quando informado, o ícone recebe realce tonal nativo. Pra INTERROMPER cobrando decisão, use `confirm()`; pra recado passageiro, `toast`.',
24
+ "Colete respostas para uma a quatro perguntas estruturadas, com opções de escolha única, múltipla ou texto livre. O consumidor controla as respostas e conecta o envio ao canal apropriado; Ask não faz transporte nem persistência.",
25
25
  },
26
- 'badge': {
27
- name: 'badge',
28
- ancestry: 'shadcn',
26
+ alert: {
27
+ name: "alert",
28
+ ancestry: "opus",
29
29
  whenToUse:
30
- 'Rótulo curto de status/categoria. `variant` pra intenção (default/secondary/destructive/outline) ou tom de status (success/warning/info/danger, fill tingido). Não-interativo pra clique, use Button ou `asChild` num <a>. Valor de dicionário com papel declarado usa DictionaryValue em vez de escolher a variante à mão.',
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 mantém uma moldura tonal quadrada, mesmo com descrição multilinha. O texto comunica o significado sem depender da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
31
31
  },
32
- 'empty-value': {
33
- name: 'empty-value',
34
- ancestry: 'opus',
32
+ badge: {
33
+ name: "badge",
34
+ ancestry: "shadcn",
35
35
  whenToUse:
36
- '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 a usam; renderer customizado reutiliza em vez de repetir a condicional.',
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` em um <a>. Valor de dicionário com papel declarado usa DictionaryValue em vez de escolher contexto ou variante na tela.",
37
37
  },
38
- 'dictionary-value': {
39
- name: 'dictionary-value',
40
- ancestry: 'opus',
38
+ "empty-value": {
39
+ name: "empty-value",
40
+ ancestry: "opus",
41
41
  whenToUse:
42
- 'Valor de um `t.dict` com a apresentação que o dicionário declarou (ADR 0003): `classification` vira Badge outline, `status`/`stage` viram Badge tonal pelo `tone` da entrada, `plain` ou sem papel vira texto. Ícone só quando a entrada declara `icon` do catálogo; tooltip só quando `description` acrescenta ao rótulo. O texto está sempre presente. Overrides explícitos por `presentation`, `variant`, `icon`, `tooltip` e `fallback`; não inferir badge, cor ou ícone a partir do nome do dicionário. Colunas de ActionList cujo campo é dicionário já usam este renderer.',
42
+ "Mostre valores ausentes de forma consistente e acessível. O modo compacto usa um travessão visual e preserva “Não informado” para leitores de tela; `label` permite declarar uma ausência específica do domínio. Zero e falso continuam sendo valores.",
43
43
  },
44
- 'dot': {
45
- name: 'dot',
46
- ancestry: 'opus',
44
+ "dictionary-value": {
45
+ name: "dictionary-value",
46
+ ancestry: "opus",
47
47
  whenToUse:
48
- 'Sinal compacto de estado quando o contexto ou o nome acessível já explica o significado. `variant` segue a intenção semântica (default/secondary/destructive/outline/success/warning/info). Passe `label` quando a cor comunicar informação; sem label, o ponto é decorativo. Para texto visível, use Badge.',
48
+ "Apresente um valor de `t.dict` conforme a semântica declarada no próprio dicionário. Classificações, status, estágios e valores simples recebem tratamentos previsíveis sem inferências pelo nome; use as propriedades de apresentação apenas para exceções explícitas.",
49
49
  },
50
- 'detail': {
51
- name: 'detail',
52
- ancestry: 'opus',
50
+ dot: {
51
+ name: "dot",
52
+ ancestry: "opus",
53
53
  whenToUse:
54
- '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, `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.',
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
- 'dock': {
57
- name: 'dock',
58
- ancestry: 'opus',
56
+ detail: {
57
+ name: "detail",
58
+ ancestry: "opus",
59
59
  whenToUse:
60
- '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.',
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
- 'button': {
63
- name: 'button',
64
- ancestry: 'shadcn',
62
+ dock: {
63
+ name: "dock",
64
+ ancestry: "opus",
65
65
  whenToUse:
66
- 'Ação clicável. `variant` define intenção (default/secondary/outline/ghost/destructive/link), `size` define altura (default/sm/lg · icon/icon-sm/icon-xs para os casos só-ícone, 2.25/2/1.5rem) e `shape="pill"` troca somente a geometria, sem alterar cor ou hierarquia. `busy` mostra spinner e desabilita. `asChild` renderiza como outro elemento.',
66
+ "Ancore ferramentas a uma superfície de trabalho, como canvas, editor ou prévia. Agrupe ações relacionadas com DockGroup e mantenha o estado da superfície em SurfaceStatus. Para ações da página, use Page; para opções exclusivas, use ToggleGroup.",
67
67
  },
68
- 'card': {
69
- name: 'card',
70
- ancestry: 'shadcn',
68
+ button: {
69
+ name: "button",
70
+ ancestry: "shadcn",
71
71
  whenToUse:
72
- '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) + CardContent + CardFooter o padding mora nos slots (como o Dialog). Divergência declarada vs shadcn: sem shadow e sem flex/gap forçados (o upstream brigava com card-box simples).',
72
+ "Inicie uma ação com um controle clicável. Use `context` para o significado, `variant` para o tratamento visual e `size` para a escala; `busy` comunica o andamento e impede um novo acionamento. Para ações relacionadas, use ButtonGroup.",
73
73
  },
74
- 'chat': {
75
- name: 'chat',
76
- ancestry: 'opus',
74
+ card: {
75
+ name: "card",
76
+ ancestry: "shadcn",
77
77
  whenToUse:
78
- '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`).',
78
+ "Agrupe conteúdo relacionado em uma superfície delimitada. Use Card diretamente para um bloco simples ou componha cabeçalho, corpo e rodapé quando houver hierarquia e ações. CardContent permanece apenas como alias temporário de compatibilidade.",
79
79
  },
80
- 'checkbox': {
81
- name: 'checkbox',
82
- ancestry: 'shadcn',
80
+ "metric-card": {
81
+ name: "metric-card",
82
+ ancestry: "opus",
83
83
  whenToUse:
84
- 'Caixa de marcação booleana (Radix). Controlado por `checked`/`onCheckedChange`. Parear com Label. Pra escolha única de várias opções, use Select/RadioGroup.',
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
- 'icon-picker': {
87
- name: 'icon-picker',
88
- ancestry: 'opus',
86
+ chat: {
87
+ name: "chat",
88
+ ancestry: "opus",
89
89
  whenToUse:
90
- '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).',
90
+ "Monte uma conversa completa com mensagens, composição, carregamento e rolagem automática. A propriedade `send` aceita resposta integral ou streaming de eventos; use Composer quando precisar apenas da entrada de texto. Defina uma altura para o contêiner.",
91
91
  },
92
- 'command': {
93
- name: 'command',
94
- ancestry: 'shadcn',
92
+ checkbox: {
93
+ name: "checkbox",
94
+ ancestry: "shadcn",
95
95
  whenToUse:
96
- 'Lista filtrável com teclado (cmdk) base de command-palettes. Use CommandDialog pra palette modal (⌘K). Pra escolha simples, use o Select direto.',
96
+ "Caixa de marcação booleana (Radix). Controlado por `checked`/`onCheckedChange`. Parear com Label. Para escolha única de várias opções, use Select/RadioGroup.",
97
97
  },
98
- 'composer': {
99
- name: 'composer',
100
- ancestry: 'opus',
98
+ "icon-picker": {
99
+ name: "icon-picker",
100
+ ancestry: "opus",
101
101
  whenToUse:
102
- '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.',
102
+ "Permita escolher um ícone por uma lista pesquisável. O valor é o nome do ícone em kebab-case; use a mesma paleta ao renderizá-lo e forneça `icons` quando o produto precisar de um vocabulário próprio.",
103
103
  },
104
- 'content-header': {
105
- name: 'content-header',
106
- ancestry: 'opus',
104
+ command: {
105
+ name: "command",
106
+ ancestry: "shadcn",
107
107
  whenToUse:
108
- 'Cabeçalho semântico de uma seção de conteúdo: título, descrição, meta e ações na mesma composição. Use `variant="section"` dentro de páginas e painéis; `Page` fornece o cabeçalho principal e não deve receber outro ContentHeader equivalente. O `level` controla a hierarquia do heading sem alterar a hierarquia visual.',
108
+ "Lista filtrável com teclado (cmdk) base de command-palettes. Use CommandDialog para palette modal (⌘K). Para escolha simples, use o Select direto.",
109
109
  },
110
- 'copyable': {
111
- name: 'copyable',
112
- ancestry: 'opus',
110
+ composer: {
111
+ name: "composer",
112
+ ancestry: "opus",
113
113
  whenToUse:
114
- '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).',
114
+ "Receba texto para envio sem montar uma conversa completa. Enter envia, Shift+Enter quebra a linha e `actions` acrescenta uma faixa para seletores relacionados. O componente é controlado; use Chat quando também precisar de mensagens e estado da conversa.",
115
115
  },
116
- 'dialog': {
117
- name: 'dialog',
118
- ancestry: 'shadcn',
116
+ "content-header": {
117
+ name: "content-header",
118
+ ancestry: "opus",
119
119
  whenToUse:
120
- '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.',
120
+ "Estruture o cabeçalho de um Content com título, descrição, metadados e ações. No caso comum, declare esses valores diretamente em Content; componha ContentHeader apenas quando precisar controlar a anatomia.",
121
121
  },
122
- 'input': {
123
- name: 'input',
124
- ancestry: 'shadcn',
122
+ copyable: {
123
+ name: "copyable",
124
+ ancestry: "opus",
125
125
  whenToUse:
126
- '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.',
126
+ "Copie identificadores, tokens, slugs ou URLs com confirmação visual. Sem filhos, Copyable funciona como botão de ícone; com filhos, mantém um rótulo visível. Em ambientes sem acesso à área de transferência, a ação não produz efeito.",
127
127
  },
128
- 'label': {
129
- name: 'label',
130
- ancestry: 'shadcn',
131
- whenToUse: 'Rótulo acessível de um campo. `htmlFor` aponta pro id do controle. Parear com Input/Textarea/Select.',
132
- },
133
- 'markdown': {
134
- name: 'markdown',
135
- ancestry: 'opus',
128
+ dialog: {
129
+ name: "dialog",
130
+ ancestry: "opus",
136
131
  whenToUse:
137
- '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 não empurram a caixa em volta. Pra código com destaque e cópia, CodeBlock.',
132
+ "Abra conteúdo ou uma tarefa em uma janela modal com foco contido. Use o modo padrão quando a superfície puder ser dispensada e `mode=\"alert\"` quando exigir resposta explícita. Para o caso imperativo comum, use `dialog.alert`, `dialog.confirm`, `dialog.prompt` ou `dialog.choose`. Distribua conteúdo próprio entre cabeçalho, corpo rolável e rodapé de ações.",
138
133
  },
139
- 'menu': {
140
- name: 'menu',
141
- ancestry: 'opus',
134
+ input: {
135
+ name: "input",
136
+ ancestry: "shadcn",
142
137
  whenToUse:
143
- 'O menu de AÇÕES da casa: lista flutuante ancorada num gatilho (Radix DropdownMenu). Compõe Menu > MenuTrigger (`asChild` funde no Button) + MenuContent > (MenuItem, MenuCheckboxItem, MenuRadioGroup>MenuRadioItem, MenuLabel, MenuSeparator, MenuShortcut, MenuSub>MenuSubTrigger+MenuSubContent). `variant="destructive"` no item para a ação que apaga. É o único menu (5.0.0): ContextMenu, Menubar e NavigationMenu saíram mesmo papel com outro gatilho, zero uso. Pra ESCOLHER um valor, use Select; pra busca por teclado, Command; pra conteúdo livre ancorado, Popover.',
138
+ "Receba texto em uma única linha com os atributos nativos de `input`. Use `icon` para identidade e `trailing` para uma ação no fim do campo; associe uma Label. Quando precisar combinar múltiplos adornos ou controles na mesma moldura, use InputGroup.",
144
139
  },
145
- 'popover': {
146
- name: 'popover',
147
- ancestry: 'shadcn',
140
+ label: {
141
+ name: "label",
142
+ ancestry: "shadcn",
148
143
  whenToUse:
149
- '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.',
144
+ "Rótulo acessível de um campo. `htmlFor` aponta para o id do controle. Parear com Input/Textarea/Select.",
150
145
  },
151
- 'select': {
152
- name: 'select',
153
- ancestry: 'opus',
146
+ markdown: {
147
+ name: "markdown",
148
+ ancestry: "opus",
154
149
  whenToUse:
155
- '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
- },
157
- 'separator': {
158
- name: 'separator',
159
- ancestry: 'shadcn',
160
- whenToUse: 'Linha divisória entre seções/itens (Radix). `orientation` horizontal|vertical. Decorativa por padrão (a11y).',
150
+ "Renderize Markdown como HTML semântico com a tipografia do tema. HTML recebido no texto é escapado, por isso o componente pode apresentar conteúdo de pessoas ou modelos com segurança. Para código com destaque e cópia, use CodeBlock.",
161
151
  },
162
- 'skeleton': {
163
- name: 'skeleton',
164
- ancestry: 'shadcn',
165
- whenToUse: 'Placeholder pulsante de carregamento. Dê o tamanho via className (h-4 w-32). Pra estado de loading antes do conteúdo chegar.',
152
+ menu: {
153
+ name: "menu",
154
+ ancestry: "opus",
155
+ whenToUse:
156
+ 'O menu de ações da casa: lista flutuante ancorada em um 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.',
166
157
  },
167
- 'spinner': {
168
- name: 'spinner',
169
- ancestry: 'shadcn',
170
- whenToUse: 'Loading girando (ação em andamento: botão, fetch). Pra placeholder com forma de conteúdo, use Skeleton.',
158
+ popover: {
159
+ name: "popover",
160
+ ancestry: "shadcn",
161
+ whenToUse:
162
+ "Painel flutuante ancorado em um gatilho, sem modal (Radix). Para conteúdo livre (form curto, detalhes). Use PopoverHeader/PopoverTitle/PopoverDescription para estruturar. Para lista de ações, use Menu; para modal, Dialog.",
171
163
  },
172
- 'table': {
173
- name: 'table',
174
- ancestry: 'shadcn',
164
+ select: {
165
+ name: "select",
166
+ ancestry: "opus",
175
167
  whenToUse:
176
- '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.',
168
+ "Ofereça escolhas a partir de uma lista declarada em `options`. Habilite pesquisa, seleção múltipla, busca remota ou controle nativo conforme a necessidade; use RadioGroup quando poucas opções precisarem permanecer visíveis.",
177
169
  },
178
- 'tabs': {
179
- name: 'tabs',
180
- ancestry: 'shadcn',
170
+ separator: {
171
+ name: "separator",
172
+ ancestry: "shadcn",
181
173
  whenToUse:
182
- '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).',
174
+ "Linha divisória entre seções/itens (Radix). `orientation` horizontal|vertical. Decorativa por padrão (a11y).",
183
175
  },
184
- 'textarea': {
185
- name: 'textarea',
186
- ancestry: 'shadcn',
176
+ skeleton: {
177
+ name: "skeleton",
178
+ ancestry: "shadcn",
187
179
  whenToUse:
188
- 'Campo de texto multilinha. Aceita os atributos nativos de <textarea> (rows, placeholder, disabled). Cresce com o conteúdo via `field-sizing-content`.',
180
+ "Reserve a forma aproximada do conteúdo enquanto ele carrega. Defina dimensões com `className`; para uma espera sem forma conhecida, use Spinner.",
189
181
  },
190
- 'toast': {
191
- name: 'toast',
192
- ancestry: 'shadcn',
182
+ spinner: {
183
+ name: "spinner",
184
+ ancestry: "shadcn",
193
185
  whenToUse:
194
- 'Notificação efêmera (sonner). Monte `<Toaster />` 1x no root e dispare com `toast.success/error/message(...)`. Pra mensagem persistente inline, use Alert.',
186
+ "Indique uma espera sem progresso determinado, como uma ação ou consulta em andamento. Para reservar a forma do conteúdo, use Skeleton.",
195
187
  },
196
- 'tooltip': {
197
- name: 'tooltip',
198
- ancestry: 'shadcn',
188
+ table: {
189
+ name: "table",
190
+ ancestry: "shadcn",
199
191
  whenToUse:
200
- 'Dica curta no hover/foco de um elemento (Radix). Envolver a árvore num TooltipProvider. texto auxiliarnunca pôr ação ou conteúdo essencial aqui.',
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. Para listagem tabularpara o pattern de search use ActionList.',
201
193
  },
202
- 'truncate': {
203
- name: 'truncate',
204
- ancestry: 'opus',
194
+ tabs: {
195
+ name: "tabs",
196
+ ancestry: "shadcn",
205
197
  whenToUse:
206
- 'Texto truncado com tooltip 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.',
198
+ "Alterne entre painéis relacionados no mesmo nível de navegação. Cada TabsTrigger aponta para um TabsContent pelo mesmo `value`; TabsList controla o tratamento visual e Tabs define orientação e escala.",
207
199
  },
208
- 'accordion': {
209
- name: 'accordion',
210
- ancestry: 'shadcn',
200
+ textarea: {
201
+ name: "textarea",
202
+ ancestry: "shadcn",
211
203
  whenToUse:
212
- '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.',
204
+ "Campo de texto multilinha. Aceita os atributos nativos de <textarea> (rows, placeholder, disabled). Cresce com o conteúdo via `field-sizing-content`.",
213
205
  },
214
- 'alert-dialog': {
215
- name: 'alert-dialog',
216
- ancestry: 'opus',
206
+ toast: {
207
+ name: "toast",
208
+ ancestry: "shadcn",
217
209
  whenToUse:
218
- '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 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.',
210
+ "Comunique um resultado temporário sem interromper o fluxo. Monte Toaster uma vez na raiz e dispare a notificação pela API `toast`; ações seguem a ordem declarada e a última recebe destaque primário. Para uma mensagem persistente no contexto da página, use Alert.",
219
211
  },
220
- 'aspect-ratio': {
221
- name: 'aspect-ratio',
222
- ancestry: 'shadcn',
212
+ tooltip: {
213
+ name: "tooltip",
214
+ ancestry: "shadcn",
223
215
  whenToUse:
224
- '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.',
216
+ "Ofereça uma dica curta ao passar o ponteiro ou focar um elemento. Envolva a árvore em TooltipProvider e mantenha ações ou conteúdo essencial fora do tooltip.",
225
217
  },
226
- 'avatar': {
227
- name: 'avatar',
228
- ancestry: 'shadcn',
218
+ truncate: {
219
+ name: "truncate",
220
+ ancestry: "opus",
229
221
  whenToUse:
230
- '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").',
222
+ "Trunque uma linha de texto e mostre a dica somente quando houver transbordamento. Use `tooltip` para substituir o conteúdo da dica e `fade` para trocar as reticências por um esmaecimento. Requer TooltipProvider na raiz.",
231
223
  },
232
- 'breadcrumb': {
233
- name: 'breadcrumb',
234
- ancestry: 'shadcn',
224
+ accordion: {
225
+ name: "accordion",
226
+ ancestry: "shadcn",
235
227
  whenToUse:
236
- '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.',
228
+ "Lista de seções empilhadas que abrem/fecham (Radix). `type` single (um painel por vez combine com `collapsible` para permitir fechar todos) ou multiple (vários abertos). Cada AccordionItem precisa de `value`; o chevron vem no AccordionTrigger. Para alternar conteúdo lado a lado, use Tabs; para um único bloco recolhível solto, use Collapsible.",
237
229
  },
238
- 'button-group': {
239
- name: 'button-group',
240
- ancestry: 'shadcn',
230
+ "aspect-ratio": {
231
+ name: "aspect-ratio",
232
+ ancestry: "shadcn",
241
233
  whenToUse:
242
- 'Junta botões (e Select) num bloco coeso bordas internas colapsadas e cantos arredondados 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.',
234
+ "Preserve a proporção de mídias, miniaturas e prévias enquanto a largura muda ou o conteúdo carrega. A largura vem do contêiner e `ratio` determina a altura; borda, arredondamento e recorte pertencem ao AspectRatio.",
243
235
  },
244
- 'calendar': {
245
- name: 'calendar',
246
- ancestry: 'shadcn',
236
+ avatar: {
237
+ name: "avatar",
238
+ ancestry: "shadcn",
247
239
  whenToUse:
248
- '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.',
240
+ "Represente uma pessoa ou agente por imagem, iniciais ou ícone de fallback. AvatarBadge acrescenta um estado no canto; AvatarGroup reúne participantes e AvatarGroupCount resume o excedente.",
249
241
  },
250
- 'carousel': {
251
- name: 'carousel',
252
- ancestry: 'shadcn',
242
+ breadcrumb: {
243
+ name: "breadcrumb",
244
+ ancestry: "shadcn",
253
245
  whenToUse:
254
- '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.',
246
+ "Trilha de navegação hierárquica (workspace repositório sessão): mostra onde o usuário está e o caminho de volta. `BreadcrumbLink` para os níveis navegáveis, `BreadcrumbPage` para o atual (não clicável), `BreadcrumbSeparator` entre eles e `BreadcrumbEllipsis` para colapsar trilhas longas. Para alternar painéis no mesmo nível, use Tabs.",
255
247
  },
256
- 'collapsible': {
257
- name: 'collapsible',
258
- ancestry: 'shadcn',
248
+ calendar: {
249
+ name: "calendar",
250
+ ancestry: "shadcn",
259
251
  whenToUse:
260
- 'Seção que abre e fecha (Radix): um CollapsibleTrigger revela ou esconde o CollapsibleContent. Compõe Collapsible > (CollapsibleTrigger + CollapsibleContent) o Trigger é 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.',
252
+ 'Grade de datas (react-day-picker) para 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 para um período distante); `numberOfMonths` mostra meses lado a lado; `disabled` (Matcher) corta datas. Para exibir em um popover de campo, ancore no Popover.',
261
253
  },
262
- 'drawer': {
263
- name: 'drawer',
264
- ancestry: 'opus',
254
+ carousel: {
255
+ name: "carousel",
256
+ ancestry: "shadcn",
265
257
  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") > (DrawerHeader > DrawerTitle/DrawerDescription, conteúdo, 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.',
258
+ "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. Para lista paginada de dados, use Table; para navegação entre painéis, Tabs.",
267
259
  },
268
- 'empty': {
269
- name: 'empty',
270
- ancestry: 'shadcn',
260
+ collapsible: {
261
+ name: "collapsible",
262
+ ancestry: "shadcn",
271
263
  whenToUse:
272
- '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.',
264
+ "Seção que abre e fecha (Radix): um CollapsibleTrigger revela ou esconde o CollapsibleContent. Compõe Collapsible > (CollapsibleTrigger + CollapsibleContent) o Trigger é o `<button>`. `defaultOpen` para o modo não controlado; `open`/`onOpenChange` para o controlado (ex.: girar o chevron); `disabled` trava o gatilho. Para alternar entre vários painéis, use Tabs; para menu de ações ancorado, Menu.",
273
265
  },
274
- 'field': {
275
- name: 'field',
276
- ancestry: 'shadcn',
266
+ drawer: {
267
+ name: "drawer",
268
+ ancestry: "opus",
277
269
  whenToUse:
278
- '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 quando 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).',
270
+ "Mostre detalhes ou edição a partir de uma borda da tela, sem trocar de página. Estruture cabeçalho, corpo e rodapé dentro de DrawerContent e escolha a borda com `side`. Para uma janela centralizada, use Dialog; para ações ancoradas, use Menu.",
279
271
  },
280
- 'input-group': {
281
- name: 'input-group',
282
- ancestry: 'shadcn',
272
+ empty: {
273
+ name: "empty",
274
+ ancestry: "shadcn",
283
275
  whenToUse:
284
- '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.',
276
+ "Apresente uma região disponível para receber ou criar conteúdo, com mensagem e ações de próximo passo. Para uma lista ou tabela sem registros, use DataState ou ActionList; para erro, use Alert.",
285
277
  },
286
- 'input-otp': {
287
- name: 'input-otp',
288
- ancestry: 'shadcn',
278
+ field: {
279
+ name: "field",
280
+ ancestry: "shadcn",
289
281
  whenToUse:
290
- '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.',
282
+ "Componha rótulo, controle, ajuda e erro com espaçamento consistente. Use a orientação vertical no caso comum e as orientações horizontal ou responsiva quando controle e texto precisarem ficar lado a lado. Field cuida do layout; o formulário continua responsável por estado e validação.",
291
283
  },
292
- 'item': {
293
- name: 'item',
294
- ancestry: 'shadcn',
284
+ "input-otp": {
285
+ name: "input-otp",
286
+ ancestry: "shadcn",
295
287
  whenToUse:
296
- 'Linha de conteúdo composta mídia + título/descrição + ações numa linha clicável ou estática. Item é o container (`variant` default/outline/muted, `size` default/sm, `asChild` pra virar link/botão); componha ItemMedia (`variant` icon/image), ItemContent (ItemTitle + ItemDescription), ItemActions e, na borda, ItemHeader/ItemFooter. Empilhe vários num ItemGroup: `variant="framed"` aplica a moldura e a superfície; ItemSeparator declara os divisores internos tanto no modo framed quanto no plain. É o padrão pra listas de workspaces, agentes, repositórios e sessões.',
288
+ "Receba um código numérico dividido em posições, como uma confirmação de acesso ou segundo fator. InputOTP define o comprimento, os slots representam as posições e o separador organiza blocos. Para texto livre, use Input.",
297
289
  },
298
- 'kbd': {
299
- name: 'kbd',
300
- ancestry: 'shadcn',
290
+ item: {
291
+ name: "item",
292
+ ancestry: "shadcn",
301
293
  whenToUse:
302
- '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.',
294
+ "Monte uma linha de conteúdo com mídia, título, descrição, corpo e ações. Ícones e imagens mantêm uma moldura quadrada alinhada ao topo; ItemGroup organiza várias linhas e seus divisores. ItemContent permanece apenas como alias legado.",
303
295
  },
304
- 'pagination': {
305
- name: 'pagination',
306
- ancestry: 'shadcn',
296
+ kbd: {
297
+ name: "kbd",
298
+ ancestry: "shadcn",
307
299
  whenToUse:
308
- 'Navegação entre páginas montada por composição: Pagination › PaginationContent › PaginationItem com PaginationLink, mais PaginationPrevious/PaginationNext e PaginationEllipsis. `page` 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.',
300
+ "Apresente uma tecla ou combinação de teclas. KbdGroup reúne várias teclas e conectores, mas não registra o atalho; o consumidor continua responsável pelo evento de teclado.",
309
301
  },
310
- 'progress': {
311
- name: 'progress',
312
- ancestry: 'shadcn',
302
+ pagination: {
303
+ name: "pagination",
304
+ ancestry: "shadcn",
313
305
  whenToUse:
314
- 'Barra de progresso determinada (Radix): mostra o quanto de uma tarefa 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.',
306
+ "Navegação entre páginas montada por composição: Pagination PaginationContent PaginationItem com PaginationLink, mais PaginationPrevious/PaginationNext e PaginationEllipsis. `page` 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é. Para rolagem infinita ou listas curtas, dispense a barra.",
315
307
  },
316
- 'radio-group': {
317
- name: 'radio-group',
318
- ancestry: 'shadcn',
308
+ progress: {
309
+ name: "progress",
310
+ ancestry: "shadcn",
319
311
  whenToUse:
320
- '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.',
312
+ "Mostre o avanço conhecido de uma tarefa com um valor entre zero e cem. Para uma espera sem percentual, use Spinner; para reservar a forma do conteúdo, use Skeleton.",
321
313
  },
322
- 'split': {
323
- name: 'split',
324
- ancestry: 'opus',
314
+ "radio-group": {
315
+ name: "radio-group",
316
+ ancestry: "shadcn",
325
317
  whenToUse:
326
- '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.',
318
+ "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. Para poucas opções que cabem na tela; com muitas, prefira Select; para ligar/desligar um único item, Checkbox ou Switch.",
327
319
  },
328
- 'sidebar': {
329
- name: 'sidebar',
330
- ancestry: 'opus',
320
+ split: {
321
+ name: "split",
322
+ ancestry: "opus",
331
323
  whenToUse:
332
- 'Chrome e navegação de uma coluna lateral, encaixada onde um Split decidir. `Sidebar` possui o colapso; `PaneHeader`, `PaneContent` e `PaneFooter` estruturam qualquer pane, e `SidebarNav`/`SidebarItem` apresentam navegação com grupos e subgrupos. Serve tanto a barra global quanto uma nav contextual; em Split redimensionável passe `divider={false}` para não duplicar a divisória.',
324
+ "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.",
333
325
  },
334
- 'scroll-area': {
335
- name: 'scroll-area',
336
- ancestry: 'shadcn',
326
+ sidebar: {
327
+ name: "sidebar",
328
+ ancestry: "opus",
337
329
  whenToUse:
338
- 'Região rolável com barra estilizada da casa (Radix), no lugar da scrollbar do sistema. altura (ou largura) ao ScrollArea via className e ponha o conteúdo dentro; a barra vertical 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).',
330
+ "Organize navegação global ou contextual em uma coluna lateral. Split e Pane definem posição e largura; Sidebar fornece a superfície e o colapso, enquanto PaneHeader, PaneBody e PaneFooter estruturam as regiões fixa e rolável. Use SidebarNav para grupos planos, componha árvores com SidebarItem e SidebarTreeGroup e use ShellNav quando a navegação precisar de cabeçalho e rodapé próprios.",
339
331
  },
340
- 'slider': {
341
- name: 'slider',
342
- ancestry: 'shadcn',
332
+ "scroll-area": {
333
+ name: "scroll-area",
334
+ ancestry: "shadcn",
343
335
  whenToUse:
344
- '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.',
336
+ '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 vem por padrão. Para rolagem horizontal, acrescente `<ScrollBar orientation="horizontal" />` como filho. Para a página inteira rolar, deixe o navegador cuidar — isto é para um painel com altura fixa (lista de sessões, log, trilho de skills).',
345
337
  },
346
- 'switch': {
347
- name: 'switch',
348
- ancestry: 'shadcn',
338
+ slider: {
339
+ name: "slider",
340
+ ancestry: "shadcn",
349
341
  whenToUse:
350
- '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.',
342
+ "Controle de valor em uma faixa contínua, arrastado pelo thumb (Radix). `min`/`max`/`step` delimitam a faixa; `value`/`onValueChange` controlam (array de números `[n]` para um thumb, `[a, b]` para um intervalo) ou `defaultValue` no modo não controlado. `orientation` horizontal/vertical, `disabled` esmaece. Para um número exato digitado, use Input type=number; para ligar/desligar, Switch.",
351
343
  },
352
- 'toggle': {
353
- name: 'toggle',
354
- ancestry: 'shadcn',
344
+ switch: {
345
+ name: "switch",
346
+ ancestry: "shadcn",
355
347
  whenToUse:
356
- '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.',
348
+ "Liga/desliga imediato de uma preferência booleana (Radix). Controlado por `checked`/`onCheckedChange` (boolean) e em par com Label. Use para estado que vale na hora (ativar agente, sincronizar); para confirmar dentro de um formulário, prefira Checkbox.",
357
349
  },
358
- 'toggle-group': {
359
- name: 'toggle-group',
360
- ancestry: 'shadcn',
350
+ toggle: {
351
+ name: "toggle",
352
+ ancestry: "shadcn",
361
353
  whenToUse:
362
- '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.',
354
+ "Alterne um estado diretamente no contexto atual. ToggleGroup reúne escolhas únicas ou múltiplas e compartilha aparência e escala entre os itens. Para um valor booleano com rótulo em formulário, prefira Switch ou Checkbox.",
363
355
  },
364
356
 
365
- 'confirm': {
366
- name: 'dialog',
367
- ancestry: 'opus',
357
+ confirm: {
358
+ name: "dialog",
359
+ ancestry: "opus",
368
360
  whenToUse:
369
- '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.',
361
+ "Solicite reconhecimento, confirmação ou uma resposta curta por uma API imperativa. Monte DialogHost uma vez no shell e use `dialog.alert`, `dialog.confirm` ou `dialog.prompt`; as solicitações são exibidas uma por vez. Para ações declaradas em contrato, prefira ActionTrigger; para formulários, use ActionFormDialog.",
370
362
  },
371
- 'action-form': {
372
- name: 'action-form',
373
- ancestry: 'opus',
363
+ "action-form": {
364
+ name: "action-form",
365
+ ancestry: "opus",
374
366
  whenToUse:
375
- '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.',
367
+ "Renderize e envie uma FormAction com validação, estado de envio e notificação consistentes. Sem filhos, os campos seguem o schema do contrato; com ActionFormField, o consumidor controla o layout sem duplicar rótulos ou erros. Para uma ação sem campos, use ActionTrigger.",
376
368
  },
377
- 'action-form-dialog': {
378
- name: 'action-form-dialog',
379
- ancestry: 'opus',
369
+ "action-form-dialog": {
370
+ name: "action-form-dialog",
371
+ ancestry: "opus",
380
372
  whenToUse:
381
- '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.',
373
+ "ActionForm dentro de um Dialog (form em modal) — controla open/onOpenChange + title; fecha no sucesso. Aceita children (modo composição) como o ActionForm. Para form inline em uma página, use ActionForm direto.",
382
374
  },
383
- 'action-form-card': {
384
- name: 'action-form-card',
385
- ancestry: 'opus',
375
+ "action-form-card": {
376
+ name: "action-form-card",
377
+ ancestry: "opus",
386
378
  whenToUse:
387
- '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.',
379
+ "Apresente uma FormAction como seção delimitada da página. ActionFormCard combina a estrutura do Card com o comportamento de ActionForm. Para um modal, use ActionFormDialog; sem superfície adicional, use ActionForm.",
388
380
  },
389
- 'action-list': {
390
- name: 'action-list',
391
- ancestry: 'opus',
381
+ "action-list": {
382
+ name: "action-list",
383
+ ancestry: "opus",
392
384
  whenToUse:
393
- '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.',
385
+ "Apresente uma coleção pesquisável a partir de uma ListAction. O contrato declara colunas, filtros, período e busca; ActionList coordena visualizações, paginação, seleção em lote e sincronização com a URL. Para um único recurso, use ActionView.",
394
386
  },
395
- 'action-trigger': {
396
- name: 'action-trigger',
397
- ancestry: 'opus',
387
+ "action-trigger": {
388
+ name: "action-trigger",
389
+ ancestry: "opus",
398
390
  whenToUse:
399
- '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.',
391
+ "Dispare uma SimpleAction sem campos com carregamento, notificação e confirmação consistentes. Declare confirmações destrutivas no contrato; sem essa declaração, a ação é executada diretamente. Para mutações com campos, use ActionForm.",
400
392
  },
401
- 'action-view': {
402
- name: 'action-view',
403
- ancestry: 'opus',
393
+ "action-view": {
394
+ name: "action-view",
395
+ ancestry: "opus",
404
396
  whenToUse:
405
- '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.',
397
+ "Carregue e apresente um recurso de uma ViewAction com estados de carregamento, erro e ausência consistentes. Os filhos definem o layout a partir dos dados e de `refetch`; para uma coleção, use ActionList.",
406
398
  },
407
- 'page': {
408
- name: 'page',
409
- ancestry: 'opus',
399
+ page: {
400
+ name: "page",
401
+ ancestry: "opus",
410
402
  whenToUse:
411
- 'O esqueleto de página do back-office: <main> + container centralizado com teto padrão de 72rem (`max-w-6xl`) + header com título, descrição e ação à direita (em geral o criar). `className` substitui o teto quando a composição pede outra largura. Presentacional (a página agrega N fontes); o action-driven mora dentro. Pra listagem em modal, ActionListDialog.',
403
+ "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. Para listagem em modal, ActionListDialog.",
412
404
  },
413
- 'router': {
414
- name: 'router',
415
- ancestry: 'opus',
405
+ router: {
406
+ name: "router",
407
+ ancestry: "opus",
416
408
  whenToUse:
417
- '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).',
409
+ "Sincronize navegação simples com a URL sem adicionar uma biblioteca de rotas. Os hooks leem caminho, segmentos e busca de forma reativa, enquanto `navigate` preserva links diretos, recarga e histórico. Para padrões de rota, parâmetros tipados ou carregamento por rota, use um roteador dedicado.",
418
410
  },
419
- 'data-state': {
420
- name: 'data-state',
421
- ancestry: 'opus',
411
+ "data-state": {
412
+ name: "data-state",
413
+ ancestry: "opus",
422
414
  whenToUse:
423
- '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.',
415
+ "Coordene carregamento, erro, vazio e conteúdo de uma consulta assíncrona. Use DataState dentro da estrutura que receberá os dados; para uma região disponível à criação, use Empty. Ações em andamento pertencem ao estado `busy` do controle que as iniciou.",
424
416
  },
425
- 'action-list-dialog': {
426
- name: 'action-list-dialog',
427
- ancestry: 'opus',
417
+ "action-list-dialog": {
418
+ name: "action-list-dialog",
419
+ ancestry: "opus",
428
420
  whenToUse:
429
- '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.',
421
+ "Apresente uma ListAction dentro de um modal com título, descrição, total e ação relacionada. Os filhos recebem itens e `refetch` para definir a composição da lista. Para uma coleção na página, use ActionList; para um formulário modal, use ActionFormDialog.",
430
422
  },
431
- } as const satisfies Record<string, ComponentMeta>
423
+ } as const satisfies Record<string, ComponentMeta>;
432
424
 
433
- export type ComponentMetaKey = keyof typeof componentMeta
425
+ export type ComponentMetaKey = keyof typeof componentMeta;