@softize/opus 19.0.0 → 20.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 (142) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/bin/cli.mjs +5 -0
  3. package/bin/lib/check.mjs +198 -10
  4. package/bin/lib/copy.mjs +29 -0
  5. package/bin/lib/mcp.mjs +1 -1
  6. package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +5 -0
  7. package/docs/adr/0024-fill-height-propagates-by-context.md +118 -0
  8. package/docs/data-products.md +15 -9
  9. package/docs/protocol.md +3 -4
  10. package/docs/releasing.md +2 -2
  11. package/package.json +2 -2
  12. package/registry/skills/create-opus-action/scripts/scaffold.mjs +2 -1
  13. package/registry/templates/app/package.json +1 -1
  14. package/src/core/runtime.ts +96 -8
  15. package/src/core/types.ts +5 -2
  16. package/src/ui/components/patterns/action-form-card.tsx +11 -1
  17. package/src/ui/components/patterns/content-header.tsx +15 -3
  18. package/src/ui/components/patterns/fill-region.ts +150 -0
  19. package/src/ui/components/patterns/list.tsx +89 -78
  20. package/src/ui/components/patterns/page.tsx +20 -4
  21. package/src/ui/components/patterns/presentation.tsx +52 -37
  22. package/src/ui/components/patterns/split.tsx +44 -4
  23. package/src/ui/components/patterns/surface-anatomy.ts +35 -8
  24. package/src/ui/components/patterns/trigger.tsx +12 -2
  25. package/src/ui/components/primitives/alert.tsx +9 -1
  26. package/src/ui/components/primitives/avatar.tsx +7 -3
  27. package/src/ui/components/primitives/carousel.tsx +34 -5
  28. package/src/ui/components/primitives/checkbox.tsx +11 -3
  29. package/src/ui/components/primitives/command.tsx +2 -1
  30. package/src/ui/components/primitives/copyable.tsx +120 -10
  31. package/src/ui/components/primitives/dialog.tsx +41 -10
  32. package/src/ui/components/primitives/drawer.tsx +9 -1
  33. package/src/ui/components/primitives/empty.tsx +1 -1
  34. package/src/ui/components/primitives/icon-picker.tsx +6 -2
  35. package/src/ui/components/primitives/icon-tile.tsx +7 -0
  36. package/src/ui/components/primitives/input-group.tsx +9 -2
  37. package/src/ui/components/primitives/input-otp.tsx +1 -1
  38. package/src/ui/components/primitives/kbd.tsx +1 -1
  39. package/src/ui/components/primitives/label.tsx +3 -0
  40. package/src/ui/components/primitives/menu.tsx +5 -0
  41. package/src/ui/components/primitives/popover.tsx +1 -1
  42. package/src/ui/components/primitives/progress.tsx +9 -1
  43. package/src/ui/components/primitives/slider.tsx +62 -11
  44. package/src/ui/components/primitives/truncate.tsx +10 -1
  45. package/src/ui/docs/content/accordion.md +74 -27
  46. package/src/ui/docs/content/action-form-card.md +24 -15
  47. package/src/ui/docs/content/action-form-dialog.md +17 -7
  48. package/src/ui/docs/content/action-form.md +92 -77
  49. package/src/ui/docs/content/action-list-dialog.md +75 -38
  50. package/src/ui/docs/content/action-list.md +134 -52
  51. package/src/ui/docs/content/action-trigger.md +27 -10
  52. package/src/ui/docs/content/action-view.md +14 -14
  53. package/src/ui/docs/content/actions.md +161 -66
  54. package/src/ui/docs/content/ai.md +43 -44
  55. package/src/ui/docs/content/alert.md +83 -29
  56. package/src/ui/docs/content/ask.md +51 -26
  57. package/src/ui/docs/content/aspect-ratio.md +22 -24
  58. package/src/ui/docs/content/audit.md +23 -19
  59. package/src/ui/docs/content/auth.md +38 -19
  60. package/src/ui/docs/content/avatar.md +54 -5
  61. package/src/ui/docs/content/badge.md +29 -9
  62. package/src/ui/docs/content/breadcrumb.md +21 -8
  63. package/src/ui/docs/content/button.md +73 -43
  64. package/src/ui/docs/content/calendar.md +134 -26
  65. package/src/ui/docs/content/card.md +41 -15
  66. package/src/ui/docs/content/carousel.md +37 -6
  67. package/src/ui/docs/content/chat.md +118 -37
  68. package/src/ui/docs/content/checkbox.md +73 -7
  69. package/src/ui/docs/content/cli.md +94 -55
  70. package/src/ui/docs/content/collapsible.md +43 -19
  71. package/src/ui/docs/content/command.md +30 -8
  72. package/src/ui/docs/content/composer.md +23 -8
  73. package/src/ui/docs/content/content.md +31 -7
  74. package/src/ui/docs/content/copyable.md +39 -8
  75. package/src/ui/docs/content/customization.md +55 -46
  76. package/src/ui/docs/content/cycle.md +33 -18
  77. package/src/ui/docs/content/data-products.md +115 -0
  78. package/src/ui/docs/content/data-state.md +20 -6
  79. package/src/ui/docs/content/data.md +20 -19
  80. package/src/ui/docs/content/detail.md +12 -5
  81. package/src/ui/docs/content/dialog.md +107 -24
  82. package/src/ui/docs/content/dictionary-value.md +4 -4
  83. package/src/ui/docs/content/dock.md +54 -19
  84. package/src/ui/docs/content/dot.md +35 -5
  85. package/src/ui/docs/content/drawer.md +63 -19
  86. package/src/ui/docs/content/empty-value.md +20 -6
  87. package/src/ui/docs/content/empty.md +24 -3
  88. package/src/ui/docs/content/events.md +76 -16
  89. package/src/ui/docs/content/executions.md +9 -9
  90. package/src/ui/docs/content/field.md +21 -6
  91. package/src/ui/docs/content/getting-started.md +44 -34
  92. package/src/ui/docs/content/icon-picker.md +19 -13
  93. package/src/ui/docs/content/icon-tile.md +28 -5
  94. package/src/ui/docs/content/input-otp.md +58 -7
  95. package/src/ui/docs/content/input.md +22 -3
  96. package/src/ui/docs/content/item.md +53 -6
  97. package/src/ui/docs/content/kbd.md +5 -1
  98. package/src/ui/docs/content/label.md +13 -4
  99. package/src/ui/docs/content/log.md +5 -5
  100. package/src/ui/docs/content/markdown.md +5 -4
  101. package/src/ui/docs/content/mcp.md +49 -23
  102. package/src/ui/docs/content/menu.md +95 -10
  103. package/src/ui/docs/content/metric-card.md +12 -4
  104. package/src/ui/docs/content/observability.md +10 -9
  105. package/src/ui/docs/content/page.md +118 -12
  106. package/src/ui/docs/content/pagination.md +13 -5
  107. package/src/ui/docs/content/pane.md +55 -5
  108. package/src/ui/docs/content/popover.md +42 -5
  109. package/src/ui/docs/content/presentation.md +91 -47
  110. package/src/ui/docs/content/progress.md +27 -14
  111. package/src/ui/docs/content/queue.md +39 -21
  112. package/src/ui/docs/content/radio-group.md +26 -4
  113. package/src/ui/docs/content/router.md +29 -10
  114. package/src/ui/docs/content/runtime.md +90 -54
  115. package/src/ui/docs/content/scheduler.md +53 -21
  116. package/src/ui/docs/content/scroll-area.md +42 -35
  117. package/src/ui/docs/content/select.md +78 -33
  118. package/src/ui/docs/content/semantic-context.md +21 -2
  119. package/src/ui/docs/content/separator.md +15 -9
  120. package/src/ui/docs/content/sidebar.md +3 -2
  121. package/src/ui/docs/content/skeleton.md +6 -1
  122. package/src/ui/docs/content/slider.md +37 -9
  123. package/src/ui/docs/content/spinner.md +4 -3
  124. package/src/ui/docs/content/split.md +19 -0
  125. package/src/ui/docs/content/storage.md +8 -9
  126. package/src/ui/docs/content/switch.md +10 -7
  127. package/src/ui/docs/content/table.md +46 -8
  128. package/src/ui/docs/content/tabs.md +14 -4
  129. package/src/ui/docs/content/testing.md +76 -31
  130. package/src/ui/docs/content/textarea.md +5 -4
  131. package/src/ui/docs/content/toast.md +48 -7
  132. package/src/ui/docs/content/toggle.md +3 -3
  133. package/src/ui/docs/content/tokens.md +15 -26
  134. package/src/ui/docs/content/tooltip.md +18 -2
  135. package/src/ui/docs/content/truncate.md +36 -6
  136. package/src/ui/docs/content/ui.md +74 -22
  137. package/src/ui/docs/content/upgrading.md +45 -36
  138. package/src/ui/docs/plugin.ts +36 -2
  139. package/src/ui/docs/registry.tsx +6 -0
  140. package/src/ui/drivers/react.tsx +16 -8
  141. package/src/ui/meta.ts +31 -31
  142. package/src/vite/design.ts +16 -4
@@ -1,6 +1,6 @@
1
1
  Use `DetailGroup` para organizar dados somente leitura como pares de rótulo e valor.
2
2
  `DetailField` representa cada par e aceita conteúdo React em `label` e `value`. Para entrada e
3
- validação, use `Field`.
3
+ validação, use [`Field`](/ui/field).
4
4
 
5
5
  ```tsx preview col
6
6
  <DetailGroup columns={2}>
@@ -27,7 +27,8 @@ validação, use `Field`.
27
27
 
28
28
  `null`, `undefined`, string vazia ou só com espaços mostram um travessão; a leitura assistiva
29
29
  recebe “Não informado”. Uma string em `empty` troca esse significado no domínio, enquanto um nó
30
- React substitui a apresentação. `0` e `false` seguem como valores. Ver `EmptyValue`.
30
+ React substitui a apresentação. `0` e `false` seguem como valores. A regra é a mesma de
31
+ [`EmptyValue`](/ui/empty-value).
31
32
 
32
33
  ```tsx preview col
33
34
  <DetailGroup columns={2}>
@@ -64,15 +65,21 @@ começam depois da mesma coluna de rótulo, com largura padrão de `7rem` em gru
64
65
  | Propriedade | Tipo | Padrão | Descrição |
65
66
  |---|---|---|---|
66
67
  | `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica a moldura canônica ao conjunto, com fundo transparente; na orientação horizontal, a coluna de rótulos recebe fundo sutil. |
67
- | `dividers` | `boolean` | `false` | Hairlines somente entre os campos, sem exigir moldura externa. |
68
+ | `dividers` | `boolean` | `false` | Linhas finas somente entre os campos, sem exigir moldura externa. |
68
69
  | `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Número fixo de colunas ou distribuição automática por largura mínima. |
69
70
  | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
70
71
 
72
+ O grupo renderiza uma lista de definições (`<dl>`); os demais atributos, como `className`, vão para
73
+ ela.
74
+
71
75
  ## Propriedades de DetailField
72
76
 
73
77
  | Propriedade | Tipo | Padrão | Descrição |
74
78
  |---|---|---|---|
75
- | `label` | `ReactNode` | | A chave do par. |
76
- | `value` | `ReactNode` | | O valor; `null`, `undefined` e string vazia renderizam a ausência, `0` e `false` seguem como valores. |
79
+ | `label` | `ReactNode` | obrigatório | A chave do par. |
80
+ | `value` | `ReactNode` | obrigatório | O valor; `null`, `undefined` e string vazia renderizam a ausência, `0` e `false` seguem como valores. |
77
81
  | `icon` | `ReactNode` | | Ícone decorativo antes do par chave/valor. |
78
82
  | `empty` | `ReactNode` | `“Não informado”` | Uma string dá significado acessível ao travessão; um nó próprio substitui a apresentação. |
83
+
84
+ Os demais atributos, como `className`, vão para o contêiner do par. `DetailField` não aceita
85
+ `children`: o conteúdo entra por `value`.
@@ -10,7 +10,8 @@ contexto da página. A forma escolhida depende do tipo de interrupção:
10
10
  | Pedir reconhecimento, confirmação binária ou uma string sem montar a superfície. | Use `dialog.alert`, `dialog.confirm` ou `dialog.prompt`. |
11
11
  | Escolher entre vários resultados simples. | Use `dialog.choose`. |
12
12
 
13
- Para conteúdo ancorado e não modal, use `Popover`. Para uma lista de ações, use `Menu`.
13
+ Para conteúdo ancorado e não modal, use [`Popover`](/ui/popover). Para uma lista de ações, use
14
+ [`Menu`](/ui/menu).
14
15
 
15
16
  ## Compor uma tarefa modal
16
17
 
@@ -118,13 +119,13 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
118
119
  <DialogContent>
119
120
  <DialogHeader>
120
121
  <DialogNavigation>
121
- <Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
122
+ <Button variant="ghost" size="icon" aria-label="Voltar para a lista">
122
123
  <ArrowLeft />
123
124
  </Button>
124
125
  </DialogNavigation>
125
126
  <DialogTitle>Evento 4821</DialogTitle>
126
127
  <DialogActions>
127
- <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
128
+ <Button variant="ghost" size="icon" aria-label="Mais ações">
128
129
  <Ellipsis />
129
130
  </Button>
130
131
  </DialogActions>
@@ -136,9 +137,82 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
136
137
  </Dialog>
137
138
  ```
138
139
 
140
+ Voltar e ações do cabeçalho usam `Button` `ghost` no tamanho `icon` (2.25rem), o mesmo que a
141
+ [`Presentation`](/ui/presentation) usa no voltar. O botão de fechar é menor: um `CloseButton` no
142
+ quadrado `icon-sm` (1.75rem) por padrão.
143
+
139
144
  O cabeçalho não recebe descrição: um modal já é a superfície de uma tarefa, e o contexto que ajuda a
140
145
  decidir aparece no começo do corpo, como texto ou `Alert`.
141
146
 
147
+ ## Identificar a tarefa com um ícone
148
+
149
+ Use `DialogMedia` quando um ícone ajuda a reconhecer a tarefa antes da leitura do título. No modo
150
+ padrão, ele abre a linha do cabeçalho com a mesma moldura de [`IconTile`](/ui/icon-tile) das demais
151
+ superfícies. No `mode="alert"`, a moldura cresce e fica centralizada acima do título, porque ali o
152
+ ícone é o principal sinal de reconhecimento da resposta.
153
+
154
+ ```tsx preview
155
+ render(
156
+ <div className="flex flex-wrap gap-3">
157
+ <Dialog>
158
+ <DialogTrigger asChild>
159
+ <Button variant="outline">Compartilhar contrato</Button>
160
+ </DialogTrigger>
161
+ <DialogContent>
162
+ <DialogHeader>
163
+ <DialogMedia>
164
+ <Share2 />
165
+ </DialogMedia>
166
+ <DialogTitle>Compartilhar contrato</DialogTitle>
167
+ </DialogHeader>
168
+ <DialogBody className="space-y-2">
169
+ <Label htmlFor="share-email">E-mail</Label>
170
+ <Input id="share-email" placeholder="nome@empresa.com.br" />
171
+ </DialogBody>
172
+ <DialogFooter>
173
+ <ButtonGroup mode="spaced">
174
+ <DialogClose asChild>
175
+ <Button variant="ghost">Cancelar</Button>
176
+ </DialogClose>
177
+ <Button>Compartilhar</Button>
178
+ </ButtonGroup>
179
+ </DialogFooter>
180
+ </DialogContent>
181
+ </Dialog>
182
+ <Dialog mode="alert">
183
+ <DialogTrigger asChild>
184
+ <Button variant="outline">Revogar acesso</Button>
185
+ </DialogTrigger>
186
+ <DialogContent>
187
+ <DialogHeader>
188
+ <DialogMedia context="danger">
189
+ <ShieldOff />
190
+ </DialogMedia>
191
+ <DialogTitle>Revogar acesso de Marina?</DialogTitle>
192
+ </DialogHeader>
193
+ <DialogBody>
194
+ <p className="text-sm text-muted-foreground">
195
+ Ela deixa de ver o contrato imediatamente.
196
+ </p>
197
+ </DialogBody>
198
+ <DialogFooter>
199
+ <ButtonGroup mode="spaced" distribution="equal">
200
+ <DialogClose initialFocus asChild>
201
+ <Button variant="outline">Cancelar</Button>
202
+ </DialogClose>
203
+ <DialogClose asChild>
204
+ <Button context="danger">Revogar acesso</Button>
205
+ </DialogClose>
206
+ </ButtonGroup>
207
+ </DialogFooter>
208
+ </DialogContent>
209
+ </Dialog>
210
+ </div>,
211
+ );
212
+ ```
213
+
214
+ Na API imperativa, a opção `media` recebe o ícone e o apresenta na mesma moldura do alerta.
215
+
142
216
  ## Pedir uma resposta pela API imperativa
143
217
 
144
218
  Use `dialog.alert`, `dialog.confirm`, `dialog.prompt` e `dialog.choose` quando a resposta couber em
@@ -169,12 +243,13 @@ function Demo() {
169
243
  size="sm"
170
244
  onClick={async () => {
171
245
  const accepted = await dialog.confirm({
172
- title: "Excluir sessão?",
173
- body: "O worktree e o preview desta sessão serão removidos.",
246
+ title: "Excluir rascunho?",
247
+ body: "O rascunho e os comentários dele serão removidos.",
248
+ media: <Trash2 />,
174
249
  action: "Excluir",
175
250
  context: "danger",
176
251
  });
177
- setResult(accepted ? "Sessão excluída." : "Sessão mantida.");
252
+ setResult(accepted ? "Rascunho excluído." : "Rascunho mantido.");
178
253
  }}
179
254
  >
180
255
  Confirmar exclusão
@@ -184,14 +259,14 @@ function Demo() {
184
259
  size="sm"
185
260
  onClick={async () => {
186
261
  const name = await dialog.prompt({
187
- title: "Renomear snapshot",
262
+ title: "Renomear versão",
188
263
  action: "Renomear",
189
264
  placeholder: "Ex.: versão final",
190
265
  });
191
266
  setResult(name === null ? "Nome mantido." : `Novo nome: ${name}`);
192
267
  }}
193
268
  >
194
- Renomear snapshot
269
+ Renomear versão
195
270
  </Button>
196
271
  <Button
197
272
  variant="outline"
@@ -229,7 +304,8 @@ render(<Demo />);
229
304
  `dialog.prompt` devolve `Promise<string | null>` e `dialog.choose` infere a união dos resultados
230
305
  declarados, acrescida de `null`. Fechar ou cancelar resolve a resposta negativa de cada operação,
231
306
  em vez de deixar a promise pendente. No aviso com uma ação, o botão ocupa toda a largura do rodapé;
232
- confirmações e prompts distribuem confirmar e cancelar em duas colunas.
307
+ confirmações e prompts distribuem confirmar e cancelar em duas colunas. O `dialog.choose` usa uma
308
+ superfície mais larga, de `32rem`, para que as ações caibam lado a lado.
233
309
 
234
310
  Em `dialog.choose`, declare pelo menos uma ação e marque exatamente uma ação habilitada com
235
311
  `initialFocus`. Essa ação representa a saída segura. Os valores de `result` precisam ser únicos.
@@ -238,7 +314,7 @@ neutro e variante outline. Defina `context` ou `variant` na própria ação para
238
314
 
239
315
  ### Montar o host
240
316
 
241
- Monte um `DialogHost` no shell do aplicativo, ao lado do `Toaster`:
317
+ Monte um `DialogHost` no shell do aplicativo, ao lado do [`Toaster`](/ui/toast):
242
318
 
243
319
  ```tsx
244
320
  <>
@@ -248,8 +324,8 @@ Monte um `DialogHost` no shell do aplicativo, ao lado do `Toaster`:
248
324
  </>
249
325
  ```
250
326
 
251
- Sem o host, a chamada lança um erro imediatamente. Solicitações concorrentes entram em uma fila e
252
- aparecem uma por vez, preservando a resposta de cada `await`.
327
+ Sem o host, a promise é rejeitada imediatamente com um erro. Solicitações concorrentes entram em
328
+ uma fila e aparecem uma por vez, preservando a resposta de cada `await`.
253
329
 
254
330
  ### Adicionar contexto relevante
255
331
 
@@ -259,21 +335,21 @@ texto, um `Alert` ou uma composição própria:
259
335
 
260
336
  ```tsx
261
337
  const accepted = await dialog.confirm({
262
- title: "Encerrar três sessões?",
338
+ title: "Revogar três acessos?",
263
339
  body: (
264
340
  <Alert
265
341
  context="warning"
266
- description="Os agentes vinculados serão interrompidos."
342
+ description="As pessoas convidadas deixam de ver o contrato imediatamente."
267
343
  />
268
344
  ),
269
- action: "Encerrar sessões",
345
+ action: "Revogar acessos",
270
346
  });
271
347
  ```
272
348
 
273
- Use `ActionTrigger` quando a confirmação já pertencer ao contrato de uma action. Use
274
- `ActionFormDialog` para formulários com validação ou vários campos. `dialog.prompt` atende somente
275
- uma string livre. Componha `Dialog` quando uma ação precisar manter a superfície
276
- aberta para exibir carregamento, validação ou falha antes do fechamento.
349
+ Use [`ActionTrigger`](/ui/action-trigger) quando a confirmação já pertencer ao contrato de uma
350
+ action. Use [`ActionFormDialog`](/ui/action-form-dialog) para formulários com validação ou vários
351
+ campos. `dialog.prompt` atende somente uma string livre. Componha `Dialog` quando uma ação precisar
352
+ manter a superfície aberta para exibir carregamento, validação ou falha antes do fechamento.
277
353
 
278
354
  ## Compor uma resposta personalizada
279
355
 
@@ -282,6 +358,10 @@ com o clique externo. Prefira a API imperativa quando a resposta couber em `aler
282
358
  `prompt` ou `choose`. Componha o componente quando a resposta depender de estado próprio ou de um
283
359
  layout específico.
284
360
 
361
+ O alerta tem `20rem` de largura máxima, suficiente para duas ações lado a lado. Com três ações,
362
+ amplie a superfície com `className="max-w-lg"` em `DialogContent`, a mesma largura que o
363
+ `dialog.choose` usa; sem isso, os rótulos não cabem no rodapé.
364
+
285
365
  ```tsx preview
286
366
  function ResponseDialogDemo() {
287
367
  const [result, setResult] = useState("Nenhuma resposta.");
@@ -292,7 +372,7 @@ function ResponseDialogDemo() {
292
372
  <DialogTrigger asChild>
293
373
  <Button variant="outline">Fechar editor</Button>
294
374
  </DialogTrigger>
295
- <DialogContent>
375
+ <DialogContent className="max-w-lg">
296
376
  <DialogHeader>
297
377
  <DialogTitle>Fechar editor?</DialogTitle>
298
378
  </DialogHeader>
@@ -328,13 +408,16 @@ render(<ResponseDialogDemo />);
328
408
  contexto, variante e tamanho pertencem ao botão. `result` identifica a resposta entregue a
329
409
  `Dialog onResult`. Marque com `initialFocus` a saída segura — normalmente `Cancelar`; em um aviso
330
410
  com uma única ação, marque essa ação. Para uma confirmação destrutiva, use `context="danger"` no
331
- botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Encerrar sessões`.
411
+ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Arquivar contratos`.
332
412
 
333
413
  ## Acessibilidade
334
414
 
335
415
  - `DialogTitle` nomeia a superfície para tecnologias assistivas. Quando um texto conciso do corpo
336
416
  também precisar descrevê-la, relacione seu `id` por `aria-describedby` em `DialogContent`.
337
417
  - O modo padrão permite fechamento externo; `mode="alert"` exige uma resposta explícita.
418
+ - Enquanto uma operação não puder ser interrompida, `closeDisabled` em `DialogContent` impede que o
419
+ botão de fechar, Esc e o clique externo fechem a superfície. As ações que você compõe com
420
+ `DialogClose` continuam ativas; desabilite-as pelo mesmo estado da operação.
338
421
  - O comportamento selecionado por `mode` determina o papel de acessibilidade; `role` não configura
339
422
  o comportamento.
340
423
  - O foco permanece dentro do diálogo aberto e retorna ao gatilho após o fechamento.
@@ -363,10 +446,10 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Ence
363
446
  | Propriedade | Tipo | Padrão | Descrição |
364
447
  | ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------- |
365
448
  | `showCloseButton` | `boolean` | `true` | No modo padrão, inclui a ação de fechamento no header; o modo de alerta exige uma resposta identificável. |
366
- | `closeDisabled` | `boolean` | `false` | Mantém a ação visível e impede o fechamento enquanto a tarefa está bloqueada. |
449
+ | `closeDisabled` | `boolean` | `false` | Mantém o botão de fechar visível e desabilitado e impede que Esc e o clique externo fechem a superfície. Handlers como `onEscapeKeyDown` e `onPointerDownOutside` continuam sendo chamados antes do bloqueio. |
367
450
  | `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
368
451
  | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. Ignorado em `mode="alert"`. |
369
- | `className` | `string` | | Ajusta a superfície. |
452
+ | `className` | `string` | | Ajusta a superfície. A largura máxima é `32rem` no modo padrão e `20rem` no alerta; amplie o alerta com `max-w-lg` quando o rodapé tiver três ações. |
370
453
  | `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou conteúdo próprio. |
371
454
 
372
455
  ## Propriedades de DialogHeader
@@ -409,7 +492,7 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Ence
409
492
  | Propriedade | Tipo | Padrão | Descrição |
410
493
  | ----------- | ----------- | ------ | ------------------------------------ |
411
494
  | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
412
- | `className` | `string` | | Ajusta o título, que trunca quando não cabe na linha. |
495
+ | `className` | `string` | | Ajusta o título. No modo padrão, ele trunca quando não cabe na linha; no alerta, fica centralizado e pode ocupar mais de uma linha. |
413
496
  | `children` | `ReactNode` | | Nome da tarefa ou do conteúdo modal. |
414
497
 
415
498
  ## Propriedades de DialogMedia
@@ -1,6 +1,6 @@
1
1
  Use `DictionaryValue` para apresentar um valor de `t.dict` de acordo com o papel declarado pelo
2
- próprio dicionário. A tela fornece o dicionário e o código; o componente escolhe texto, badge e ícone
3
- sem perder o rótulo visível.
2
+ próprio dicionário. A tela fornece o dicionário e o código; o componente escolhe texto,
3
+ [`Badge`](/ui/badge) e ícone sem perder o rótulo visível.
4
4
 
5
5
  ```tsx preview
6
6
  <DictionaryValue
@@ -56,7 +56,7 @@ export const customerStageDict = t.dict(
56
56
  - `context` (`neutral` · `info` · `success` · `warning` · `danger`) só existe em status e estágio;
57
57
  `t.dict` rejeita o contexto em classificação e em `plain`.
58
58
  - `icon` é um nome do catálogo do Opus (`iconPickerIcons`). Nome fora do catálogo não renderiza
59
- ícone; o renderer não inventa. Vocabulário próprio entra por `icons`.
59
+ ícone; o componente não escolhe um substituto. Vocabulário próprio entra por `icons`.
60
60
  - `description` é o texto curto para a pessoa e aparece em tooltip focável. Descrição igual ao
61
61
  rótulo não vira tooltip. `doc` é o entendimento de negócio para manifest e Lens; não aparece.
62
62
 
@@ -100,7 +100,7 @@ Valor fora do dicionário aparece como texto com o próprio código, marcado com
100
100
 
101
101
  ## Em ActionList
102
102
 
103
- Coluna cujo campo do schema de saída é um `t.dict().zod()` já renderiza `DictionaryValue` com o
103
+ Em [`ActionList`](/ui/action-list), a coluna cujo campo do schema de saída é um `t.dict().zod()` já renderiza `DictionaryValue` com o
104
104
  papel declarado, sem `cells`. Quando o campo de saída é uma string comum, a coluna nomeia o
105
105
  dicionário registrado no provider: `{ key: 'source', label: 'Fonte', dictionary: 'customerSource' }`.
106
106
  Dimensões independentes (tipo e estágio, por exemplo) ficam em colunas distintas; não empilhar
@@ -1,7 +1,7 @@
1
- Ferramentas ancoradas à superfície de trabalho. Um canvas ou um editor raramente comporta mais
2
- uma faixa de chrome no topo: a trilha da aplicação já ocupa esse papel, e um segundo cabeçalho
3
- empilha duas faixas com a mesma função. A Dock coloca as ações sobre a própria superfície,
4
- agrupadas e sempre alcançáveis.
1
+ Use `Dock` para as ferramentas de uma superfície de trabalho, como um canvas ou um editor. Essas
2
+ telas raramente comportam mais uma barra no topo: a navegação da aplicação já ocupa esse lugar, e
3
+ um segundo cabeçalho empilharia duas faixas com a mesma função. A Dock coloca as ações sobre a
4
+ própria superfície, agrupadas e sempre alcançáveis.
5
5
 
6
6
  ```tsx preview
7
7
  <div className="relative h-40 w-full rounded-lg border border-border bg-muted/20">
@@ -23,8 +23,8 @@ agrupadas e sempre alcançáveis.
23
23
 
24
24
  O contêiner precisa ser `relative` — a Dock se ancora nele, não na janela. `position` escolhe a
25
25
  aresta: `bottom` (centro), `bottom-left` e `bottom-right`. Uma superfície pode ter mais de uma
26
- barra quando os papéis são distintos, como ferramentas ao centro e controles de viewport à
27
- esquerda.
26
+ barra quando os papéis são distintos, como ferramentas ao centro e controles de visualização à
27
+ direita.
28
28
 
29
29
  ## Grupos e divisórias
30
30
 
@@ -44,10 +44,43 @@ Mensagem de sucesso é transitória por natureza — some depois de confirmar
44
44
  permanece até o estado mudar. Essa decisão é da aplicação, que conhece o ciclo; o componente
45
45
  apenas reserva o lugar.
46
46
 
47
- `actions` recebe o que o recurso aberto permite fazer — em geral o mesmo menu que a linha dele
48
- tem na navegação. Assim a superfície deixa de ser o único lugar onde renomear ou excluir não
49
- alcançam o item que está na tela. Apenas o texto é região viva: anunciar o menu a cada mudança de
50
- estado seria ruído para quem usa leitor de tela.
47
+ `actions` recebe o que o recurso aberto permite fazer — em geral o mesmo [`Menu`](/ui/menu) que a
48
+ linha dele tem na navegação. Assim, renomear ou excluir também alcançam o item que está na tela.
49
+ Apenas o texto é região viva: anunciar o menu a cada mudança de estado seria ruído para quem usa
50
+ leitor de tela.
51
+
52
+ No exemplo, o estado de falha fica no canto superior esquerdo com o menu do recurso, e os controles
53
+ de visualização ficam no canto inferior direito.
54
+
55
+ ```tsx preview
56
+ <div className="relative h-40 w-full rounded-lg border border-border bg-muted/20">
57
+ <SurfaceStatus
58
+ position="top-left"
59
+ context="danger"
60
+ actions={
61
+ <Menu>
62
+ <MenuTrigger asChild>
63
+ <Button variant="ghost" size="icon" aria-label="Ações do fluxo"><MoreHorizontal /></Button>
64
+ </MenuTrigger>
65
+ <MenuContent align="start">
66
+ <MenuItem><Pencil /> Renomear</MenuItem>
67
+ <MenuSeparator />
68
+ <MenuItem context="danger"><Trash2 /> Excluir</MenuItem>
69
+ </MenuContent>
70
+ </Menu>
71
+ }
72
+ >
73
+ Falha ao salvar
74
+ </SurfaceStatus>
75
+ <Dock label="Controles de visualização" position="bottom-right">
76
+ <DockGroup>
77
+ <DockAction icon={<ZoomOut />} label="Afastar" onClick={() => {}} />
78
+ <DockAction icon={<ZoomIn />} label="Aproximar" onClick={() => {}} />
79
+ <DockAction icon={<Maximize />} label="Ajustar à tela" onClick={() => {}} />
80
+ </DockGroup>
81
+ </Dock>
82
+ </div>
83
+ ```
51
84
 
52
85
  ## Modo e execução
53
86
 
@@ -57,36 +90,36 @@ o rótulo, que também é o nome acessível.
57
90
 
58
91
  ## Teclado
59
92
 
60
- A barra é uma `toolbar`: as setas andam entre as ações e Home/End vão às pontas. Cada ação nomeia-se
61
- por tooltip, então `<TooltipProvider>` precisa existir na raiz do app — o esqueleto do `opus create`
62
- já monta.
93
+ A barra é uma `toolbar`: as setas andam entre as ações e Home/End vão às pontas. Cada ação exibe o nome em um
94
+ [tooltip](/ui/tooltip), então `<TooltipProvider>` precisa existir na raiz do app — o projeto criado
95
+ por `opus create` já o monta.
63
96
 
64
97
  ## Propriedades de Dock
65
98
 
66
99
  | Propriedade | Tipo | Padrão | Descrição |
67
100
  | --- | --- | --- | --- |
68
101
  | `position` | `'bottom' \| 'bottom-left' \| 'bottom-right'` | `'bottom'` | Aresta do contêiner onde a barra se ancora. |
69
- | `label` | `string` | | Nome acessível da barra. |
70
- | `children` | `ReactNode` | | Os grupos de ações, em `DockGroup`. |
102
+ | `label` | `string` | obrigatório | Nome acessível da barra. |
103
+ | `children` | `ReactNode` | obrigatório | Os grupos de ações, em `DockGroup`. |
71
104
  | `className` | `string` | | Classes adicionais da barra. |
72
105
 
73
106
  ## Propriedades de DockGroup
74
107
 
75
108
  | Propriedade | Tipo | Padrão | Descrição |
76
109
  | --- | --- | --- | --- |
77
- | `children` | `ReactNode` | | As ações do grupo, em `DockAction`. A divisória antes do grupo é aplicada automaticamente, exceto no primeiro. |
110
+ | `children` | `ReactNode` | obrigatório | As ações do grupo, em `DockAction`. A divisória antes do grupo é aplicada automaticamente, exceto no primeiro. |
78
111
  | `className` | `string` | | Classes adicionais do grupo. |
79
112
 
80
113
  ## Propriedades de DockAction
81
114
 
82
115
  | Propriedade | Tipo | Padrão | Descrição |
83
116
  | --- | --- | --- | --- |
84
- | `icon` | `ReactNode` | | Ícone exibido no botão. |
85
- | `label` | `string` | | Nome da ação; vira o nome acessível e o tooltip quando não há `hint`. |
117
+ | `icon` | `ReactNode` | obrigatório | Ícone exibido no botão. |
118
+ | `label` | `string` | obrigatório | Nome da ação; vira o nome acessível e o tooltip quando não há `hint`. |
86
119
  | `pressed` | `boolean` | | Presente quando a ação liga um modo: aplica o preenchimento e expõe `aria-pressed`. Ausente quando a ação apenas executa. |
87
120
  | `disabled` | `boolean` | `false` | Desabilita a ação e a tira da navegação por setas. |
88
121
  | `hint` | `ReactNode` | `label` | Conteúdo do tooltip quando ele precisa dizer mais que o rótulo. |
89
- | `onClick` | `() => void` | | Executa a ação ou alterna o modo. |
122
+ | `onClick` | `() => void` | obrigatório | Executa a ação ou alterna o modo. |
90
123
  | `className` | `string` | | Classes adicionais do botão. |
91
124
 
92
125
  ## Propriedades de SurfaceStatus
@@ -96,3 +129,5 @@ já monta.
96
129
  | `position` | `'top-right' \| 'top-left'` | `'top-right'` | Canto da superfície onde o estado se ancora. |
97
130
  | `context` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | O que o estado comunica; tinge borda e texto pela família semântica. |
98
131
  | `actions` | `ReactNode` | | Ações do recurso aberto, fora da região viva. |
132
+ | `children` | `ReactNode` | | O texto do estado, anunciado pela região viva a cada mudança. |
133
+ | `className` | `string` | | Classes adicionais do contêiner. |
@@ -1,6 +1,7 @@
1
1
  Indicador visual compacto para estados que já têm contexto. O tamanho permanece fixo; `context`
2
- seleciona o significado e `variant` escolhe ponto sólido ou contornado. Quando a cor reforça significado, `label` fornece o nome
3
- acessível. Sem `label`, o ponto é decorativo.
2
+ seleciona o significado e `variant` escolhe ponto sólido ou contornado. Quando a cor reforça
3
+ significado, `label` fornece o nome acessível. Sem `label`, o ponto é decorativo e fica oculto dos
4
+ leitores de tela.
4
5
 
5
6
  ```tsx preview
6
7
  <div className="flex items-center gap-4">
@@ -8,11 +9,25 @@ acessível. Sem `label`, o ponto é decorativo.
8
9
  <Dot context="warning" label="Atenção" />
9
10
  <Dot context="danger" label="Falhou" />
10
11
  <Dot context="info" label="Publicado" />
11
- <Dot context="neutral" aria-hidden />
12
+ <Dot context="neutral" />
12
13
  </div>
13
14
  ```
14
15
 
15
- Use `Badge` quando o estado precisar permanecer legível sem depender do contexto ao redor.
16
+ Use [`Badge`](/ui/badge) quando o estado precisar permanecer legível sem depender do contexto ao
17
+ redor.
18
+
19
+ ## Ponto contornado
20
+
21
+ `variant="outline"` desenha só o contorno. Ele diferencia dois estados que compartilham o mesmo
22
+ `context`, como uma execução agendada e uma em andamento. O `label` continua nomeando cada estado.
23
+
24
+ ```tsx preview
25
+ <div className="flex items-center gap-4 text-sm">
26
+ <span className="flex items-center gap-2"><Dot context="success" label="Em execução" /> developer</span>
27
+ <span className="flex items-center gap-2"><Dot context="success" variant="outline" label="Agendado" /> reviewer</span>
28
+ <span className="flex items-center gap-2"><Dot context="neutral" variant="outline" label="Inativo" /> designer</span>
29
+ </div>
30
+ ```
16
31
 
17
32
  ## Propriedades de Dot
18
33
 
@@ -20,4 +35,19 @@ Use `Badge` quando o estado precisar permanecer legível sem depender do context
20
35
  |---|---|---|---|
21
36
  | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | O significado da cor. |
22
37
  | `variant` | `'solid' \| 'outline'` | `'solid'` | Ponto preenchido ou só contornado. |
23
- | `label` | `string` | | Nome acessível quando a cor comunica estado; sem ele o ponto é decorativo (`aria-hidden`). |
38
+ | `label` | `string` | | Nome acessível quando a cor comunica estado; o ponto passa a ser exposto como imagem com esse nome. Sem ele, o ponto é decorativo (`aria-hidden`). |
39
+
40
+ Os demais atributos vão para o elemento `span`.
41
+
42
+ ## Função dotVariants
43
+
44
+ `dotVariants({ context, variant })` retorna as classes do ponto para um elemento que não é
45
+ renderizado pelo `Dot`. Os padrões são os mesmos do componente: `neutral` e `solid`. Sem o
46
+ componente, o elemento não recebe `label` nem `aria-hidden`; trate a acessibilidade nele.
47
+
48
+ ```ts
49
+ function dotVariants(options?: {
50
+ context?: DotContext | null
51
+ variant?: DotVariant | null
52
+ }): string
53
+ ```