@softize/opus 12.11.0 → 13.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/PROMOTED.md +46 -0
  3. package/README.md +28 -19
  4. package/bin/cli.mjs +87 -216
  5. package/bin/lib/check.mjs +2 -7
  6. package/bin/lib/cli-shared.mjs +131 -0
  7. package/bin/lib/copy.mjs +1 -5
  8. package/bin/lib/db.mjs +16 -74
  9. package/bin/lib/gen-openapi.mjs +3 -3
  10. package/bin/lib/gen-runner.mjs +1 -1
  11. package/bin/lib/gen.mjs +14 -69
  12. package/bin/lib/mcp.mjs +3 -1
  13. package/bin/lib/seed.mjs +5 -62
  14. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +93 -10
  15. package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
  16. package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
  17. package/docs/ownership-vs-shadcn-lock.md +2 -3
  18. package/docs/protocol.md +7 -7
  19. package/docs/radius-scale.md +1 -1
  20. package/docs/releasing.md +8 -2
  21. package/package.json +7 -3
  22. package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
  23. package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
  24. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
  25. package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
  26. package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
  27. package/registry/templates/app/package.json +1 -1
  28. package/registry/templates/app/src/main.tsx +4 -4
  29. package/src/audit/drivers/console.ts +1 -0
  30. package/src/auth/drivers/better-auth.ts +1 -0
  31. package/src/auth/drivers/jwt.ts +1 -0
  32. package/src/cache/drivers/memory.ts +1 -0
  33. package/src/client/drivers/fetch.ts +2 -1
  34. package/src/core/actions.ts +6 -1
  35. package/src/core/audit.ts +9 -3
  36. package/src/core/contracts.ts +7 -0
  37. package/src/core/domain.ts +1 -1
  38. package/src/core/errors.ts +18 -15
  39. package/src/core/index.ts +4 -2
  40. package/src/core/package-version.ts +26 -0
  41. package/src/core/reactions.ts +1 -1
  42. package/src/core/runtime.ts +33 -23
  43. package/src/core/schedules.ts +1 -1
  44. package/src/core/types.ts +2 -2
  45. package/src/dsl/eval.ts +2 -2
  46. package/src/dsl/kysely.ts +2 -2
  47. package/src/dsl/loads.ts +1 -1
  48. package/src/dsl/parser.ts +5 -5
  49. package/src/events/drivers/mitt.ts +1 -0
  50. package/src/mcp/index.ts +2 -1
  51. package/src/observability/drivers/opentelemetry.ts +1 -0
  52. package/src/queue/drivers/bullmq.ts +3 -3
  53. package/src/scheduler/drivers/node-cron.ts +3 -2
  54. package/src/scheduler/every.ts +7 -7
  55. package/src/schema/openapi.ts +3 -3
  56. package/src/seed/index.ts +29 -0
  57. package/src/server/drivers/fastify.ts +5 -2
  58. package/src/server/drivers/node.ts +9 -6
  59. package/src/server/index.ts +3 -1
  60. package/src/storage/drivers/fs.ts +1 -0
  61. package/src/testing/index.ts +3 -3
  62. package/src/ui/components/patterns/confirm.tsx +142 -42
  63. package/src/ui/components/patterns/content-header.tsx +7 -1
  64. package/src/ui/components/patterns/data-state.tsx +1 -1
  65. package/src/ui/components/patterns/dock.tsx +20 -3
  66. package/src/ui/components/patterns/form.tsx +12 -8
  67. package/src/ui/components/patterns/list.tsx +36 -41
  68. package/src/ui/components/patterns/page-state.tsx +2 -2
  69. package/src/ui/components/patterns/page.tsx +19 -1
  70. package/src/ui/components/patterns/shell-nav.tsx +10 -3
  71. package/src/ui/components/patterns/sidebar.tsx +43 -32
  72. package/src/ui/components/patterns/trigger.tsx +39 -38
  73. package/src/ui/components/patterns/view.tsx +26 -17
  74. package/src/ui/components/primitives/alert.tsx +14 -8
  75. package/src/ui/components/primitives/ask.tsx +3 -3
  76. package/src/ui/components/primitives/badge.tsx +11 -6
  77. package/src/ui/components/primitives/breadcrumb.tsx +2 -2
  78. package/src/ui/components/primitives/button.tsx +16 -3
  79. package/src/ui/components/primitives/calendar.tsx +28 -2
  80. package/src/ui/components/primitives/carousel.tsx +3 -3
  81. package/src/ui/components/primitives/chat.tsx +1 -1
  82. package/src/ui/components/primitives/checkbox.tsx +1 -1
  83. package/src/ui/components/primitives/command.tsx +2 -2
  84. package/src/ui/components/primitives/control.ts +12 -0
  85. package/src/ui/components/primitives/copyable.tsx +1 -1
  86. package/src/ui/components/primitives/dialog.tsx +202 -40
  87. package/src/ui/components/primitives/dot.tsx +5 -0
  88. package/src/ui/components/primitives/drawer.tsx +18 -8
  89. package/src/ui/components/primitives/empty.tsx +3 -3
  90. package/src/ui/components/primitives/field.tsx +3 -3
  91. package/src/ui/components/primitives/icon-picker.tsx +3 -1
  92. package/src/ui/components/primitives/input-group.tsx +1 -1
  93. package/src/ui/components/primitives/input-otp.tsx +1 -1
  94. package/src/ui/components/primitives/input.tsx +2 -2
  95. package/src/ui/components/primitives/item.tsx +3 -3
  96. package/src/ui/components/primitives/progress.tsx +32 -3
  97. package/src/ui/components/primitives/radio-group.tsx +1 -1
  98. package/src/ui/components/primitives/resizable.tsx +3 -1
  99. package/src/ui/components/primitives/select.tsx +5 -5
  100. package/src/ui/components/primitives/slider.tsx +5 -1
  101. package/src/ui/components/primitives/sonner.tsx +190 -8
  102. package/src/ui/components/primitives/switch.tsx +1 -0
  103. package/src/ui/components/primitives/tabs.tsx +1 -0
  104. package/src/ui/components/primitives/textarea.tsx +1 -1
  105. package/src/ui/components/primitives/toggle.tsx +1 -1
  106. package/src/ui/components/primitives/tooltip.tsx +1 -0
  107. package/src/ui/docs/DocBrowser.tsx +102 -23
  108. package/src/ui/docs/changelog.tsx +1 -1
  109. package/src/ui/docs/content/accordion.md +22 -16
  110. package/src/ui/docs/content/action-form-card.md +8 -8
  111. package/src/ui/docs/content/action-form-dialog.md +9 -9
  112. package/src/ui/docs/content/action-form.md +37 -36
  113. package/src/ui/docs/content/action-list-dialog.md +11 -6
  114. package/src/ui/docs/content/action-list.md +73 -39
  115. package/src/ui/docs/content/action-trigger.md +29 -15
  116. package/src/ui/docs/content/action-view.md +17 -10
  117. package/src/ui/docs/content/actions.md +9 -9
  118. package/src/ui/docs/content/ai.md +3 -3
  119. package/src/ui/docs/content/alert.md +14 -12
  120. package/src/ui/docs/content/ask.md +11 -0
  121. package/src/ui/docs/content/aspect-ratio.md +4 -4
  122. package/src/ui/docs/content/audit.md +2 -2
  123. package/src/ui/docs/content/auth.md +3 -3
  124. package/src/ui/docs/content/avatar.md +34 -14
  125. package/src/ui/docs/content/badge.md +3 -3
  126. package/src/ui/docs/content/breadcrumb.md +13 -8
  127. package/src/ui/docs/content/button.md +81 -6
  128. package/src/ui/docs/content/calendar.md +18 -5
  129. package/src/ui/docs/content/card.md +27 -1
  130. package/src/ui/docs/content/carousel.md +16 -11
  131. package/src/ui/docs/content/chat.md +23 -3
  132. package/src/ui/docs/content/checkbox.md +7 -7
  133. package/src/ui/docs/content/cli.md +74 -22
  134. package/src/ui/docs/content/collapsible.md +8 -8
  135. package/src/ui/docs/content/command.md +16 -8
  136. package/src/ui/docs/content/composer.md +17 -2
  137. package/src/ui/docs/content/content.md +17 -2
  138. package/src/ui/docs/content/copyable.md +12 -3
  139. package/src/ui/docs/content/customization.md +5 -5
  140. package/src/ui/docs/content/cycle.md +3 -3
  141. package/src/ui/docs/content/data-state.md +11 -12
  142. package/src/ui/docs/content/data.md +26 -33
  143. package/src/ui/docs/content/detail.md +22 -4
  144. package/src/ui/docs/content/dialog.md +339 -31
  145. package/src/ui/docs/content/dictionary-value.md +17 -10
  146. package/src/ui/docs/content/dock.md +11 -3
  147. package/src/ui/docs/content/dot.md +8 -0
  148. package/src/ui/docs/content/drawer.md +27 -14
  149. package/src/ui/docs/content/empty-value.md +2 -2
  150. package/src/ui/docs/content/empty.md +19 -12
  151. package/src/ui/docs/content/events.md +4 -4
  152. package/src/ui/docs/content/field.md +34 -12
  153. package/src/ui/docs/content/getting-started.md +3 -3
  154. package/src/ui/docs/content/icon-picker.md +19 -4
  155. package/src/ui/docs/content/input-otp.md +20 -12
  156. package/src/ui/docs/content/input.md +121 -9
  157. package/src/ui/docs/content/item.md +27 -13
  158. package/src/ui/docs/content/kbd.md +19 -11
  159. package/src/ui/docs/content/label.md +12 -3
  160. package/src/ui/docs/content/log.md +4 -4
  161. package/src/ui/docs/content/markdown.md +7 -6
  162. package/src/ui/docs/content/mcp.md +13 -15
  163. package/src/ui/docs/content/menu.md +40 -16
  164. package/src/ui/docs/content/metric-card.md +13 -0
  165. package/src/ui/docs/content/observability.md +2 -2
  166. package/src/ui/docs/content/page.md +59 -6
  167. package/src/ui/docs/content/pagination.md +22 -17
  168. package/src/ui/docs/content/popover.md +22 -8
  169. package/src/ui/docs/content/progress.md +15 -16
  170. package/src/ui/docs/content/queue.md +5 -5
  171. package/src/ui/docs/content/radio-group.md +20 -12
  172. package/src/ui/docs/content/router.md +11 -6
  173. package/src/ui/docs/content/scheduler.md +4 -5
  174. package/src/ui/docs/content/scroll-area.md +12 -7
  175. package/src/ui/docs/content/select.md +47 -34
  176. package/src/ui/docs/content/semantic-context.md +2 -2
  177. package/src/ui/docs/content/separator.md +5 -5
  178. package/src/ui/docs/content/sidebar.md +329 -54
  179. package/src/ui/docs/content/skeleton.md +9 -2
  180. package/src/ui/docs/content/slider.md +8 -7
  181. package/src/ui/docs/content/spinner.md +8 -8
  182. package/src/ui/docs/content/split.md +29 -5
  183. package/src/ui/docs/content/storage.md +6 -8
  184. package/src/ui/docs/content/switch.md +8 -7
  185. package/src/ui/docs/content/table.md +13 -3
  186. package/src/ui/docs/content/tabs.md +28 -14
  187. package/src/ui/docs/content/testing.md +9 -11
  188. package/src/ui/docs/content/textarea.md +12 -4
  189. package/src/ui/docs/content/toast.md +47 -13
  190. package/src/ui/docs/content/toggle.md +75 -7
  191. package/src/ui/docs/content/tokens.md +7 -7
  192. package/src/ui/docs/content/tooltip.md +19 -11
  193. package/src/ui/docs/content/truncate.md +15 -8
  194. package/src/ui/docs/content/ui.md +24 -9
  195. package/src/ui/docs/content/upgrading.md +7 -8
  196. package/src/ui/docs/doc-client.tsx +5 -5
  197. package/src/ui/docs/doc.tsx +26 -14
  198. package/src/ui/docs/registry.tsx +25 -42
  199. package/src/ui/docs/standalone.tsx +2 -2
  200. package/src/ui/drivers/react.tsx +17 -12
  201. package/src/ui/lib/action-errors.ts +45 -0
  202. package/src/ui/lib/zod-pt-br.ts +31 -4
  203. package/src/ui/meta.ts +65 -95
  204. package/src/ui/react.tsx +17 -16
  205. package/src/ui/theme.css +60 -8
  206. package/src/vite/design.ts +6 -18
  207. package/src/ui/components/primitives/alert-dialog.tsx +0 -192
  208. package/src/ui/docs/content/alert-dialog.md +0 -73
  209. package/src/ui/docs/content/button-group.md +0 -71
  210. package/src/ui/docs/content/confirm.md +0 -120
  211. package/src/ui/docs/content/input-group.md +0 -79
  212. package/src/ui/docs/content/page-state.md +0 -45
  213. package/src/ui/docs/content/toggle-group.md +0 -81
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Um slide por vez
2
2
 
3
- Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext pra navegar. As setas ficam fora do trilho (-left-12/-right-12), então reserve a margem lateral no entorno.
3
+ Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext para navegar. As setas ficam fora do trilho (-left-12/-right-12), então reserve a margem lateral no entorno.
4
4
 
5
5
  ```tsx preview
6
6
  <Carousel className="mx-12 w-full max-w-xs">
@@ -28,7 +28,7 @@ Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext
28
28
 
29
29
  ## Vários por vista
30
30
 
31
- O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três slides por vez. Bom pra galeria de workspaces ou repositórios.
31
+ O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três slides por vez. Bom para galeria de workspaces ou repositórios.
32
32
 
33
33
  ```tsx preview
34
34
  <Carousel className="mx-12 w-full max-w-sm" opts={{ align: 'start' }}>
@@ -48,7 +48,7 @@ O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três
48
48
 
49
49
  ## Vertical
50
50
 
51
- orientation=vertical empilha os slides; as setas migram pra cima e pra baixo (-top-12/-bottom-12). Dê uma altura ao CarouselContent pra delimitar a vista.
51
+ orientation=vertical empilha os slides; as setas migram para cima e para baixo (-top-12/-bottom-12). Dê uma altura ao CarouselContent para delimitar a vista.
52
52
 
53
53
  ```tsx preview
54
54
  <Carousel className="w-full max-w-xs" orientation="vertical">
@@ -74,12 +74,17 @@ orientation=vertical empilha os slides; as setas migram pra cima e pra baixo (-t
74
74
  </Carousel>
75
75
  ```
76
76
 
77
- ## Props
77
+ ## Propriedades de Carousel
78
78
 
79
- | Prop | Tipo | Default | Descrição |
79
+ | Propriedade | Tipo | Padrão | Descrição |
80
80
  |---|---|---|---|
81
- | `orientation (Carousel)` | `'horizontal' \| 'vertical'` | `'horizontal'` | Eixo do deslize vertical empilha os slides e gira as setas pro topo/base. |
82
- | `opts (Carousel)` | `CarouselOptions` | | Opções do embla (ex.: { loop: true }, { align: "start" }). Repassadas direto pro motor. |
83
- | `setApi (Carousel)` | `(api: CarouselApi) => void` | | Recebe a instância do embla pra controlar de fora (scrollTo, ler o slide ativo). |
84
- | `plugins (Carousel)` | `CarouselPlugin` | | Plugins do embla (ex.: autoplay) anexados ao carousel. |
85
- | `className (CarouselItem)` | `string` | | O basis decide quantos slides cabem na vista (basis-full, basis-1/2, basis-1/3). |
81
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Eixo do deslocamento. No modo vertical, os slides são empilhados e as setas apontam para cima e para baixo. |
82
+ | `opts` | `CarouselOptions` | | Opções repassadas ao Embla, como `{ loop: true }` ou `{ align: 'start' }`. |
83
+ | `setApi` | `(api: CarouselApi) => void` | | Recebe a instância para controle externo, como navegar com `scrollTo` ou ler o slide ativo. |
84
+ | `plugins` | `CarouselPlugin[]` | | Plugins do Embla associados ao carrossel, como autoplay. |
85
+
86
+ ## Propriedades de CarouselItem
87
+
88
+ | Propriedade | Tipo | Padrão | Descrição |
89
+ |---|---|---|---|
90
+ | `className` | `string` | | Classes de dimensão; a base define quantos slides cabem na área visível. |
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Conversa com resposta integral
2
2
 
3
- Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por dentro (estado, loading, auto-scroll; **Enter** envia, **Shift+Enter** quebra linha) — a inteligência vem da prop `send`. Com o composer vazio, **↑** recupera as mensagens anteriores do usuário e **↓** volta em direção ao rascunho; durante a edição, as setas continuam movendo o cursor normalmente. O `greeting` é o estado vazio (centrado; some quando a conversa começa e NÃO entra no transcript). Dê altura ao container.
3
+ Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por dentro (estado, loading, auto-scroll; **Enter** envia, **Shift+Enter** quebra linha) — a inteligência vem da prop `send`. Com o composer vazio, **↑** recupera as mensagens anteriores do usuário e **↓** volta em direção ao rascunho; durante a edição, as setas continuam movendo o cursor normalmente. O `greeting` é o estado vazio (centrado; some quando a conversa começa e não entra no transcript). Dê altura ao container.
4
4
 
5
5
  ```tsx preview
6
6
  <div className="h-96 rounded-lg border">
@@ -9,7 +9,7 @@ Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por den
9
9
  send={async (messages) => {
10
10
  await new Promise((r) => setTimeout(r, 500))
11
11
  const last = messages[messages.length - 1]
12
- return `Você disse: "${last.content}". (Num app real, aqui rodaria o agente.)`
12
+ return `Você disse: "${last.content}". (Em um app real, aqui rodaria o agente.)`
13
13
  }}
14
14
  />
15
15
  </div>
@@ -91,3 +91,23 @@ continua valendo — é o caso degenerado do protocolo.
91
91
  Reidratação: passe `initialMessages` com o histórico persistido e troque a `key` do
92
92
  componente ao trocar de conversa. O rótulo do indicador é customizável por
93
93
  `humanizeTool={(name) => '…'}`.
94
+
95
+ ## Propriedades de Chat
96
+
97
+ | Propriedade | Tipo | Padrão | Descrição |
98
+ |---|---|---|---|
99
+ | `send` | `(messages: ChatMessage[]) => Promise<string> \| AsyncIterable<ChatEvent>` | | Modo autogerenciado: envia o histórico e devolve a resposta inteira ou um stream de eventos. Ignorado no modo controlado. |
100
+ | `messages` | `ChatTranscriptItem[]` | | Modo controlado: o transcript vem do app; com ele, `onSend`, `busy` e `activity` assumem. |
101
+ | `onSend` | `(text: string) => void \| boolean \| Promise<void \| boolean>` | | Modo controlado: recebe o texto enviado; retornar `false` devolve o texto ao composer. |
102
+ | `busy` | `boolean` | | Modo controlado: trava o composer enquanto o turno corre. |
103
+ | `activity` | `string \| null` | `undefined` | Indicador vivo: `null` mostra “Pensando…”, string mostra o rótulo; `undefined` esconde. |
104
+ | `notice` | `ReactNode` | | Aviso do app acima do composer (credencial, agente desatualizado…). |
105
+ | `composerActions` | `ReactNode` | | Seletores discretos na barra do composer (agente, app, escopo). |
106
+ | `composerClassName` | `string` | | Ajusta o contêiner externo do composer sem alcançar o DOM interno. |
107
+ | `greeting` | `string` | | Texto do estado vazio; some quando a conversa começa. |
108
+ | `empty` | `ReactNode` | | Estado vazio composto pelo app; vence `greeting` quando os dois existem. |
109
+ | `initialMessages` | `ChatMessage[]` | | Histórico inicial do modo autogerenciado; troque a `key` ao trocar de conversa. |
110
+ | `kickoff` | `() => Promise<string> \| AsyncIterable<ChatEvent>` | | Conversa que começa pelo assistente, uma vez, quando o transcript nasce vazio. |
111
+ | `renderArtifact` | `(artifact: ChatArtifact) => ReactNode` | link com o título | Render do evento `artifact`. |
112
+ | `humanizeTool` | `(name: string, detail?: string) => string` | pt-BR embutido | Rótulo humano do tool em uso no indicador vivo. |
113
+ | `placeholder` | `string` | `'Escreva uma mensagem…'` | Placeholder do composer. |
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Escolha booleana
2
2
 
3
- Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a caixa. defaultChecked pro modo não controlado.
3
+ Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a caixa. defaultChecked para o modo não controlado.
4
4
 
5
5
  ```tsx preview
6
6
  <div className="flex items-center gap-2">
@@ -11,7 +11,7 @@ Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a caixa. defa
11
11
 
12
12
  ## Controlado
13
13
 
14
- onCheckedChange recebe boolean | 'indeterminate' — compare com true pra guardar um boolean.
14
+ onCheckedChange recebe boolean | 'indeterminate' — compare com true para guardar um boolean.
15
15
 
16
16
  ```tsx preview
17
17
  const [autoReview, setAutoReview] = useState(true)
@@ -30,7 +30,7 @@ render(
30
30
 
31
31
  ## Lista de opções
32
32
 
33
- Várias caixas, um estado: o conjunto marcado é a lista de valores — o padrão pra anexar skills a um agente.
33
+ Várias caixas, um estado: o conjunto marcado é a lista de valores — o padrão para anexar skills a um agente.
34
34
 
35
35
  ```tsx preview col-start
36
36
  const [skills, setSkills] = useState(['clean-code', 'test'])
@@ -65,11 +65,11 @@ disabled esmaece a caixa e o rótulo em par (peer-disabled no Label) — marcado
65
65
  </div>
66
66
  ```
67
67
 
68
- ## Props
68
+ ## Propriedades de Checkbox
69
69
 
70
- | Prop | Tipo | Default | Descrição |
70
+ | Propriedade | Tipo | Padrão | Descrição |
71
71
  |---|---|---|---|
72
72
  | `checked` | `boolean \| 'indeterminate'` | | O estado, no modo controlado — parear com onCheckedChange. |
73
- | `onCheckedChange` | `(checked: boolean \| 'indeterminate') => void` | | Chamado a cada alternância. Pra guardar um boolean, compare com true. |
73
+ | `onCheckedChange` | `(checked: boolean \| 'indeterminate') => void` | | Chamado a cada alternância. Para guardar um boolean, compare com true. |
74
74
  | `defaultChecked` | `boolean` | `false` | Estado inicial no modo não controlado. |
75
75
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia — o Label em par esmaece junto (peer-disabled). |
@@ -5,18 +5,39 @@ title: CLI opus
5
5
  # CLI opus
6
6
 
7
7
  O Opus traz um CLI que cobre o ciclo: faz o bootstrap, gera artefatos a partir das declarações,
8
- valida as convenções e expõe o estado vivo pros agentes via MCP.
8
+ valida as convenções e expõe o estado vivo para os agentes via MCP. `opus --help` lista os
9
+ comandos e `opus <comando> --help` detalha cada um.
9
10
 
10
11
  ## Gates
11
12
 
12
- > Use o check no CI e antes de entregar uma mudança. Ele informa quais contratos precisam de
13
- > ajuste e encerra com sucesso quando não encontra violações.
13
+ > Use os gates no CI e antes de entregar uma mudança. Cada um informa o que precisa de ajuste e
14
+ > encerra com sucesso (exit 0) quando não encontra violação.
14
15
 
15
16
  ```bash
16
- opus check src # valida as convenções das actions (exit ≠ 0 se violar)
17
- opus db check # drift entidade banco (read-only)
18
- opus db migrate # aplica o schema idempotente + drift-check na sequência
19
- opus seed check # valida bindings, dependências, ciclos e comandos paralelos
17
+ opus check src # convenções das actions e da UI (exit ≠ 0 se violar)
18
+ opus copy --check # inventário de copy ausente ou desatualizado
19
+ opus db check # drift entidade banco (read-only)
20
+ opus seed check # bindings, dependências, ciclos e scripts paralelos de seed
21
+ ```
22
+
23
+ `opus check` lê o source sem executar nada e aplica nove regras: cinco sobre as actions
24
+ (`action-name`, `kind`, `field-order`, `export`, `requires-sem-authorize`) e quatro sobre a UI
25
+ (`ui-structure`, `ui-semantic-api`, `removed-ui-token`, `unpaired-ui-surface`). Um projeto
26
+ marcado com `opus.json` e ainda sem actions passa vacuamente; sem o marcador, zero actions
27
+ falha, porque um gate vazio não é aprovação. `opus check --help` descreve cada regra.
28
+
29
+ ### Hook de pré-push
30
+
31
+ O hook Git que `opus setup` instala roda, antes de cada push: `opus copy --check`; depois
32
+ `opus pre-push materialization` na raiz, para confirmar que os artefatos Opus materializados
33
+ (skills, hooks, instruções) correspondem à versão adotada; e `opus check` em cada app com
34
+ `opus.json`. Qualquer um com exit ≠ 0 bloqueia o push. Os mesmos comandos podem ser executados à
35
+ mão para antecipar o resultado:
36
+
37
+ ```bash
38
+ opus pre-push # o mesmo opus check no diretório atual
39
+ opus pre-push apps/portal # o check de um app específico
40
+ opus pre-push materialization # só a freshness dos artefatos materializados
20
41
  ```
21
42
 
22
43
  ## Seeds de desenvolvimento e teste
@@ -31,43 +52,74 @@ opus seed apply customers.scenarios --profile smoke --scope local
31
52
  opus seed verify customers.scenarios --profile smoke --scope local
32
53
  ```
33
54
 
34
- `apply` converge quando repetido; não reset ou truncate no contrato. A skill
35
- `$create-opus-seed` estrutura um novo dataset, e `$apply-opus-seed` opera um seed registrado pela
36
- mesma CLI.
55
+ `--profile` escolhe o perfil (default: o `defaultProfile` do seed) e `--scope` declara o escopo
56
+ dos dados (a variável `OPUS_SEED_SCOPE` é a alternativa). `--json` devolve o resultado
57
+ estruturado, inclusive em caso de erro. `apply` converge quando repetido; não há reset ou
58
+ truncate no contrato. A skill `$create-opus-seed` estrutura um novo dataset, e
59
+ `$apply-opus-seed` opera um seed registrado pela mesma CLI.
37
60
 
38
61
  ## Geração e introspecção
39
62
 
40
63
  > As declarações (`description` de entidades/actions) são a fonte; o `gen` as projeta. O manifest
41
- > é um lockfile commitado diff de manifest é ouro pra review.
64
+ > é um lockfile versionado. A diferença do manifest torna a revisão objetiva.
42
65
 
43
66
  ```bash
44
- opus gen # manifest / openapi / docs / stubs a partir do opus.config.ts
45
- opus introspect # modelo da estrutura (actions/reactions/schedules + wiring)
67
+ opus gen # manifest / openapi / docs / stubs a partir do opus.config.ts
68
+ opus gen --config ./apps/api/opus.config.ts # config fora do diretório atual
69
+ opus gen --output ./custom/gen # pasta de saída (default: a do config, ou ./.gen)
70
+ opus copy # inventário semântico de copy dos contratos
71
+ opus introspect # modelo da estrutura (actions/reactions/schedules + wiring)
46
72
  opus introspect --json
47
73
  ```
48
74
 
49
- ## Bootstrap e templates
75
+ `opus copy` projeta os textos de `defineAction`/`defineContract` no inventário que a política de
76
+ copy da `@softize/base` valida. O caminho vem de `base.json` (`copy.inventory`; default
77
+ `.base/copy-inventory.json` na raiz Git), a escrita é atômica e o arquivo gerado deve ser
78
+ versionado. `--check` compara sem escrever e falha quando o inventário está ausente,
79
+ desatualizado ou contém copy dinâmica não declarada.
80
+
81
+ `--config` vale para `gen`, `db` e `seed` e sempre aponta para um caminho dentro do projeto. O
82
+ `gen` aceita `--force` por compatibilidade, mas a flag não altera nada: a saída mora em um
83
+ diretório dedicado e é sempre sobrescrita.
84
+
85
+ ## Banco
86
+
87
+ > Os comandos `db` carregam o `opus.config.ts` e abrem conexão; por isso rodam num runner isolado
88
+ > via `tsx`. O padrão é um schema idempotente: um script SQL evolutivo re-rodável, não migrations
89
+ > versionadas.
90
+
91
+ ```bash
92
+ opus db check # compara o schema do banco com as entidades (read-only)
93
+ opus db migrate # aplica o schema idempotente e roda o drift-check na sequência
94
+ opus db scaffold # rascunho kysely a partir do diff, como referência para escrever o SQL
95
+ ```
96
+
97
+ `db scaffold` gera um rascunho para revisão à mão; a verdade continua sendo o script. `db migrate
98
+ down` está aposentado e encerra com erro: sem histórico de migrations não há o que reverter —
99
+ rollback é editar o schema e rodar `opus db migrate` de novo. O `opus.config.ts` precisa expor a
100
+ factory lazy `database`, as entidades (ou domínios) e, opcionalmente, `schema` e `migrations`;
101
+ `opus db --help` detalha.
102
+
103
+ ## Bootstrap
50
104
 
51
105
  > `create` scaffolda um app novo com os pré-requisitos plugados; `setup` é per-app
52
- > (idempotente, nunca sobrescreve o seu); `add` copia um template do catálogo empacotado.
106
+ > (idempotente, nunca sobrescreve o seu).
53
107
 
54
108
  ```bash
55
- opus create meu-app # app canônico do zero: protocolo + UI + preview + automação
109
+ opus create meu-app # app canônico do zero: protocolo + UI + preview + automação
56
110
  opus create meu-cliente --monorepo # a RAIZ de um workspace (apps/* + packages/*)
57
- opus create apps/portal # dentro de um workspace: só o app (modo detectado)
58
- opus setup # grava opus.json e materializa a camada específica do SDK
59
- opus list # lista os templates disponíveis
60
- opus add action-form # copia um template do catálogo pro projeto
111
+ opus create apps/portal # dentro de um workspace: só o app (modo detectado)
112
+ opus setup # grava opus.json e materializa a camada específica do SDK
61
113
  ```
62
114
 
63
115
  O esqueleto do `create` versiona com o Opus (sai do mesmo pacote que o SDK que ele
64
116
  configura) e nasce com os gates verdes: domínio-exemplo canônico, teste, manifest e o dev
65
- server pronto pro preview do Maestro. O método geral, a memória e a revisão vêm da Base
117
+ server pronto para o preview do Maestro. O método geral, a memória e a revisão vêm da Base
66
118
  depois de `pnpm run setup`. Dois modos, por detecção:
67
119
  repo standalone (template inteiro) ou **app em monorepo** (dentro de um workspace pnpm:
68
120
  só os arquivos do app; o que a raiz precisa ter vira aviso, sem clobber).
69
121
 
70
- ## MCP — estado vivo pros agentes
122
+ ## MCP — estado vivo para os agentes
71
123
 
72
124
  > O server MCP expõe introspecção, check e scaffold de action. É como um agente lê a estrutura e cria
73
125
  > action no formato canônico sem decorar convenção.
@@ -1,4 +1,4 @@
1
- ## Básico
1
+ ## Seção recolhível
2
2
 
3
3
  CollapsibleTrigger alterna o CollapsibleContent — o Trigger já é o <button>. defaultOpen deixa o estado com o componente.
4
4
 
@@ -18,7 +18,7 @@ CollapsibleTrigger alterna o CollapsibleContent — o Trigger já é o <button>.
18
18
 
19
19
  ## Controlado
20
20
 
21
- open + onOpenChange põem o estado nas suas mãos — dá pra refletir no gatilho (aqui o chevron gira) ou guardar a preferência.
21
+ open + onOpenChange põem o estado nas suas mãos — dá para refletir no gatilho (aqui o chevron gira) ou guardar a preferência.
22
22
 
23
23
  ```tsx preview col
24
24
  const [open, setOpen] = useState(false)
@@ -54,11 +54,11 @@ disabled no Collapsible trava o gatilho — a seção fica fixa no estado atual
54
54
  </Collapsible>
55
55
  ```
56
56
 
57
- ## Props
57
+ ## Propriedades de Collapsible
58
58
 
59
- | Prop | Tipo | Default | Descrição |
59
+ | Propriedade | Tipo | Padrão | Descrição |
60
60
  |---|---|---|---|
61
- | `defaultOpen (Collapsible)` | `boolean` | `false` | Estado inicial no modo não controlado. |
62
- | `open (Collapsible)` | `boolean` | | Estado no modo controlado pareie com onOpenChange. |
63
- | `onOpenChange (Collapsible)` | `(open: boolean) => void` | | Chamado a cada abertura ou fechamento. |
64
- | `disabled (Collapsible)` | `boolean` | `false` | Trava o gatilho a seção fica presa no estado atual. |
61
+ | `defaultOpen` | `boolean` | `false` | Estado inicial no modo não controlado. |
62
+ | `open` | `boolean` | | Estado no modo controlado. Use com `onOpenChange`. |
63
+ | `onOpenChange` | `(open: boolean) => void` | | Chamado a cada abertura ou fechamento. |
64
+ | `disabled` | `boolean` | `false` | Bloqueia o gatilho e mantém a seção no estado atual. |
@@ -1,6 +1,7 @@
1
1
  ## Lista filtrável inline
2
2
 
3
- Digite pra filtrar navegação por teclado, grupos e CommandEmpty de graça (cmdk). É a base do Select buscável; pra escolha em form, use o Select.
3
+ Digite para filtrar uma coleção com navegação por teclado, grupos e estado vazio. Command é a base
4
+ do Select pesquisável; para uma escolha em formulário, use Select.
4
5
 
5
6
  ```tsx preview
6
7
  <Command className="max-w-sm rounded-lg border border-border">
@@ -22,7 +23,7 @@ Digite pra filtrar — navegação por teclado, grupos e CommandEmpty de graça
22
23
 
23
24
  ## Palette modal (CommandDialog)
24
25
 
25
- O Command embrulhado num Dialog, com header sr-only pra a11y. O atalho ⌘K (keydown no app) só troca o open — o conteúdo é o mesmo do inline.
26
+ O Command embrulhado em um Dialog, com header sr-only para a11y. O atalho ⌘K (keydown no app) só troca o open — o conteúdo é o mesmo do inline.
26
27
 
27
28
  ```tsx preview
28
29
  const [open, setOpen] = useState(false)
@@ -46,11 +47,18 @@ render(
46
47
  )
47
48
  ```
48
49
 
49
- ## Props
50
+ ## Propriedades de CommandDialog
50
51
 
51
- | Prop | Tipo | Default | Descrição |
52
+ | Propriedade | Tipo | Padrão | Descrição |
52
53
  |---|---|---|---|
53
- | `CommandDialog.open / onOpenChange` | `boolean / (open: boolean) => void` | | Controle do modal ligue ao atalho de teclado do app. |
54
- | `CommandDialog.title / description` | `string` | `'Comandos' / 'Busque um comando pra executar.'` | Texto sr-only do header (a11y do Dialog) — não aparece na tela. |
55
- | `CommandDialog.showCloseButton` | `boolean` | `true` | Mostra o X do Dialog desligue se o Esc/clique fora bastarem. |
56
- | `CommandItem.onSelect` | `(value: string) => void` | | Dispara ao escolher (Enter ou clique) feche o palette aqui. |
54
+ | `open` | `boolean` | | Estado do modal no modo controlado. |
55
+ | `onOpenChange` | `(open: boolean) => void` | | Atualiza o estado do modal; pode ser conectado ao atalho do aplicativo. |
56
+ | `title` | `string` | `'Comandos'` | Nome acessível do diálogo, disponível para leitura assistiva. |
57
+ | `description` | `string` | `'Busque um comando para executar.'` | Descrição acessível do diálogo. |
58
+ | `showCloseButton` | `boolean` | `true` | Exibe o botão de fechamento. |
59
+
60
+ ## Propriedades de CommandItem
61
+
62
+ | Propriedade | Tipo | Padrão | Descrição |
63
+ |---|---|---|---|
64
+ | `onSelect` | `(value: string) => void` | | Chamado ao selecionar o item por clique ou teclado. |
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Envio de texto
2
2
 
3
- A caixa de escrever da casa: textarea numa pílula elevada (`rounded-xl` + `border` + `shadow-sm`), **Enter** envia / **Shift+Enter** quebra linha, enviar dentro. É o composer do [Chat](/components/chat) extraído — use SOZINHO quando há entrada de texto mas não um chat (ex.: criar uma sessão). Controlado: o dono do texto é você. Os callbacks opcionais `onHistoryPrevious` e `onHistoryNext` permitem que esse dono consuma **↑/↓**; sem eles, as setas mantêm o comportamento nativo da textarea.
3
+ A caixa de escrever da casa: textarea em uma pílula elevada (`rounded-xl` + `border` + `shadow-sm`), **Enter** envia / **Shift+Enter** quebra linha, enviar dentro. É o composer do [Chat](/components/chat) extraído — use sozinho quando há entrada de texto mas não um chat (ex.: criar uma sessão). Controlado: o dono do texto é você. Os callbacks opcionais `onHistoryPrevious` e `onHistoryNext` permitem que esse dono consuma **↑/↓**; sem eles, as setas mantêm o comportamento nativo da textarea.
4
4
 
5
5
  ```tsx preview col
6
6
  const [text, setText] = React.useState('')
@@ -48,3 +48,18 @@ render(
48
48
  />,
49
49
  )
50
50
  ```
51
+
52
+ ## Propriedades de Composer
53
+
54
+ | Propriedade | Tipo | Padrão | Descrição |
55
+ |---|---|---|---|
56
+ | `value` | `string` | | Texto controlado; o dono do estado é quem compõe. |
57
+ | `onChange` | `(value: string) => void` | | Recebe cada alteração do texto. |
58
+ | `onSubmit` | `() => void` | | Enter (sem Shift) ou o botão enviar; só dispara quando dá para enviar. |
59
+ | `onHistoryPrevious` / `onHistoryNext` | `() => boolean` | | Navegação por ↑/↓ no histórico do dono; retorne `true` quando a tecla foi consumida. |
60
+ | `busy` | `boolean` | `false` | Trava o composer enquanto o turno corre; o enviar vira spinner. |
61
+ | `submitDisabled` | `boolean` | `false` | Gate extra de envio além de vazio e `busy` (ex.: falta escolher o app). |
62
+ | `placeholder` | `string` | `'Escreva uma mensagem…'` | Texto de orientação do campo. |
63
+ | `rows` | `number` | `1` | Linhas iniciais do textarea; ele cresce com o conteúdo. |
64
+ | `autoFocus` | `boolean` | | Foca o campo ao montar. |
65
+ | `actions` | `ReactNode` | | Controles discretos à esquerda do enviar; presente, o composer vira duas linhas. |
@@ -13,7 +13,7 @@ render(
13
13
  description="Sessões com acesso à sua conta."
14
14
  actions={<Button variant="outline">Encerrar outras sessões</Button>}
15
15
  >
16
- <div className="rounded-lg border border-border p-4">MacBook Pro · ativo agora</div>
16
+ <div className="rounded-lg border border-border p-4">MacBook Para o · ativo agora</div>
17
17
  </Content>,
18
18
  )
19
19
  ```
@@ -34,7 +34,7 @@ render(
34
34
  <ContentActions><Button variant="outline">Atualizar</Button></ContentActions>
35
35
  </ContentHeader>
36
36
  <ContentBody>
37
- <div className="rounded-lg border border-border p-4">MacBook Pro · ativo agora</div>
37
+ <div className="rounded-lg border border-border p-4">MacBook Para o · ativo agora</div>
38
38
  </ContentBody>
39
39
  </Content>,
40
40
  )
@@ -42,3 +42,18 @@ render(
42
42
 
43
43
  As duas formas geram os mesmos elementos, estilos e `data-slot`. `opus check` reprova slots fora
44
44
  do pai correto, filhos estruturais indiretos e a mistura de shorthand com composição explícita.
45
+
46
+ ## Propriedades de Content
47
+
48
+ | Propriedade | Tipo | Padrão | Descrição |
49
+ |---|---|---|---|
50
+ | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
51
+ | `meta` | `ReactNode` | | Forma curta: complemento ao lado do título, como uma contagem. |
52
+ | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
53
+ | `actions` | `ReactNode` | | Forma curta: ações alinhadas à direita do header. |
54
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | herdado | Nível semântico do heading, independente do destaque visual. |
55
+ | `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual; `page` permanece só por compatibilidade da série 12. |
56
+
57
+ Na composição explícita, `ContentHeader` recebe `ContentTitle`, `ContentMeta`, `ContentDescription` e
58
+ `ContentActions`, e `ContentBody` recebe o conteúdo; nenhum desses slots aceita `title` ou `level`
59
+ próprios — a hierarquia é declarada em `Content`.
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Copiar por ícone
2
2
 
3
- Sem filhos, é um botão-ícone: copia `value` e o ícone vira um check por ~1.5s. Bom pra toolbar ou célula estreita, ao lado de um ID/token/slug.
3
+ Sem filhos, é um botão-ícone: copia `value` e o ícone vira um check por ~1.5s. Bom para toolbar ou célula estreita, ao lado de um ID/token/slug.
4
4
 
5
5
  ```tsx preview
6
6
  <Copyable value="opus_sk_1a2b3c4d5e6f" className="text-muted-foreground hover:text-foreground" />
@@ -21,10 +21,19 @@ Com filhos, o valor visível fica à esquerda e o ícone à direita — clicar n
21
21
 
22
22
  ## Duração do feedback
23
23
 
24
- `feedbackMs` ajusta quanto o check dura (default 1500). Some no-op silencioso se o clipboard não existir (contexto inseguro/SSR).
24
+ `feedbackMs` ajusta por quanto tempo a confirmação aparece; o padrão é 1500 milissegundos. Se a
25
+ área de transferência não estiver disponível, a ação não produz efeito.
25
26
 
26
27
  ```tsx preview
27
28
  <Copyable value="copiado devagar" feedbackMs={3000} className="text-muted-foreground hover:text-foreground">
28
29
  copiar (3s)
29
30
  </Copyable>
30
31
  ```
32
+
33
+ ## Propriedades de Copyable
34
+
35
+ | Propriedade | Tipo | Padrão | Descrição |
36
+ |---|---|---|---|
37
+ | `value` | `string` | | O texto que vai para a área de transferência no clique. |
38
+ | `feedbackMs` | `number` | `1500` | Duração do estado “copiado”, em milissegundos. |
39
+ | `children` | `ReactNode` | | Rótulo ao lado do ícone; sem ele, o controle é só o ícone com nome acessível. |
@@ -6,7 +6,7 @@ title: Customização
6
6
 
7
7
  Cinco alavancas, do global ao pontual — e um limite de propósito. O caminho previsto é compor
8
8
  e configurar, nunca forkar componente: o que não cabe nas alavancas evolui no Opus (com
9
- divergência declarada), pra valer pra casa toda.
9
+ divergência declarada), para valer para casa toda.
10
10
 
11
11
  ## 1 · Identidade por tokens
12
12
 
@@ -36,7 +36,7 @@ de 16, sem transformar esse valor em uma regra da biblioteca.
36
36
  ## 2 · className em tudo
37
37
 
38
38
  > Todo componente termina em `cn(base, className)` com tailwind-merge: o utilitário do consumidor
39
- > vence o conflito. Pra layout local (largura, margem, grid) — não pra repintar o visual da casa.
39
+ > vence o conflito. Para layout local (largura, margem, grid) — não para repintar o visual da casa.
40
40
 
41
41
  ```tsx
42
42
  <Button className="w-full">Continuar</Button>
@@ -47,7 +47,7 @@ de 16, sem transformar esse valor em uma regra da biblioteca.
47
47
  ## 3 · Recomposição estrutural
48
48
 
49
49
  > Os componentes são explodidos em slots. `asChild` (Radix Slot) renderiza como outro elemento
50
- > mantendo estilo e comportamento; os `*Variants` aplicam a cara da casa num elemento arbitrário.
50
+ > mantendo estilo e comportamento; os `*Variants` aplicam a cara da casa em um elemento arbitrário.
51
51
 
52
52
  ```tsx preview
53
53
  <Button asChild variant="outline">
@@ -65,7 +65,7 @@ de 16, sem transformar esse valor em uma regra da biblioteca.
65
65
  // asChild: o filho VIRA o botão (sem forkar estilo).
66
66
  <Button asChild><a href="/docs">Abrir documentação</a></Button>
67
67
 
68
- // buttonVariants: a cara da casa num elemento qualquer.
68
+ // buttonVariants: a cara da casa em um elemento qualquer.
69
69
  <a className={buttonVariants({ variant: 'outline' })}>Link estilizado</a>
70
70
  ```
71
71
 
@@ -115,4 +115,4 @@ const [open, setOpen] = useState(false)
115
115
 
116
116
  Se uma necessidade real não cabe nas alavancas (tokens · className · slots/asChild · props ·
117
117
  contrato), o movimento não é dialeto local: é evoluir o componente **no Opus**, com a divergência
118
- declarada (skill `build-opus-ui`) — assim a mudança vale pra casa toda, e esta doc passa a mostrá-la.
118
+ declarada (skill `build-opus-ui`) — assim a mudança vale para casa toda, e esta doc passa a mostrá-la.
@@ -16,9 +16,9 @@ No seu projeto, uma linha por apontamento em `.opus/issues.jsonl` na raiz do rep
16
16
 
17
17
  ## Não trave esperando
18
18
 
19
- O ponto do ciclo é **não bloquear a entrega**. Bateu num gap ou num bug do Opus:
19
+ O ponto do ciclo é **não bloquear a entrega**. Bateu em um gap ou em um bug do Opus:
20
20
 
21
- 1. **Contorne local** — componha um wrapper no seu projeto. O Opus entrega _source_, então dá pra embrulhar qualquer superfície dele. Nunca edite `node_modules` (some no próximo install).
21
+ 1. **Contorne local** — componha um wrapper no seu projeto. O Opus entrega _source_, então dá para embrulhar qualquer superfície dele. Nunca edite `node_modules` (some no próximo install).
22
22
  2. **Entregue** a feature com o workaround.
23
23
  3. **Aponte** no `.opus/issues.jsonl` e siga em frente.
24
24
 
@@ -28,7 +28,7 @@ O "depois" — o conserto no Opus — corre em paralelo. Ele não segura o seu t
28
28
 
29
29
  O apontamento é colhido e abre uma **Issue no repositório do Opus**, onde a triagem acontece (deduplicada — re-apontar o mesmo é idempotente):
30
30
 
31
- - **Enhancement** aceito (com reincidência) → implementado no Opus → sai num _bump_ → seu projeto atualiza o pin (`opus.json`) e troca o workaround pelo import.
31
+ - **Enhancement** aceito (com reincidência) → implementado no Opus → sai em um _bump_ → seu projeto atualiza o pin (`opus.json`) e troca o workaround pelo import.
32
32
  - **Bug** → vira _fix_ + entrada no `CHANGELOG` → no _bump_, o workaround sai.
33
33
 
34
34
  A régua e a decisão ficam com quem mantém o Opus — hoje, a **Softize**. O registro curado das promoções vive no `PROMOTED.md` do pacote.
@@ -1,9 +1,9 @@
1
1
  ## Estados
2
2
 
3
- Um lugar pro erro/carregando/vazio/conteúdo de uma carga. Carregando = Spinner centralizado;
4
- vazio = texto em uma moldura sólida no modo bloco; erro = aviso calmo (a mensagem técnica não vai
5
- pra tela). É o "antes" do conteúdo
6
- pro "depois" (ação em andamento), use o busy do Button.
3
+ Use `DataState` para apresentar carregamento, erro, vazio e conteúdo de uma mesma consulta. O
4
+ carregamento usa `Spinner`; o vazio preserva uma moldura sólida; e o erro apresenta uma mensagem
5
+ segura, sem expor detalhes técnicos. Para uma ação em andamento depois do clique, use `busy` em
6
+ `Button`.
7
7
 
8
8
  ```tsx preview col
9
9
  <div className="w-full space-y-3">
@@ -19,12 +19,11 @@ pro "depois" (ação em andamento), use o busy do Button.
19
19
  </div>
20
20
  ```
21
21
 
22
- ## Em tabela (colSpan)
22
+ ## Dentro de uma tabela
23
23
 
24
- Em lista ou tabela já emoldurada, passe colSpan: o estado vira UMA linha de largura cheia
25
- (`<tr><td colSpan>`) que cabe direto no `<tbody>`; o conteúdo são as `<tr>` dos itens. A tabela
26
- continua dona da borda, sem uma segunda moldura no vazio. Para uma região disponível para criação
27
- ou vínculo, com título, descrição ou ação, use `Empty`, cuja moldura é tracejada.
24
+ Em uma tabela já emoldurada, passe `colSpan` para ocupar uma linha inteira dentro de `<tbody>`. A
25
+ tabela continua responsável pela borda, evitando uma segunda moldura no estado vazio. Para uma
26
+ região disponível para criação ou vínculo, use `Empty`.
28
27
 
29
28
  ```tsx preview col
30
29
  <table className="w-full overflow-hidden rounded-lg border border-border text-sm">
@@ -38,13 +37,13 @@ ou vínculo, com título, descrição ou ação, use `Empty`, cuja moldura é tr
38
37
  </table>
39
38
  ```
40
39
 
41
- ## Props
40
+ ## Propriedades de DataState
42
41
 
43
- | Prop | Tipo | Default | Descrição |
42
+ | Propriedade | Tipo | Padrão | Descrição |
44
43
  |---|---|---|---|
45
44
  | `loading` | `boolean` | | Carregando (antes do conteúdo) — mostra o Spinner centralizado. |
46
45
  | `empty` | `boolean` | | Sem itens — mostra o emptyText. |
47
46
  | `emptyText` | `string` | | Texto do vazio (pt-BR, ex.: "Nenhum papel."). |
48
- | `error` | `{ message?: string } \| null` | | Erro da carga — aviso calmo. A mensagem técnica NÃO vai pra tela (use errorText). |
47
+ | `error` | `{ message?: string } \| null` | | Erro da carga — aviso calmo. A mensagem técnica não vai para tela (use errorText). |
49
48
  | `errorText` | `string` | `'Não foi possível carregar.'` | Aviso de erro, orientado ao usuário. |
50
49
  | `colSpan` | `number` | | Em tabela: renderiza o estado como `<tr><td colSpan>` (cabe direto no tbody). |