@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.
- package/CHANGELOG.md +56 -0
- package/bin/lib/check.mjs +1098 -310
- package/bin/lib/copy.mjs +12 -5
- package/docs/adr/0003-dictionary-presentation-is-declared.md +3 -0
- package/docs/adr/0004-page-content-state-is-composed.md +65 -0
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +180 -0
- package/docs/adr/0006-semantic-context-precedes-visual-variant.md +182 -0
- package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
- package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
- package/docs/radius-scale.md +1 -1
- package/package.json +1 -1
- package/registry/instructions/opus.md +5 -0
- package/registry/skills/build-opus-ui/SKILL.md +27 -16
- package/registry/skills/build-opus-ui/references/evaluations.md +16 -5
- package/registry/skills/build-opus-ui/references/ui-patterns.md +38 -15
- package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
- package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
- package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
- package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
- package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
- package/registry/skills/model-opus-dictionary/SKILL.md +4 -2
- package/registry/skills/model-opus-dictionary/references/evaluations.md +4 -3
- package/registry/templates/app/src/App.tsx +1 -1
- package/src/core/dictionary.ts +52 -14
- package/src/core/index.ts +10 -0
- package/src/core/ui-context.ts +29 -0
- package/src/schema/drivers/zod.ts +17 -8
- package/src/ui/components/patterns/action-form-card.tsx +18 -12
- package/src/ui/components/patterns/confirm.tsx +163 -40
- package/src/ui/components/patterns/content-header.tsx +335 -61
- package/src/ui/components/patterns/data-state.tsx +23 -10
- package/src/ui/components/patterns/list.tsx +1097 -783
- package/src/ui/components/patterns/page-state.tsx +115 -0
- package/src/ui/components/patterns/page.tsx +231 -41
- package/src/ui/components/patterns/sidebar.tsx +357 -83
- package/src/ui/components/patterns/trigger.tsx +37 -30
- package/src/ui/components/patterns/view.tsx +7 -11
- package/src/ui/components/primitives/alert.tsx +298 -110
- package/src/ui/components/primitives/ask.tsx +2 -1
- package/src/ui/components/primitives/badge.tsx +91 -30
- package/src/ui/components/primitives/button.tsx +99 -60
- package/src/ui/components/primitives/calendar.tsx +39 -39
- package/src/ui/components/primitives/card.tsx +96 -23
- package/src/ui/components/primitives/detail.tsx +2 -2
- package/src/ui/components/primitives/dialog.tsx +196 -39
- package/src/ui/components/primitives/dictionary-value.tsx +9 -14
- package/src/ui/components/primitives/dot.tsx +74 -21
- package/src/ui/components/primitives/drawer.tsx +40 -24
- package/src/ui/components/primitives/empty.tsx +3 -3
- package/src/ui/components/primitives/item.tsx +135 -79
- package/src/ui/components/primitives/menu.tsx +11 -3
- package/src/ui/components/primitives/metric-card.tsx +133 -0
- package/src/ui/components/primitives/sonner.tsx +187 -8
- package/src/ui/components/primitives/table.tsx +2 -2
- package/src/ui/docs/DocBrowser.tsx +104 -25
- package/src/ui/docs/changelog.tsx +1 -1
- package/src/ui/docs/content/accordion.md +22 -16
- package/src/ui/docs/content/action-form-card.md +8 -8
- package/src/ui/docs/content/action-form-dialog.md +9 -9
- package/src/ui/docs/content/action-form.md +28 -34
- package/src/ui/docs/content/action-list-dialog.md +11 -6
- package/src/ui/docs/content/action-list.md +64 -39
- package/src/ui/docs/content/action-trigger.md +21 -14
- package/src/ui/docs/content/action-view.md +8 -8
- package/src/ui/docs/content/actions.md +9 -9
- package/src/ui/docs/content/ai.md +3 -3
- package/src/ui/docs/content/alert.md +54 -28
- package/src/ui/docs/content/aspect-ratio.md +4 -4
- package/src/ui/docs/content/audit.md +2 -2
- package/src/ui/docs/content/auth.md +3 -3
- package/src/ui/docs/content/avatar.md +34 -14
- package/src/ui/docs/content/badge.md +21 -22
- package/src/ui/docs/content/breadcrumb.md +13 -8
- package/src/ui/docs/content/button.md +93 -15
- package/src/ui/docs/content/calendar.md +5 -5
- package/src/ui/docs/content/card.md +6 -6
- package/src/ui/docs/content/carousel.md +16 -11
- package/src/ui/docs/content/chat.md +3 -3
- package/src/ui/docs/content/checkbox.md +7 -7
- package/src/ui/docs/content/cli.md +5 -5
- package/src/ui/docs/content/collapsible.md +8 -8
- package/src/ui/docs/content/command.md +16 -8
- package/src/ui/docs/content/composer.md +2 -2
- package/src/ui/docs/content/content.md +44 -0
- package/src/ui/docs/content/copyable.md +4 -3
- package/src/ui/docs/content/customization.md +7 -7
- package/src/ui/docs/content/cycle.md +3 -3
- package/src/ui/docs/content/data-state.md +11 -12
- package/src/ui/docs/content/data.md +26 -33
- package/src/ui/docs/content/detail.md +8 -5
- package/src/ui/docs/content/dialog.md +339 -31
- package/src/ui/docs/content/dictionary-value.md +19 -18
- package/src/ui/docs/content/dock.md +3 -3
- package/src/ui/docs/content/dot.md +7 -7
- package/src/ui/docs/content/drawer.md +32 -16
- package/src/ui/docs/content/empty-value.md +2 -2
- package/src/ui/docs/content/empty.md +19 -12
- package/src/ui/docs/content/events.md +4 -4
- package/src/ui/docs/content/field.md +34 -12
- package/src/ui/docs/content/getting-started.md +1 -1
- package/src/ui/docs/content/icon-picker.md +8 -4
- package/src/ui/docs/content/input-otp.md +20 -12
- package/src/ui/docs/content/input.md +121 -9
- package/src/ui/docs/content/item.md +64 -24
- package/src/ui/docs/content/kbd.md +19 -11
- package/src/ui/docs/content/label.md +5 -3
- package/src/ui/docs/content/log.md +4 -4
- package/src/ui/docs/content/markdown.md +7 -6
- package/src/ui/docs/content/mcp.md +13 -15
- package/src/ui/docs/content/menu.md +36 -17
- package/src/ui/docs/content/metric-card.md +41 -0
- package/src/ui/docs/content/observability.md +2 -2
- package/src/ui/docs/content/page.md +93 -10
- package/src/ui/docs/content/pagination.md +22 -17
- package/src/ui/docs/content/popover.md +16 -8
- package/src/ui/docs/content/progress.md +7 -5
- package/src/ui/docs/content/queue.md +5 -5
- package/src/ui/docs/content/radio-group.md +20 -12
- package/src/ui/docs/content/router.md +11 -6
- package/src/ui/docs/content/scheduler.md +4 -5
- package/src/ui/docs/content/scroll-area.md +12 -7
- package/src/ui/docs/content/select.md +42 -29
- package/src/ui/docs/content/semantic-context.md +63 -0
- package/src/ui/docs/content/separator.md +5 -5
- package/src/ui/docs/content/sidebar.md +325 -56
- package/src/ui/docs/content/skeleton.md +5 -4
- package/src/ui/docs/content/slider.md +8 -7
- package/src/ui/docs/content/spinner.md +8 -8
- package/src/ui/docs/content/split.md +8 -5
- package/src/ui/docs/content/storage.md +6 -8
- package/src/ui/docs/content/switch.md +8 -7
- package/src/ui/docs/content/table.md +16 -6
- package/src/ui/docs/content/tabs.md +28 -14
- package/src/ui/docs/content/testing.md +9 -11
- package/src/ui/docs/content/textarea.md +5 -4
- package/src/ui/docs/content/toast.md +47 -13
- package/src/ui/docs/content/toggle.md +75 -7
- package/src/ui/docs/content/tokens.md +31 -3
- package/src/ui/docs/content/tooltip.md +19 -11
- package/src/ui/docs/content/truncate.md +7 -8
- package/src/ui/docs/content/ui.md +10 -9
- package/src/ui/docs/content/upgrading.md +7 -8
- package/src/ui/docs/doc-client.tsx +2 -2
- package/src/ui/docs/registry.tsx +580 -229
- package/src/ui/lib/semantic-context.ts +30 -0
- package/src/ui/meta.ts +278 -286
- package/src/ui/react.tsx +377 -111
- package/src/ui/theme.css +116 -0
- package/src/ui/components/primitives/alert-dialog.tsx +0 -190
- package/src/ui/docs/content/alert-dialog.md +0 -73
- package/src/ui/docs/content/button-group.md +0 -71
- package/src/ui/docs/content/confirm.md +0 -120
- package/src/ui/docs/content/input-group.md +0 -78
- package/src/ui/docs/content/toggle-group.md +0 -81
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
## Tabela de domínio
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
##
|
|
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
|
|
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
|
-
##
|
|
1
|
+
## Alternar painéis relacionados
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
|
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
|
-
##
|
|
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
|
-
##
|
|
88
|
+
## Propriedades de Tabs
|
|
85
89
|
|
|
86
|
-
|
|
|
90
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
87
91
|
|---|---|---|---|
|
|
88
|
-
| `defaultValue
|
|
89
|
-
| `value
|
|
90
|
-
| `onValueChange
|
|
91
|
-
| `size
|
|
92
|
-
| `orientation
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
8
|
-
|
|
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
|
-
##
|
|
10
|
+
## Executar o contrato em unidade
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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`,
|
|
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 —
|
|
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
|
-
##
|
|
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
|
-
##
|
|
1
|
+
## Texto com várias linhas
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
##
|
|
1
|
+
## Notificação temporária
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
-
##
|
|
25
|
+
## Ações e progresso
|
|
23
26
|
|
|
24
|
-
|
|
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
|
-
|
|
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
|
|
66
|
+
## Toaster na raiz
|
|
52
67
|
|
|
53
|
-
Monte
|
|
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
|
-
##
|
|
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
|
-
|
|
|
94
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
64
95
|
|---|---|---|---|
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
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
|
-
##
|
|
1
|
+
## Alternar um estado
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
##
|
|
65
|
+
## Propriedades de Toggle
|
|
64
66
|
|
|
65
|
-
|
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
##
|
|
1
|
+
## Informação complementar
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
18
|
+
`side` define o lado preferido; o Radix reposiciona a dica quando não há 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
|
|
35
|
+
## Provider na raiz
|
|
34
36
|
|
|
35
|
-
|
|
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
|
-
##
|
|
60
|
+
## Propriedades de TooltipProvider
|
|
58
61
|
|
|
59
|
-
|
|
|
62
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
60
63
|
|---|---|---|---|
|
|
61
|
-
| `
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
##
|
|
1
|
+
## Truncar somente quando necessário
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
##
|
|
12
|
+
## Texto sem transbordo
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
Quando há 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`
|
|
52
|
-
quando
|
|
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
|
-
|
|
8
|
-
|
|
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
|
-
|
|
13
|
-
|
|
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
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
40
|
+
- **Nativo do Opus** — nasceu aqui (os patterns de action). Não tem upstream para acompanhar; a
|
|
40
41
|
referência é esta doc.
|