@softize/opus 12.11.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 (119) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/bin/lib/check.mjs +2 -7
  3. package/bin/lib/copy.mjs +1 -5
  4. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +93 -10
  5. package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
  6. package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
  7. package/docs/radius-scale.md +1 -1
  8. package/package.json +1 -1
  9. package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
  10. package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
  11. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
  12. package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
  13. package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
  14. package/src/ui/components/patterns/confirm.tsx +140 -40
  15. package/src/ui/components/patterns/list.tsx +35 -40
  16. package/src/ui/components/patterns/page-state.tsx +2 -2
  17. package/src/ui/components/patterns/sidebar.tsx +26 -26
  18. package/src/ui/components/patterns/trigger.tsx +25 -22
  19. package/src/ui/components/primitives/alert.tsx +3 -3
  20. package/src/ui/components/primitives/dialog.tsx +196 -39
  21. package/src/ui/components/primitives/drawer.tsx +8 -5
  22. package/src/ui/components/primitives/empty.tsx +3 -3
  23. package/src/ui/components/primitives/item.tsx +3 -3
  24. package/src/ui/components/primitives/sonner.tsx +187 -8
  25. package/src/ui/docs/DocBrowser.tsx +102 -23
  26. package/src/ui/docs/content/accordion.md +22 -16
  27. package/src/ui/docs/content/action-form-card.md +8 -8
  28. package/src/ui/docs/content/action-form-dialog.md +9 -9
  29. package/src/ui/docs/content/action-form.md +28 -34
  30. package/src/ui/docs/content/action-list-dialog.md +11 -6
  31. package/src/ui/docs/content/action-list.md +64 -39
  32. package/src/ui/docs/content/action-trigger.md +21 -14
  33. package/src/ui/docs/content/action-view.md +8 -8
  34. package/src/ui/docs/content/actions.md +9 -9
  35. package/src/ui/docs/content/ai.md +3 -3
  36. package/src/ui/docs/content/alert.md +14 -12
  37. package/src/ui/docs/content/aspect-ratio.md +4 -4
  38. package/src/ui/docs/content/audit.md +2 -2
  39. package/src/ui/docs/content/auth.md +3 -3
  40. package/src/ui/docs/content/avatar.md +34 -14
  41. package/src/ui/docs/content/badge.md +3 -3
  42. package/src/ui/docs/content/breadcrumb.md +13 -8
  43. package/src/ui/docs/content/button.md +81 -6
  44. package/src/ui/docs/content/calendar.md +5 -5
  45. package/src/ui/docs/content/card.md +1 -1
  46. package/src/ui/docs/content/carousel.md +16 -11
  47. package/src/ui/docs/content/chat.md +3 -3
  48. package/src/ui/docs/content/checkbox.md +7 -7
  49. package/src/ui/docs/content/cli.md +5 -5
  50. package/src/ui/docs/content/collapsible.md +8 -8
  51. package/src/ui/docs/content/command.md +16 -8
  52. package/src/ui/docs/content/composer.md +2 -2
  53. package/src/ui/docs/content/content.md +2 -2
  54. package/src/ui/docs/content/copyable.md +4 -3
  55. package/src/ui/docs/content/customization.md +5 -5
  56. package/src/ui/docs/content/cycle.md +3 -3
  57. package/src/ui/docs/content/data-state.md +11 -12
  58. package/src/ui/docs/content/data.md +26 -33
  59. package/src/ui/docs/content/detail.md +3 -3
  60. package/src/ui/docs/content/dialog.md +339 -31
  61. package/src/ui/docs/content/dictionary-value.md +8 -8
  62. package/src/ui/docs/content/dock.md +3 -3
  63. package/src/ui/docs/content/drawer.md +27 -14
  64. package/src/ui/docs/content/empty-value.md +2 -2
  65. package/src/ui/docs/content/empty.md +19 -12
  66. package/src/ui/docs/content/events.md +4 -4
  67. package/src/ui/docs/content/field.md +34 -12
  68. package/src/ui/docs/content/getting-started.md +1 -1
  69. package/src/ui/docs/content/icon-picker.md +8 -4
  70. package/src/ui/docs/content/input-otp.md +20 -12
  71. package/src/ui/docs/content/input.md +121 -9
  72. package/src/ui/docs/content/item.md +27 -13
  73. package/src/ui/docs/content/kbd.md +19 -11
  74. package/src/ui/docs/content/label.md +5 -3
  75. package/src/ui/docs/content/log.md +4 -4
  76. package/src/ui/docs/content/markdown.md +7 -6
  77. package/src/ui/docs/content/mcp.md +13 -15
  78. package/src/ui/docs/content/menu.md +34 -16
  79. package/src/ui/docs/content/observability.md +2 -2
  80. package/src/ui/docs/content/page.md +51 -6
  81. package/src/ui/docs/content/pagination.md +22 -17
  82. package/src/ui/docs/content/popover.md +16 -8
  83. package/src/ui/docs/content/progress.md +7 -5
  84. package/src/ui/docs/content/queue.md +5 -5
  85. package/src/ui/docs/content/radio-group.md +20 -12
  86. package/src/ui/docs/content/router.md +11 -6
  87. package/src/ui/docs/content/scheduler.md +4 -5
  88. package/src/ui/docs/content/scroll-area.md +12 -7
  89. package/src/ui/docs/content/select.md +42 -29
  90. package/src/ui/docs/content/separator.md +5 -5
  91. package/src/ui/docs/content/sidebar.md +323 -54
  92. package/src/ui/docs/content/skeleton.md +3 -2
  93. package/src/ui/docs/content/slider.md +8 -7
  94. package/src/ui/docs/content/spinner.md +8 -8
  95. package/src/ui/docs/content/split.md +8 -5
  96. package/src/ui/docs/content/storage.md +6 -8
  97. package/src/ui/docs/content/switch.md +8 -7
  98. package/src/ui/docs/content/table.md +13 -3
  99. package/src/ui/docs/content/tabs.md +28 -14
  100. package/src/ui/docs/content/testing.md +9 -11
  101. package/src/ui/docs/content/textarea.md +5 -4
  102. package/src/ui/docs/content/toast.md +47 -13
  103. package/src/ui/docs/content/toggle.md +75 -7
  104. package/src/ui/docs/content/tokens.md +3 -3
  105. package/src/ui/docs/content/tooltip.md +19 -11
  106. package/src/ui/docs/content/truncate.md +7 -8
  107. package/src/ui/docs/content/ui.md +10 -9
  108. package/src/ui/docs/content/upgrading.md +7 -8
  109. package/src/ui/docs/registry.tsx +20 -37
  110. package/src/ui/meta.ts +64 -94
  111. package/src/ui/react.tsx +15 -16
  112. package/src/ui/theme.css +50 -0
  113. package/src/ui/components/primitives/alert-dialog.tsx +0 -192
  114. package/src/ui/docs/content/alert-dialog.md +0 -73
  115. package/src/ui/docs/content/button-group.md +0 -71
  116. package/src/ui/docs/content/confirm.md +0 -120
  117. package/src/ui/docs/content/input-group.md +0 -79
  118. package/src/ui/docs/content/page-state.md +0 -45
  119. package/src/ui/docs/content/toggle-group.md +0 -81
package/src/ui/meta.ts CHANGED
@@ -1,7 +1,7 @@
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
@@ -15,37 +15,37 @@ export const componentMeta = {
15
15
  name: "content",
16
16
  ancestry: "opus",
17
17
  whenToUse:
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.",
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
20
  ask: {
21
21
  name: "ask",
22
22
  ancestry: "opus",
23
23
  whenToUse:
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.",
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
26
  alert: {
27
27
  name: "alert",
28
28
  ancestry: "opus",
29
29
  whenToUse:
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`.",
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 só da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
31
31
  },
32
32
  badge: {
33
33
  name: "badge",
34
34
  ancestry: "shadcn",
35
35
  whenToUse:
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.",
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
38
  "empty-value": {
39
39
  name: "empty-value",
40
40
  ancestry: "opus",
41
41
  whenToUse:
42
- "Representação padrão de valor ausente (`null`, `undefined`, string vazia ou 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.",
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
44
  "dictionary-value": {
45
45
  name: "dictionary-value",
46
46
  ancestry: "opus",
47
47
  whenToUse:
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.",
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
50
  dot: {
51
51
  name: "dot",
@@ -63,19 +63,19 @@ export const componentMeta = {
63
63
  name: "dock",
64
64
  ancestry: "opus",
65
65
  whenToUse:
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.",
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
68
  button: {
69
69
  name: "button",
70
70
  ancestry: "shadcn",
71
71
  whenToUse:
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.',
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
74
  card: {
75
75
  name: "card",
76
76
  ancestry: "shadcn",
77
77
  whenToUse:
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).',
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
80
  "metric-card": {
81
81
  name: "metric-card",
@@ -87,85 +87,85 @@ export const componentMeta = {
87
87
  name: "chat",
88
88
  ancestry: "opus",
89
89
  whenToUse:
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`).",
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
92
  checkbox: {
93
93
  name: "checkbox",
94
94
  ancestry: "shadcn",
95
95
  whenToUse:
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.",
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
98
  "icon-picker": {
99
99
  name: "icon-picker",
100
100
  ancestry: "opus",
101
101
  whenToUse:
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).",
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
104
  command: {
105
105
  name: "command",
106
106
  ancestry: "shadcn",
107
107
  whenToUse:
108
- "Lista filtrável com teclado (cmdk) — base de command-palettes. Use CommandDialog pra palette modal (⌘K). Pra escolha simples, use o Select direto.",
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
110
  composer: {
111
111
  name: "composer",
112
112
  ancestry: "opus",
113
113
  whenToUse:
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.",
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
116
  "content-header": {
117
117
  name: "content-header",
118
118
  ancestry: "opus",
119
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.",
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
122
  copyable: {
123
123
  name: "copyable",
124
124
  ancestry: "opus",
125
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).",
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
128
  dialog: {
129
129
  name: "dialog",
130
- ancestry: "shadcn",
130
+ ancestry: "opus",
131
131
  whenToUse:
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.',
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.",
133
133
  },
134
134
  input: {
135
135
  name: "input",
136
136
  ancestry: "shadcn",
137
137
  whenToUse:
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.",
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.",
139
139
  },
140
140
  label: {
141
141
  name: "label",
142
142
  ancestry: "shadcn",
143
143
  whenToUse:
144
- "Rótulo acessível de um campo. `htmlFor` aponta pro id do controle. Parear com Input/Textarea/Select.",
144
+ "Rótulo acessível de um campo. `htmlFor` aponta para o id do controle. Parear com Input/Textarea/Select.",
145
145
  },
146
146
  markdown: {
147
147
  name: "markdown",
148
148
  ancestry: "opus",
149
149
  whenToUse:
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.",
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.",
151
151
  },
152
152
  menu: {
153
153
  name: "menu",
154
154
  ancestry: "opus",
155
155
  whenToUse:
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.',
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.',
157
157
  },
158
158
  popover: {
159
159
  name: "popover",
160
160
  ancestry: "shadcn",
161
161
  whenToUse:
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.",
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.",
163
163
  },
164
164
  select: {
165
165
  name: "select",
166
166
  ancestry: "opus",
167
167
  whenToUse:
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`.',
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.",
169
169
  },
170
170
  separator: {
171
171
  name: "separator",
@@ -177,25 +177,25 @@ export const componentMeta = {
177
177
  name: "skeleton",
178
178
  ancestry: "shadcn",
179
179
  whenToUse:
180
- "Placeholder pulsante de carregamento. o tamanho via className (h-4 w-32). Pra estado de loading antes do conteúdo chegar.",
180
+ "Reserve a forma aproximada do conteúdo enquanto ele carrega. Defina dimensões com `className`; para uma espera sem forma conhecida, use Spinner.",
181
181
  },
182
182
  spinner: {
183
183
  name: "spinner",
184
184
  ancestry: "shadcn",
185
185
  whenToUse:
186
- "Loading girando (ação em andamento: botão, fetch). Pra placeholder com forma de conteúdo, use Skeleton.",
186
+ "Indique uma espera sem progresso determinado, como uma ação ou consulta em andamento. Para reservar a forma do conteúdo, use Skeleton.",
187
187
  },
188
188
  table: {
189
189
  name: "table",
190
190
  ancestry: "shadcn",
191
191
  whenToUse:
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.',
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 tabular — para o pattern de search use ActionList.',
193
193
  },
194
194
  tabs: {
195
195
  name: "tabs",
196
196
  ancestry: "shadcn",
197
197
  whenToUse:
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).",
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.",
199
199
  },
200
200
  textarea: {
201
201
  name: "textarea",
@@ -207,133 +207,115 @@ export const componentMeta = {
207
207
  name: "toast",
208
208
  ancestry: "shadcn",
209
209
  whenToUse:
210
- "Notificação efêmera (sonner). Monte `<Toaster />` 1x no root e dispare com `toast.success/error/message(...)`. Pra mensagem persistente inline, use Alert.",
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.",
211
211
  },
212
212
  tooltip: {
213
213
  name: "tooltip",
214
214
  ancestry: "shadcn",
215
215
  whenToUse:
216
- "Dica curta no hover/foco de um elemento (Radix). Envolver a árvore num TooltipProvider. texto auxiliar — nunca pôr ação ou conteúdo essencial aqui.",
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.",
217
217
  },
218
218
  truncate: {
219
219
  name: "truncate",
220
220
  ancestry: "opus",
221
221
  whenToUse:
222
- "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.",
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.",
223
223
  },
224
224
  accordion: {
225
225
  name: "accordion",
226
226
  ancestry: "shadcn",
227
227
  whenToUse:
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.",
229
- },
230
- "alert-dialog": {
231
- name: "alert-dialog",
232
- ancestry: "opus",
233
- whenToUse:
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.',
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 já vem no AccordionTrigger. Para alternar conteúdo lado a lado, use Tabs; para um único bloco recolhível solto, use Collapsible.",
235
229
  },
236
230
  "aspect-ratio": {
237
231
  name: "aspect-ratio",
238
232
  ancestry: "shadcn",
239
233
  whenToUse:
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.",
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.",
241
235
  },
242
236
  avatar: {
243
237
  name: "avatar",
244
238
  ancestry: "shadcn",
245
239
  whenToUse:
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").',
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.",
247
241
  },
248
242
  breadcrumb: {
249
243
  name: "breadcrumb",
250
244
  ancestry: "shadcn",
251
245
  whenToUse:
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.",
253
- },
254
- "button-group": {
255
- name: "button-group",
256
- ancestry: "shadcn",
257
- whenToUse:
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.',
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.",
259
247
  },
260
248
  calendar: {
261
249
  name: "calendar",
262
250
  ancestry: "shadcn",
263
251
  whenToUse:
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.',
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.',
265
253
  },
266
254
  carousel: {
267
255
  name: "carousel",
268
256
  ancestry: "shadcn",
269
257
  whenToUse:
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.",
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.",
271
259
  },
272
260
  collapsible: {
273
261
  name: "collapsible",
274
262
  ancestry: "shadcn",
275
263
  whenToUse:
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.",
264
+ "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` 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.",
277
265
  },
278
266
  drawer: {
279
267
  name: "drawer",
280
268
  ancestry: "opus",
281
269
  whenToUse:
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.',
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.",
283
271
  },
284
272
  empty: {
285
273
  name: "empty",
286
274
  ancestry: "shadcn",
287
275
  whenToUse:
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.",
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.",
289
277
  },
290
278
  field: {
291
279
  name: "field",
292
280
  ancestry: "shadcn",
293
281
  whenToUse:
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 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).",
295
- },
296
- "input-group": {
297
- name: "input-group",
298
- ancestry: "shadcn",
299
- whenToUse:
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.',
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.",
301
283
  },
302
284
  "input-otp": {
303
285
  name: "input-otp",
304
286
  ancestry: "shadcn",
305
287
  whenToUse:
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.",
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.",
307
289
  },
308
290
  item: {
309
291
  name: "item",
310
292
  ancestry: "shadcn",
311
293
  whenToUse:
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 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.',
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.",
313
295
  },
314
296
  kbd: {
315
297
  name: "kbd",
316
298
  ancestry: "shadcn",
317
299
  whenToUse:
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.',
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.",
319
301
  },
320
302
  pagination: {
321
303
  name: "pagination",
322
304
  ancestry: "shadcn",
323
305
  whenToUse:
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.",
306
+ "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é. Para rolagem infinita ou listas curtas, dispense a barra.",
325
307
  },
326
308
  progress: {
327
309
  name: "progress",
328
310
  ancestry: "shadcn",
329
311
  whenToUse:
330
- "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.",
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.",
331
313
  },
332
314
  "radio-group": {
333
315
  name: "radio-group",
334
316
  ancestry: "shadcn",
335
317
  whenToUse:
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.",
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.",
337
319
  },
338
320
  split: {
339
321
  name: "split",
@@ -345,110 +327,98 @@ export const componentMeta = {
345
327
  name: "sidebar",
346
328
  ancestry: "opus",
347
329
  whenToUse:
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.",
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.",
349
331
  },
350
332
  "scroll-area": {
351
333
  name: "scroll-area",
352
334
  ancestry: "shadcn",
353
335
  whenToUse:
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).',
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 já 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).',
355
337
  },
356
338
  slider: {
357
339
  name: "slider",
358
340
  ancestry: "shadcn",
359
341
  whenToUse:
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.",
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.",
361
343
  },
362
344
  switch: {
363
345
  name: "switch",
364
346
  ancestry: "shadcn",
365
347
  whenToUse:
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.",
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.",
367
349
  },
368
350
  toggle: {
369
351
  name: "toggle",
370
352
  ancestry: "shadcn",
371
353
  whenToUse:
372
- "Botão de duas posições — liga/desliga um estado in-loco, sem sair da tela (Radix). `variant` default (fundo 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.",
373
- },
374
- "toggle-group": {
375
- name: "toggle-group",
376
- ancestry: "shadcn",
377
- whenToUse:
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.",
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.",
379
355
  },
380
356
 
381
357
  confirm: {
382
358
  name: "dialog",
383
359
  ancestry: "opus",
384
360
  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.",
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.",
386
362
  },
387
363
  "action-form": {
388
364
  name: "action-form",
389
365
  ancestry: "opus",
390
366
  whenToUse:
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.",
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.",
392
368
  },
393
369
  "action-form-dialog": {
394
370
  name: "action-form-dialog",
395
371
  ancestry: "opus",
396
372
  whenToUse:
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.",
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.",
398
374
  },
399
375
  "action-form-card": {
400
376
  name: "action-form-card",
401
377
  ancestry: "opus",
402
378
  whenToUse:
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.",
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.",
404
380
  },
405
381
  "action-list": {
406
382
  name: "action-list",
407
383
  ancestry: "opus",
408
384
  whenToUse:
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.",
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.",
410
386
  },
411
387
  "action-trigger": {
412
388
  name: "action-trigger",
413
389
  ancestry: "opus",
414
390
  whenToUse:
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.",
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.",
416
392
  },
417
393
  "action-view": {
418
394
  name: "action-view",
419
395
  ancestry: "opus",
420
396
  whenToUse:
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.",
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.",
422
398
  },
423
399
  page: {
424
400
  name: "page",
425
401
  ancestry: "opus",
426
402
  whenToUse:
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.",
428
- },
429
- "page-state": {
430
- name: "page-state",
431
- ancestry: "opus",
432
- whenToUse:
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.",
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.",
434
404
  },
435
405
  router: {
436
406
  name: "router",
437
407
  ancestry: "opus",
438
408
  whenToUse:
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).',
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.",
440
410
  },
441
411
  "data-state": {
442
412
  name: "data-state",
443
413
  ancestry: "opus",
444
414
  whenToUse:
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.',
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.",
446
416
  },
447
417
  "action-list-dialog": {
448
418
  name: "action-list-dialog",
449
419
  ancestry: "opus",
450
420
  whenToUse:
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.',
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.",
452
422
  },
453
423
  } as const satisfies Record<string, ComponentMeta>;
454
424