@softize/opus 12.10.0 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/bin/lib/check.mjs +1098 -310
  3. package/bin/lib/copy.mjs +12 -5
  4. package/docs/adr/0003-dictionary-presentation-is-declared.md +3 -0
  5. package/docs/adr/0004-page-content-state-is-composed.md +65 -0
  6. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +180 -0
  7. package/docs/adr/0006-semantic-context-precedes-visual-variant.md +182 -0
  8. package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
  9. package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
  10. package/docs/radius-scale.md +1 -1
  11. package/package.json +1 -1
  12. package/registry/instructions/opus.md +5 -0
  13. package/registry/skills/build-opus-ui/SKILL.md +27 -16
  14. package/registry/skills/build-opus-ui/references/evaluations.md +16 -5
  15. package/registry/skills/build-opus-ui/references/ui-patterns.md +38 -15
  16. package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
  17. package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
  18. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
  19. package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
  20. package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
  21. package/registry/skills/model-opus-dictionary/SKILL.md +4 -2
  22. package/registry/skills/model-opus-dictionary/references/evaluations.md +4 -3
  23. package/registry/templates/app/src/App.tsx +1 -1
  24. package/src/core/dictionary.ts +52 -14
  25. package/src/core/index.ts +10 -0
  26. package/src/core/ui-context.ts +29 -0
  27. package/src/schema/drivers/zod.ts +17 -8
  28. package/src/ui/components/patterns/action-form-card.tsx +18 -12
  29. package/src/ui/components/patterns/confirm.tsx +163 -40
  30. package/src/ui/components/patterns/content-header.tsx +335 -61
  31. package/src/ui/components/patterns/data-state.tsx +23 -10
  32. package/src/ui/components/patterns/list.tsx +1097 -783
  33. package/src/ui/components/patterns/page-state.tsx +115 -0
  34. package/src/ui/components/patterns/page.tsx +231 -41
  35. package/src/ui/components/patterns/sidebar.tsx +357 -83
  36. package/src/ui/components/patterns/trigger.tsx +37 -30
  37. package/src/ui/components/patterns/view.tsx +7 -11
  38. package/src/ui/components/primitives/alert.tsx +298 -110
  39. package/src/ui/components/primitives/ask.tsx +2 -1
  40. package/src/ui/components/primitives/badge.tsx +91 -30
  41. package/src/ui/components/primitives/button.tsx +99 -60
  42. package/src/ui/components/primitives/calendar.tsx +39 -39
  43. package/src/ui/components/primitives/card.tsx +96 -23
  44. package/src/ui/components/primitives/detail.tsx +2 -2
  45. package/src/ui/components/primitives/dialog.tsx +196 -39
  46. package/src/ui/components/primitives/dictionary-value.tsx +9 -14
  47. package/src/ui/components/primitives/dot.tsx +74 -21
  48. package/src/ui/components/primitives/drawer.tsx +40 -24
  49. package/src/ui/components/primitives/empty.tsx +3 -3
  50. package/src/ui/components/primitives/item.tsx +135 -79
  51. package/src/ui/components/primitives/menu.tsx +11 -3
  52. package/src/ui/components/primitives/metric-card.tsx +133 -0
  53. package/src/ui/components/primitives/sonner.tsx +187 -8
  54. package/src/ui/components/primitives/table.tsx +2 -2
  55. package/src/ui/docs/DocBrowser.tsx +104 -25
  56. package/src/ui/docs/changelog.tsx +1 -1
  57. package/src/ui/docs/content/accordion.md +22 -16
  58. package/src/ui/docs/content/action-form-card.md +8 -8
  59. package/src/ui/docs/content/action-form-dialog.md +9 -9
  60. package/src/ui/docs/content/action-form.md +28 -34
  61. package/src/ui/docs/content/action-list-dialog.md +11 -6
  62. package/src/ui/docs/content/action-list.md +64 -39
  63. package/src/ui/docs/content/action-trigger.md +21 -14
  64. package/src/ui/docs/content/action-view.md +8 -8
  65. package/src/ui/docs/content/actions.md +9 -9
  66. package/src/ui/docs/content/ai.md +3 -3
  67. package/src/ui/docs/content/alert.md +54 -28
  68. package/src/ui/docs/content/aspect-ratio.md +4 -4
  69. package/src/ui/docs/content/audit.md +2 -2
  70. package/src/ui/docs/content/auth.md +3 -3
  71. package/src/ui/docs/content/avatar.md +34 -14
  72. package/src/ui/docs/content/badge.md +21 -22
  73. package/src/ui/docs/content/breadcrumb.md +13 -8
  74. package/src/ui/docs/content/button.md +93 -15
  75. package/src/ui/docs/content/calendar.md +5 -5
  76. package/src/ui/docs/content/card.md +6 -6
  77. package/src/ui/docs/content/carousel.md +16 -11
  78. package/src/ui/docs/content/chat.md +3 -3
  79. package/src/ui/docs/content/checkbox.md +7 -7
  80. package/src/ui/docs/content/cli.md +5 -5
  81. package/src/ui/docs/content/collapsible.md +8 -8
  82. package/src/ui/docs/content/command.md +16 -8
  83. package/src/ui/docs/content/composer.md +2 -2
  84. package/src/ui/docs/content/content.md +44 -0
  85. package/src/ui/docs/content/copyable.md +4 -3
  86. package/src/ui/docs/content/customization.md +7 -7
  87. package/src/ui/docs/content/cycle.md +3 -3
  88. package/src/ui/docs/content/data-state.md +11 -12
  89. package/src/ui/docs/content/data.md +26 -33
  90. package/src/ui/docs/content/detail.md +8 -5
  91. package/src/ui/docs/content/dialog.md +339 -31
  92. package/src/ui/docs/content/dictionary-value.md +19 -18
  93. package/src/ui/docs/content/dock.md +3 -3
  94. package/src/ui/docs/content/dot.md +7 -7
  95. package/src/ui/docs/content/drawer.md +32 -16
  96. package/src/ui/docs/content/empty-value.md +2 -2
  97. package/src/ui/docs/content/empty.md +19 -12
  98. package/src/ui/docs/content/events.md +4 -4
  99. package/src/ui/docs/content/field.md +34 -12
  100. package/src/ui/docs/content/getting-started.md +1 -1
  101. package/src/ui/docs/content/icon-picker.md +8 -4
  102. package/src/ui/docs/content/input-otp.md +20 -12
  103. package/src/ui/docs/content/input.md +121 -9
  104. package/src/ui/docs/content/item.md +64 -24
  105. package/src/ui/docs/content/kbd.md +19 -11
  106. package/src/ui/docs/content/label.md +5 -3
  107. package/src/ui/docs/content/log.md +4 -4
  108. package/src/ui/docs/content/markdown.md +7 -6
  109. package/src/ui/docs/content/mcp.md +13 -15
  110. package/src/ui/docs/content/menu.md +36 -17
  111. package/src/ui/docs/content/metric-card.md +41 -0
  112. package/src/ui/docs/content/observability.md +2 -2
  113. package/src/ui/docs/content/page.md +93 -10
  114. package/src/ui/docs/content/pagination.md +22 -17
  115. package/src/ui/docs/content/popover.md +16 -8
  116. package/src/ui/docs/content/progress.md +7 -5
  117. package/src/ui/docs/content/queue.md +5 -5
  118. package/src/ui/docs/content/radio-group.md +20 -12
  119. package/src/ui/docs/content/router.md +11 -6
  120. package/src/ui/docs/content/scheduler.md +4 -5
  121. package/src/ui/docs/content/scroll-area.md +12 -7
  122. package/src/ui/docs/content/select.md +42 -29
  123. package/src/ui/docs/content/semantic-context.md +63 -0
  124. package/src/ui/docs/content/separator.md +5 -5
  125. package/src/ui/docs/content/sidebar.md +325 -56
  126. package/src/ui/docs/content/skeleton.md +5 -4
  127. package/src/ui/docs/content/slider.md +8 -7
  128. package/src/ui/docs/content/spinner.md +8 -8
  129. package/src/ui/docs/content/split.md +8 -5
  130. package/src/ui/docs/content/storage.md +6 -8
  131. package/src/ui/docs/content/switch.md +8 -7
  132. package/src/ui/docs/content/table.md +16 -6
  133. package/src/ui/docs/content/tabs.md +28 -14
  134. package/src/ui/docs/content/testing.md +9 -11
  135. package/src/ui/docs/content/textarea.md +5 -4
  136. package/src/ui/docs/content/toast.md +47 -13
  137. package/src/ui/docs/content/toggle.md +75 -7
  138. package/src/ui/docs/content/tokens.md +31 -3
  139. package/src/ui/docs/content/tooltip.md +19 -11
  140. package/src/ui/docs/content/truncate.md +7 -8
  141. package/src/ui/docs/content/ui.md +10 -9
  142. package/src/ui/docs/content/upgrading.md +7 -8
  143. package/src/ui/docs/doc-client.tsx +2 -2
  144. package/src/ui/docs/registry.tsx +580 -229
  145. package/src/ui/lib/semantic-context.ts +30 -0
  146. package/src/ui/meta.ts +278 -286
  147. package/src/ui/react.tsx +377 -111
  148. package/src/ui/theme.css +116 -0
  149. package/src/ui/components/primitives/alert-dialog.tsx +0 -190
  150. package/src/ui/docs/content/alert-dialog.md +0 -73
  151. package/src/ui/docs/content/button-group.md +0 -71
  152. package/src/ui/docs/content/confirm.md +0 -120
  153. package/src/ui/docs/content/input-group.md +0 -78
  154. package/src/ui/docs/content/toggle-group.md +0 -81
@@ -1,6 +1,8 @@
1
1
  ## Tabela de domínio
2
2
 
3
- A Table vem SEM borda externa as divisórias de linha (a última o TableBody zera). Coluna numérica alinha à direita (text-right no TableHead E no TableCell). A TableCaption fica embaixo (caption-bottom) e descreve a tabela.
3
+ Use `Table` para dados organizados em linhas e colunas. A variante padrão não possui borda externa;
4
+ `TableBody` mantém somente as divisórias internas. Aplique `text-right` ao cabeçalho e às células
5
+ quando o domínio pedir alinhamento numérico. `TableCaption` descreve a tabela abaixo do conteúdo.
4
6
 
5
7
  ```tsx preview col
6
8
  <Table>
@@ -17,26 +19,26 @@ A Table vem SEM borda externa — só as divisórias de linha (a última o Table
17
19
  <TableRow>
18
20
  <TableCell className="font-medium">Importar pedidos da transportadora</TableCell>
19
21
  <TableCell>developer</TableCell>
20
- <TableCell><Badge variant="info">Em sessão</Badge></TableCell>
22
+ <TableCell><Badge context="info">Em sessão</Badge></TableCell>
21
23
  <TableCell className="text-right">42 min</TableCell>
22
24
  </TableRow>
23
25
  <TableRow>
24
26
  <TableCell className="font-medium">Revisar contrato de rastreio</TableCell>
25
27
  <TableCell>reviewer</TableCell>
26
- <TableCell><Badge variant="warning">Aguardando revisor</Badge></TableCell>
28
+ <TableCell><Badge context="warning">Aguardando revisor</Badge></TableCell>
27
29
  <TableCell className="text-right">18 min</TableCell>
28
30
  </TableRow>
29
31
  <TableRow>
30
32
  <TableCell className="font-medium">Ajustar microcopy do painel</TableCell>
31
33
  <TableCell>designer</TableCell>
32
- <TableCell><Badge variant="success">Concluída</Badge></TableCell>
34
+ <TableCell><Badge context="success">Concluída</Badge></TableCell>
33
35
  <TableCell className="text-right">7 min</TableCell>
34
36
  </TableRow>
35
37
  </TableBody>
36
38
  </Table>
37
39
  ```
38
40
 
39
- ## Moldura (o datagrid da casa)
41
+ ## Tabela emoldurada
40
42
 
41
43
  A variante `framed` aplica no próprio contêiner a borda externa, os cantos arredondados, o
42
44
  scroll horizontal contido e o fundo discreto do cabeçalho. A última linha já vem sem divisória,
@@ -69,7 +71,8 @@ pesquisáveis derivadas de actions `kind: 'list'`.
69
71
 
70
72
  ## Com rodapé (TableFooter)
71
73
 
72
- TableFooter fecha a tabela com a linha de agregação fundo muted e peso de fonte já vêm prontos.
74
+ Use `TableFooter` para totais ou outras agregações. O componente aplica fundo muted e peso de fonte
75
+ adequados a essa região.
73
76
 
74
77
  ```tsx preview col
75
78
  <Table>
@@ -101,3 +104,10 @@ TableFooter fecha a tabela com a linha de agregação — fundo muted e peso de
101
104
  </TableFooter>
102
105
  </Table>
103
106
  ```
107
+
108
+ ## Propriedades de Table
109
+
110
+ | Propriedade | Tipo | Padrão | Descrição |
111
+ |---|---|---|---|
112
+ | `variant` | `'plain' \| 'framed'` | `'plain'` | Escolhe entre a estrutura sem moldura externa e o contêiner emoldurado. |
113
+ | `className` | `string` | | Classes aplicadas ao elemento `table`. |
@@ -1,6 +1,8 @@
1
- ## Padrão (pill)
1
+ ## Alternar painéis relacionados
2
2
 
3
- O value do TabsTrigger pareia com o do TabsContent. defaultValue deixa o estado com o componente; pra controlar, use value + onValueChange.
3
+ Use `Tabs` para alternar painéis relacionados no mesmo contexto. O `value` de cada `TabsTrigger`
4
+ corresponde ao `TabsContent` que ele abre. `defaultValue` define a aba inicial no modo não
5
+ controlado.
4
6
 
5
7
  ```tsx preview col
6
8
  <Tabs defaultValue="sessions">
@@ -23,7 +25,8 @@ O value do TabsTrigger pareia com o do TabsContent. defaultValue deixa o estado
23
25
 
24
26
  ## Variante line
25
27
 
26
- variant=line na TabsList: fundo transparente, o ativo é marcado pelo traço embaixo — bom pra cabeçalho de página, onde o pill pesaria.
28
+ Use `variant="line"` em `TabsList` quando a lista precisar se integrar a uma borda, como em um
29
+ cabeçalho. A aba ativa é marcada por uma linha em vez de uma superfície preenchida.
27
30
 
28
31
  ```tsx preview col
29
32
  <Tabs defaultValue="agents">
@@ -46,7 +49,8 @@ variant=line na TabsList: fundo transparente, o ativo é marcado pelo traço emb
46
49
 
47
50
  ## Vertical
48
51
 
49
- orientation=vertical no Tabs: a lista vira coluna e o traço da variante line migra pra lateral direita do trigger.
52
+ Com `orientation="vertical"`, a lista forma uma coluna e a marca da variante `line` passa para a
53
+ lateral do gatilho.
50
54
 
51
55
  ```tsx preview col
52
56
  <Tabs defaultValue="prompt" orientation="vertical">
@@ -67,7 +71,7 @@ orientation=vertical no Tabs: a lista vira coluna e o traço da variante line mi
67
71
  </Tabs>
68
72
  ```
69
73
 
70
- ## Densidade (size)
74
+ ## Tamanho
71
75
 
72
76
  `size="sm"` no `Tabs` reduz a lista de `h-9` (2.25rem) para `h-8` (2rem). É o par do `sm` de Button e Select para uma fileira densa, como uma toolbar ou um cabeçalho, em que o segmento não deve ficar mais alto que os elementos vizinhos.
73
77
 
@@ -81,14 +85,24 @@ orientation=vertical no Tabs: a lista vira coluna e o traço da variante line mi
81
85
  </Tabs>
82
86
  ```
83
87
 
84
- ## Props
88
+ ## Propriedades de Tabs
85
89
 
86
- | Prop | Tipo | Default | Descrição |
90
+ | Propriedade | Tipo | Padrão | Descrição |
87
91
  |---|---|---|---|
88
- | `defaultValue (Tabs)` | `string` | | A aba inicial no modo não-controlado. |
89
- | `value (Tabs)` | `string` | | A aba ativa no modo controlado pareie com onValueChange. |
90
- | `onValueChange (Tabs)` | `(value: string) => void` | | Chamado quando o usuário troca de aba. |
91
- | `size (Tabs)` | `'default' \| 'sm'` | `'default'` | Altura da lista: default (h-9) ou sm (h-8), o par do sm de Button/Select. Flui pra TabsList por contexto. |
92
- | `orientation (Tabs)` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas — vertical vira coluna lateral. |
93
- | `variant (TabsList)` | `'default' \| 'line'` | `'default'` | default é o pill (fundo muted); line é a barra sublinhada, sem fundo. |
94
- | `value (TabsTrigger/TabsContent)` | `string` | | Identificador que pareia o trigger com o painel correspondente. |
92
+ | `defaultValue` | `string` | | Aba inicial no modo não controlado. |
93
+ | `value` | `string` | | Aba ativa no modo controlado. Use com `onValueChange`. |
94
+ | `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outra aba. |
95
+ | `size` | `'default' \| 'sm'` | `'default'` | Escala de altura compartilhada com `TabsList`. |
96
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas. |
97
+
98
+ ## Propriedades de TabsList
99
+
100
+ | Propriedade | Tipo | Padrão | Descrição |
101
+ |---|---|---|---|
102
+ | `variant` | `'default' \| 'line'` | `'default'` | `default` usa uma superfície preenchida; `line` marca a aba ativa junto à borda. |
103
+
104
+ ## Propriedades de TabsTrigger e TabsContent
105
+
106
+ | Propriedade | Tipo | Padrão | Descrição |
107
+ |---|---|---|---|
108
+ | `value` | `string` | | Identificador que associa o gatilho ao painel correspondente. |
@@ -4,16 +4,14 @@ title: Testes de action
4
4
 
5
5
  # Testes de action
6
6
 
7
- A unidade natural de teste no Opus é a **action** o contrato: input → output/erro,
8
- bordas do schema, autorização fail-closed. `@softize/opus/testing` roda esse contrato
9
- em unidade, sem montar runtime nem mockar contexto à mão.
7
+ Teste cada action pela fronteira do contrato: entrada, saída ou erro, limites do schema e
8
+ autorização. `@softize/opus/testing` executa esse fluxo em unidade sem montar o runtime completo.
10
9
 
11
- ## runAction o contrato em unidade
10
+ ## Executar o contrato em unidade
12
11
 
13
- O harness executa o **mesmo pipeline do runtime**: valida o input cobra o gate
14
- `public` avalia o `authorize` (string DSL ou closure, semântica idêntica) → roda o
15
- handler → valida o output. Falha estoura o mesmo `ActionError` tipado do runtime
16
- (`validation.invalid_input`, `auth.unauthenticated`, `auth.forbidden`…).
12
+ `runAction` valida a entrada, aplica o gate `public`, avalia `authorize`, executa o handler e valida
13
+ a saída. Falhas usam o mesmo `ActionError` tipado do runtime, como `validation.invalid_input`,
14
+ `auth.unauthenticated` e `auth.forbidden`.
17
15
 
18
16
  ```ts
19
17
  import { runAction } from '@softize/opus/testing'
@@ -45,7 +43,7 @@ it('só a dona edita', async () => {
45
43
 
46
44
  ## Contexto observável
47
45
 
48
- `runAction` (e `testContext`, pra quem quer só o ctx) devolve os efeitos capturados —
46
+ `runAction` (e `testContext`, para quem quer só o ctx) devolve os efeitos capturados —
49
47
  o teste afirma o que importa:
50
48
 
51
49
  ```ts
@@ -55,7 +53,7 @@ expect(emitted).toEqual([{ event: 'task.done', data: { id: '1' } }])
55
53
 
56
54
  ## memStorage
57
55
 
58
- `StorageAdapter` em memória com a mesma régua de key dos drivers reais — pra handler
56
+ `StorageAdapter` em memória com a mesma régua de key dos drivers reais — para handler
59
57
  que anexa arquivo:
60
58
 
61
59
  ```ts
@@ -81,7 +79,7 @@ const many = fakeMany(EventEntity.zod(), 20) // 20, estáveis entre execuções
81
79
  fake(schema, { seed: 7 }) // seed própria
82
80
  ```
83
81
 
84
- ## O que fica de fora
82
+ ## Limites do teste de unidade
85
83
 
86
84
  De propósito — é harness de **unidade**: loaders reais (passe `loaded` pronto), audit,
87
85
  reactions em cadeia e o servidor. Fluxo completo é teste de integração com o runtime.
@@ -1,6 +1,7 @@
1
- ## Básico
1
+ ## Texto com várias linhas
2
2
 
3
- Cresce com o conteúdo a partir da altura mínima (field-sizing-content) digite e veja.
3
+ Use `Textarea` para texto livre com várias linhas. O campo cresce com o conteúdo a partir de sua
4
+ altura mínima.
4
5
 
5
6
  ```tsx preview col md
6
7
  <Textarea placeholder="Descreva o que o agente deve fazer nesta sessão." />
@@ -8,7 +9,7 @@ Cresce com o conteúdo a partir da altura mínima (field-sizing-content) — dig
8
9
 
9
10
  ## Com Label
10
11
 
11
- O mesmo par htmlFor↔id dos outros campos o overview do handoff é o caso típico.
12
+ Associe `htmlFor` no `Label` ao `id` do campo para manter o rótulo acessível.
12
13
 
13
14
  ```tsx preview col md
14
15
  <div className="grid gap-2">
@@ -22,7 +23,7 @@ O mesmo par htmlFor↔id dos outros campos — o overview do handoff é o caso t
22
23
 
23
24
  ## Estados
24
25
 
25
- aria-invalid pinta borda e anel destructive; disabled esmaece e bloqueia a edição.
26
+ `aria-invalid` comunica e apresenta o estado inválido; `disabled` bloqueia a edição.
26
27
 
27
28
  ```tsx preview col md
28
29
  <Textarea aria-invalid placeholder="Conte o contexto da mudança." />
@@ -1,6 +1,9 @@
1
- ## Tipos
1
+ ## Notificação temporária
2
2
 
3
- Cada tipo vem com o ícone lucide do Opus. O título é label (sem ponto); a description, frase (com ponto).
3
+ Use `toast` para informar o resultado temporário de uma ação sem interromper o fluxo. Cada tipo usa o
4
+ ícone correspondente do Opus. Escreva o título como rótulo, sem ponto final, e a descrição como uma
5
+ frase. A moldura do ícone permanece quadrada e alinhada à primeira linha mesmo quando a descrição
6
+ ocupa várias linhas.
4
7
 
5
8
  ```tsx preview
6
9
  <Button variant="outline" onClick={() => toast.success('Workspace criado')}>Sucesso</Button>
@@ -13,22 +16,34 @@ Cada tipo já vem com o ícone lucide do Opus. O título é label (sem ponto); a
13
16
  <Button variant="outline" onClick={() => toast.info('Base atualizada')}>Info</Button>
14
17
  <Button
15
18
  variant="outline"
16
- onClick={() => toast.warning('Preview parado', { description: 'Inicie o ambiente pra ver a sessão.' })}
19
+ onClick={() => toast.warning('Preview parado', { description: 'Inicie o ambiente para ver a sessão.' })}
17
20
  >
18
21
  Aviso
19
22
  </Button>
20
23
  ```
21
24
 
22
- ## Ação e progresso
25
+ ## Ações e progresso
23
26
 
24
- action põe um botão no toast (ex.: desfazer); toast.promise acompanha uma operação loading vira sucesso ou erro sozinho.
27
+ `actions` recebe uma coleção ordenada de ações compactas. A última ação ganha destaque primário por
28
+ padrão; as anteriores usam tratamento neutro e podem declarar `context` e `variant` quando a
29
+ hierarquia precisar ser diferente. A região fica alinhada ao fim lógico da superfície, no mesmo
30
+ canto usado pelas ações do Alert. O clique fecha o toast, salvo quando o handler chama
31
+ `event.preventDefault()`.
32
+
33
+ Na versão 13, `actions` substitui os campos `action` e `cancel` da versão 12. Migre cada controle
34
+ para uma entrada da coleção e preserve a ordem visual desejada.
35
+
36
+ `toast.promise` acompanha uma promessa e atualiza a mesma notificação nos estados de carregamento,
37
+ sucesso ou erro.
25
38
 
26
39
  ```tsx preview
27
40
  <Button
28
41
  variant="outline"
29
42
  onClick={() =>
30
43
  toast('Sessão arquivada', {
31
- action: { label: 'Desfazer', onClick: () => toast.success('Sessão restaurada') },
44
+ actions: [
45
+ { label: 'Desfazer', onClick: () => toast.success('Sessão restaurada') },
46
+ ],
32
47
  })
33
48
  }
34
49
  >
@@ -48,9 +63,10 @@ action põe um botão no toast (ex.: desfazer); toast.promise acompanha uma oper
48
63
  </Button>
49
64
  ```
50
65
 
51
- ## Toaster no root
66
+ ## Toaster na raiz
52
67
 
53
- Monte uma vez, fora do App. Divergência declarada: sem next-themes — o tema vem por prop (default 'system'); a elevação dark usa bg-popover.
68
+ Monte um único `Toaster` na raiz do aplicativo. O tema vem da propriedade `theme`, cujo padrão é
69
+ `system`; não há dependência de `next-themes`.
54
70
 
55
71
  ```tsx
56
72
  /* main.tsx do app — uma vez. */
@@ -58,10 +74,28 @@ Monte uma vez, fora do App. Divergência declarada: sem next-themes — o tema v
58
74
  <Toaster />
59
75
  ```
60
76
 
61
- ## Props
77
+ ## Propriedades de Toaster
78
+
79
+ | Propriedade | Tipo | Padrão | Descrição |
80
+ |---|---|---|---|
81
+ | `theme` | `'light' \| 'dark' \| 'system'` | `'system'` | Define o tema das notificações; sem `next-themes`, a escolha pertence ao aplicativo. |
82
+ | `position` | `'bottom-right' \| 'top-center' \| …` | `'bottom-right'` | Região da tela onde as notificações aparecem. |
83
+
84
+ ## Opções de toast
85
+
86
+ | Opção | Tipo | Padrão | Descrição |
87
+ |---|---|---|---|
88
+ | `description` | `React.ReactNode` | | Complemento exibido abaixo do título. |
89
+ | `actions` | `ToastAction[]` | | Coleção ordenada de ações; a última recebe destaque primário por padrão. |
90
+ | `duration` | `number` | do Sonner | Tempo de permanência da notificação. |
91
+
92
+ ## Propriedades de ToastAction
62
93
 
63
- | Prop | Tipo | Default | Descrição |
94
+ | Propriedade | Tipo | Padrão | Descrição |
64
95
  |---|---|---|---|
65
- | `Toaster.theme` | `'light' \| 'dark' \| 'system'` | `'system'` | Força o tema dos toasts — sem next-themes, a escolha é do app. |
66
- | `Toaster.position` | `'bottom-right' \| 'top-center' \| …` | `'bottom-right'` | Canto onde os toasts aparecem (sonner). |
67
- | `toast(title, opts)` | `{ description?, action?, duration?, }` | | A API de disparo (sonner): descrição, botão de ação e duração por toast. |
96
+ | `label` | `React.ReactNode` | obrigatório | Conteúdo visível da ação. |
97
+ | `onClick` | `(event: React.MouseEvent<HTMLButtonElement>) => void` | obrigatório | Executa a ação. Chame `event.preventDefault()` para manter o toast aberto. |
98
+ | `context` | `ButtonContext` | última: `'primary'`; anteriores: `'neutral'` | Define a intenção semântica do botão. |
99
+ | `variant` | `ButtonVariant` | última: `'solid'`; anteriores: `'ghost'` | Define o tratamento visual do botão. |
100
+ | `disabled` | `boolean` | `false` | Impede a interação com a ação. |
101
+ | `key` | `React.Key` | posição na coleção | Mantém a identidade da ação entre renderizações. |
@@ -1,6 +1,7 @@
1
- ## Básico
1
+ ## Alternar um estado
2
2
 
3
- Um botão que lembra se está ligado. defaultPressed deixa o estado com o componente; o filho costuma ser um ícone.
3
+ Use `Toggle` para uma ação que alterna entre ligada e desligada. `defaultPressed` define o estado
4
+ inicial no modo não controlado; o conteúdo pode ser texto ou ícone.
4
5
 
5
6
  ```tsx preview
6
7
  <Toggle defaultPressed aria-label="Negrito">
@@ -10,7 +11,7 @@ Um botão que lembra se está ligado. defaultPressed deixa o estado com o compon
10
11
 
11
12
  ## Controlado
12
13
 
13
- pressed + onPressedChange tiram o estado do componente — o booleano fica no seu store. Bom pra alternar o modo somente-leitura de uma sessão.
14
+ Use `pressed` e `onPressedChange` quando o estado pertencer ao consumidor.
14
15
 
15
16
  ```tsx preview
16
17
  const [readOnly, setReadOnly] = useState(true)
@@ -29,7 +30,8 @@ render(
29
30
 
30
31
  ## Variantes e tamanhos
31
32
 
32
- variant default não tem borda (o fundo aparece ativo); outline carrega a borda. size sm/default/lg ajusta a altura.
33
+ Na variante `default`, o fundo aparece somente quando o controle está ativo; `outline` mantém a
34
+ borda. `size` ajusta a altura.
33
35
 
34
36
  ```tsx preview
35
37
  <Toggle aria-label="Quebra de linha">
@@ -60,13 +62,79 @@ disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
60
62
  </Toggle>
61
63
  ```
62
64
 
63
- ## Props
65
+ ## Propriedades de Toggle
64
66
 
65
- | Prop | Tipo | Default | Descrição |
67
+ | Propriedade | Tipo | Padrão | Descrição |
66
68
  |---|---|---|---|
67
69
  | `pressed` | `boolean` | | O estado ligado/desligado no modo controlado — parear com onPressedChange. |
68
70
  | `onPressedChange` | `(pressed: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
69
71
  | `defaultPressed` | `boolean` | `false` | Estado inicial no modo não controlado. |
70
72
  | `variant` | `'default' \| 'outline'` | `'default'` | default não tem borda (fundo só quando ativo); outline carrega a borda. |
71
- | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura do botão — sm pra toolbar densa, lg pra alvo mais confortável. |
73
+ | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura do botão — sm para toolbar densa, lg para alvo mais confortável. |
72
74
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |
75
+
76
+ ## ToggleGroup
77
+
78
+ Use `ToggleGroup` quando vários toggles formarem uma única escolha ou uma coleção de estados
79
+ relacionados. `type="single"` mantém um item ativo; `type="multiple"` aceita vários.
80
+
81
+ ### Escolha única
82
+
83
+ ```tsx preview
84
+ const [view, setView] = useState('sessions')
85
+
86
+ render(
87
+ <ToggleGroup type="single" value={view} onValueChange={(v) => v && setView(v)}>
88
+ <ToggleGroupItem value="overview">Visão geral</ToggleGroupItem>
89
+ <ToggleGroupItem value="sessions">Sessões</ToggleGroupItem>
90
+ <ToggleGroupItem value="skills">Habilidades</ToggleGroupItem>
91
+ </ToggleGroup>,
92
+ )
93
+ ```
94
+
95
+ ### Escolha múltipla
96
+
97
+ ```tsx preview
98
+ const [marks, setMarks] = useState(['bold'])
99
+
100
+ render(
101
+ <ToggleGroup type="multiple" value={marks} onValueChange={setMarks}>
102
+ <ToggleGroupItem value="bold" aria-label="Negrito"><Bold /></ToggleGroupItem>
103
+ <ToggleGroupItem value="italic" aria-label="Itálico"><Italic /></ToggleGroupItem>
104
+ <ToggleGroupItem value="underline" aria-label="Sublinhado"><Underline /></ToggleGroupItem>
105
+ </ToggleGroup>,
106
+ )
107
+ ```
108
+
109
+ ### Variante e espaçamento
110
+
111
+ `variant`, `size` e `shape` definidos no grupo chegam aos itens por contexto. `spacing` separa os
112
+ itens; com zero, eles formam um bloco contínuo.
113
+
114
+ ```tsx preview
115
+ <ToggleGroup type="single" variant="outline" spacing={2} defaultValue="developer">
116
+ <ToggleGroupItem value="developer">developer</ToggleGroupItem>
117
+ <ToggleGroupItem value="reviewer">reviewer</ToggleGroupItem>
118
+ <ToggleGroupItem value="designer">designer</ToggleGroupItem>
119
+ </ToggleGroup>
120
+ ```
121
+
122
+ ### Propriedades de ToggleGroup
123
+
124
+ | Propriedade | Tipo | Padrão | Descrição |
125
+ |---|---|---|---|
126
+ | `type` | `'single' \| 'multiple'` | | Define seleção única (`string`) ou múltipla (`string[]`). |
127
+ | `value` | `string \| string[]` | | Seleção controlada; o tipo acompanha `type`. |
128
+ | `onValueChange` | `(value: string \| string[]) => void` | | Informa a nova seleção. No modo single, uma string vazia representa nenhum item ativo. |
129
+ | `defaultValue` | `string \| string[]` | | Seleção inicial no modo não controlado. |
130
+ | `variant` | `'default' \| 'outline'` | `'default'` | Tratamento visual repassado aos itens. |
131
+ | `size` | `'default' \| 'sm' \| 'lg'` | `'default'` | Tamanho repassado aos itens. |
132
+ | `shape` | `'default' \| 'pill'` | `'default'` | Geometria do grupo e de suas extremidades. |
133
+ | `spacing` | `number` | `0` | Distância entre os itens em unidades de spacing. |
134
+
135
+ ### Propriedades de ToggleGroupItem
136
+
137
+ | Propriedade | Tipo | Padrão | Descrição |
138
+ |---|---|---|---|
139
+ | `value` | `string` | | Identificador que entra no valor do grupo quando o item é ativado. |
140
+ | `disabled` | `boolean` | `false` | Bloqueia somente este item e preserva seu estado visual. |
@@ -4,7 +4,7 @@ title: Tokens & Tema
4
4
 
5
5
  # Tokens & Tema
6
6
 
7
- O tema canônico vive no Opus (`theme.css`): tokens com a cor inteira na var, mapeados pro
7
+ O tema canônico vive no Opus (`theme.css`): tokens com a cor inteira na var, mapeados para o
8
8
  Tailwind via `@theme inline`. Os swatches abaixo leem as vars **ao vivo** — troque o tema do app
9
9
  e a página acompanha.
10
10
 
@@ -43,6 +43,34 @@ render(
43
43
  )
44
44
  ```
45
45
 
46
+ ## Famílias contextuais
47
+
48
+ Os tokens `primary`, `secondary` e `destructive` acima permanecem fundações de superfície. A API
49
+ dos componentes usa famílias contextuais para separar significado de tratamento visual: cada
50
+ família oferece sólido, foreground, superfície sutil, ênfase e borda. Use as props `context` e
51
+ `variant`; classes contextuais diretas ficam reservadas à implementação dos primitives.
52
+
53
+ ```tsx preview
54
+ const CONTEXTS = ['neutral', 'primary', 'info', 'success', 'warning', 'danger']
55
+ render(
56
+ <div className="grid w-full gap-2 sm:grid-cols-2 lg:grid-cols-3">
57
+ {CONTEXTS.map((context) => (
58
+ <div
59
+ key={context}
60
+ className="rounded-md border px-3 py-2 text-sm"
61
+ style={{
62
+ backgroundColor: `var(--context-${context}-subtle)`,
63
+ borderColor: `var(--context-${context}-border)`,
64
+ color: `var(--context-${context}-emphasis)`,
65
+ }}
66
+ >
67
+ {context}
68
+ </div>
69
+ ))}
70
+ </div>,
71
+ )
72
+ ```
73
+
46
74
  ## Linhas e foco
47
75
 
48
76
  > Bordas e o anel de foco também são tokens — nada de cinza hardcoded. A aresta de superfície
@@ -142,7 +170,7 @@ render(
142
170
  > A regra anti-drift: o que não está declarado aqui (e no `theme.css`) é drift e deve ser
143
171
  > sincronizado — skill `build-opus-ui`.
144
172
 
145
- 1. Formato HSL nos tokens (o upstream migrou pra oklch) — legibilidade e ferramentas nossas; os
173
+ 1. Formato HSL nos tokens (o upstream migrou para oklch) — legibilidade e ferramentas nossas; os
146
174
  valores acompanham o upstream, só o formato difere.
147
175
  2. Elevação no dark: `--card`/`--popover` ficam ACIMA de `--background` (10% vs 3.9%) — identidade
148
176
  da casa; dialog e card "sobem" da página de verdade.
@@ -164,7 +192,7 @@ render(
164
192
 
165
193
  ## Identidade por app
166
194
 
167
- > O tema do Opus é a base; cada app sobrescreve as vars pra ter a própria identidade sem forkar componente.
195
+ > O tema do Opus é a base; cada app sobrescreve as vars para ter a própria identidade sem forkar componente.
168
196
 
169
197
  ```css
170
198
  /* index.css do app — depois do import do tema. */
@@ -1,6 +1,8 @@
1
- ## Básico
1
+ ## Informação complementar
2
2
 
3
- Texto auxiliar, nunca essencial quem navega por toque não vê tooltip. Em botão de ícone, o aria-label continua obrigatório.
3
+ Use `Tooltip` para informação curta e complementar. Como a dica não está disponível em todas as
4
+ formas de interação, ela não pode conter informação essencial. Botões somente com ícone continuam
5
+ precisando de `aria-label`.
4
6
 
5
7
  ```tsx preview
6
8
  <Tooltip>
@@ -13,7 +15,7 @@ Texto auxiliar, nunca essencial — quem navega por toque não vê tooltip. Em b
13
15
 
14
16
  ## Lados
15
17
 
16
- side escolhe o lado preferido; o Radix inverte sozinho quando falta espaço.
18
+ `side` define o lado preferido; o Radix reposiciona a dica quando não espaço.
17
19
 
18
20
  ```tsx preview
19
21
  <Tooltip>
@@ -30,9 +32,10 @@ side escolhe o lado preferido; o Radix inverte sozinho quando falta espaço.
30
32
  </Tooltip>
31
33
  ```
32
34
 
33
- ## Provider no root
35
+ ## Provider na raiz
34
36
 
35
- O TooltipProvider embrulha o app uma vez (delay compartilhado); cada Tooltip dispensa provider próprio. Este app já monta o seu no main.tsx.
37
+ Monte um único `TooltipProvider` na raiz para compartilhar o atraso de exibição. Cada `Tooltip` não
38
+ precisa de um provider próprio.
36
39
 
37
40
  ```tsx
38
41
  /* main.tsx do app — uma vez, no root. */
@@ -54,11 +57,16 @@ default nos formulários.
54
57
  </Tooltip>
55
58
  ```
56
59
 
57
- ## Props
60
+ ## Propriedades de TooltipProvider
58
61
 
59
- | Prop | Tipo | Default | Descrição |
62
+ | Propriedade | Tipo | Padrão | Descrição |
60
63
  |---|---|---|---|
61
- | `TooltipProvider.delayDuration` | `number` | `0` | Atraso (ms) até aparecer compartilhado por todos os tooltips do app. |
62
- | `TooltipContent.side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | Lado preferido; inverte sozinho sem espaço (Radix). |
63
- | `TooltipContent.sideOffset` | `number` | `0` | Distância (px) entre gatilho e dica. |
64
- | `TooltipContent.className` | `string` | `max-w-sm text-pretty` | Permite substituir o limite e a distribuição de linha quando necessário. |
64
+ | `delayDuration` | `number` | `0` | Atraso antes da exibição, compartilhado pelos tooltips do aplicativo. |
65
+
66
+ ## Propriedades de TooltipContent
67
+
68
+ | Propriedade | Tipo | Padrão | Descrição |
69
+ |---|---|---|---|
70
+ | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | Lado preferido; o Radix reposiciona a dica quando não há espaço. |
71
+ | `sideOffset` | `number` | `0` | Distância entre o gatilho e a dica. |
72
+ | `className` | `string` | `max-w-sm text-pretty` | Classes para ajustar o limite e a distribuição do texto. |
@@ -1,8 +1,7 @@
1
- ## Básico
1
+ ## Truncar somente quando necessário
2
2
 
3
- Trunca numa linha e mostra tooltip **só quando o texto realmente corta** (medição do
4
- overflow, re-medida em resize). Texto que cabe não ganha dica diferente do `title`
5
- sempre presente, que vira ruído.
3
+ Use `Truncate` para limitar um texto a uma linha e mostrar a dica somente quando houver transbordo.
4
+ O componente mede novamente o conteúdo quando o tamanho muda. Se o texto couber, não cria tooltip.
6
5
 
7
6
  ```tsx preview
8
7
  <div className="w-48 rounded-md border p-2">
@@ -10,9 +9,9 @@ sempre presente, que vira ruído.
10
9
  </div>
11
10
  ```
12
11
 
13
- ## Quando cabe, nada acontece
12
+ ## Texto sem transbordo
14
13
 
15
- O mesmo componente, com espaço de sobra: sem tooltip, sem atributo, só o texto.
14
+ Quando espaço suficiente, o componente mantém apenas o texto visível.
16
15
 
17
16
  ```tsx preview
18
17
  <div className="w-96 rounded-md border p-2">
@@ -48,8 +47,8 @@ const { ref, overflowing } = useOverflowing<HTMLSpanElement>(label)
48
47
 
49
48
  ## Conteúdo da dica
50
49
 
51
- `tooltip` sobrepõe o conteúdo mostrado no hover (default: os próprios children) útil
52
- quando a dica precisa de mais contexto que o texto cortado.
50
+ `tooltip` substitui o conteúdo da dica, cujo padrão são os próprios `children`. Use essa propriedade
51
+ quando o texto completo ainda não oferecer contexto suficiente.
53
52
 
54
53
  ```tsx preview
55
54
  <div className="w-48 rounded-md border p-2">
@@ -4,21 +4,22 @@ title: Como consumir
4
4
 
5
5
  # Como consumir a UI
6
6
 
7
- A verdade visual da casa: os componentes do `@softize/opus/ui` renderizados com o nosso tema. O
8
- que você aqui é o que os apps entregam — a referência é esta doc, não o site do shadcn.
7
+ Esta documentação é a referência visual e de uso de `@softize/opus/ui`. Os exemplos são renderizados
8
+ com o tema e o contrato entregues aos aplicativos.
9
9
 
10
10
  ## Por que esta doc existe
11
11
 
12
- > O site do shadcn é catálogo do que existe lá; os exemplos de decoram composições que não
13
- > existem no nosso registry. A expectativa visual e de uso nasce aqui.
12
+ O catálogo do shadcn documenta seu próprio código e pode mostrar composições que não fazem parte do
13
+ Opus. Consulte estas páginas para conhecer os componentes, as variações e os comportamentos
14
+ suportados pelo pacote.
14
15
 
15
- Cada página de componente mostra exemplos vivos por variante (renderizados com o tema da casa), o
16
- snippet de como se escreve e as props que importam. O texto de quando usar vem do próprio
17
- componente (o `meta` co-localizado na fonte) — a doc deriva, não duplica.
16
+ Cada página combina exemplos vivos, código e uma referência de propriedades por componente. A
17
+ orientação inicial vem de `componentMeta`, a mesma fonte usada pelo catálogo e pelas ferramentas.
18
18
 
19
19
  ## Como consumir
20
20
 
21
- > Um barrel pra componentes e hooks; o tema entra por CSS. Nada de copiar componente pra dentro do app.
21
+ Importe componentes e hooks de `@softize/opus/ui/react` e o tema por CSS. Não copie a implementação
22
+ para o aplicativo quando a API pública já atender ao caso.
22
23
 
23
24
  ```tsx
24
25
  // Componentes e hooks — tudo do mesmo barrel.
@@ -36,5 +37,5 @@ import { Button, Dialog, useAction } from '@softize/opus/ui/react'
36
37
  - **Origem shadcn** — port curado do shadcn (Radix + cmdk). Toda divergência do upstream é
37
38
  DECLARADA no componente ou no tema — o que diverge sem declaração é drift e deve ser
38
39
  sincronizado (skill `build-opus-ui`).
39
- - **Nativo do Opus** — nasceu aqui (os patterns de action). Não tem upstream pra acompanhar; a
40
+ - **Nativo do Opus** — nasceu aqui (os patterns de action). Não tem upstream para acompanhar; a
40
41
  referência é esta doc.