@softize/opus 18.0.1 → 18.1.1
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 +105 -0
- package/PROMOTED.md +4 -5
- package/README.md +5 -4
- package/bin/cli.mjs +4 -0
- package/docs/adr/0004-page-content-state-is-composed.md +3 -0
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +6 -2
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +6 -1
- package/docs/adr/0014-structural-headers-do-not-carry-description.md +2 -2
- package/docs/adr/0015-action-size-follows-interaction-density.md +4 -3
- package/docs/adr/0017-ui-assumes-a-fixed-desktop-layout.md +54 -0
- package/docs/adr/{0012-modal-header-only-names-the-surface.md → 0018-modal-header-only-names-the-surface.md} +4 -1
- package/docs/adr/0019-productive-surfaces-use-compact-density.md +65 -0
- package/docs/code-style.md +2 -2
- package/docs/consumer-upgrade-propagation.md +1 -1
- package/docs/data-products.md +5 -3
- package/docs/protocol.md +6 -6
- package/docs/relative-unit-scale.md +9 -2
- package/docs/releasing.md +28 -4
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/references/evaluations.md +3 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +20 -4
- package/src/auth/drivers/jwt.ts +2 -1
- package/src/core/runtime.ts +32 -5
- package/src/core/types.ts +16 -7
- package/src/mcp/index.ts +13 -1
- package/src/ui/components/patterns/action-list-dialog.tsx +2 -2
- package/src/ui/components/patterns/content-header.tsx +2 -2
- package/src/ui/components/patterns/form-dialog.tsx +7 -2
- package/src/ui/components/patterns/form.tsx +1 -1
- package/src/ui/components/patterns/list.tsx +239 -47
- package/src/ui/components/patterns/presentation.tsx +7 -5
- package/src/ui/components/patterns/sidebar.tsx +1 -1
- package/src/ui/components/patterns/state-surface.tsx +2 -2
- package/src/ui/components/patterns/surface-header.tsx +4 -4
- package/src/ui/components/primitives/alert.tsx +2 -2
- package/src/ui/components/primitives/breadcrumb.tsx +1 -1
- package/src/ui/components/primitives/button-group.tsx +1 -1
- package/src/ui/components/primitives/button.tsx +3 -3
- package/src/ui/components/primitives/calendar.tsx +1 -1
- package/src/ui/components/primitives/card.tsx +1 -1
- package/src/ui/components/primitives/close-button.tsx +40 -0
- package/src/ui/components/primitives/detail.tsx +68 -30
- package/src/ui/components/primitives/dialog.tsx +36 -21
- package/src/ui/components/primitives/drawer.tsx +26 -19
- package/src/ui/components/primitives/empty-value.tsx +3 -3
- package/src/ui/components/primitives/empty.tsx +1 -1
- package/src/ui/components/primitives/field.tsx +12 -12
- package/src/ui/components/primitives/icon-picker.tsx +1 -1
- package/src/ui/components/primitives/input-group.tsx +1 -1
- package/src/ui/components/primitives/input.tsx +2 -2
- package/src/ui/components/primitives/item.tsx +5 -5
- package/src/ui/components/primitives/pagination.tsx +4 -4
- package/src/ui/components/primitives/radio-group.tsx +1 -1
- package/src/ui/components/primitives/select.tsx +3 -3
- package/src/ui/components/primitives/table.tsx +26 -17
- package/src/ui/components/primitives/tabs.tsx +80 -23
- package/src/ui/components/primitives/textarea.tsx +1 -1
- package/src/ui/components/primitives/toggle-group.tsx +9 -2
- package/src/ui/docs/content/action-form-dialog.md +11 -4
- package/src/ui/docs/content/action-form.md +13 -3
- package/src/ui/docs/content/action-list-dialog.md +5 -7
- package/src/ui/docs/content/action-list.md +53 -5
- package/src/ui/docs/content/action-trigger.md +9 -5
- package/src/ui/docs/content/action-view.md +12 -8
- package/src/ui/docs/content/actions.md +36 -13
- package/src/ui/docs/content/ai.md +26 -7
- package/src/ui/docs/content/alert.md +6 -3
- package/src/ui/docs/content/aspect-ratio.md +2 -2
- package/src/ui/docs/content/auth.md +25 -10
- package/src/ui/docs/content/avatar.md +1 -1
- package/src/ui/docs/content/badge.md +2 -2
- package/src/ui/docs/content/breadcrumb.md +3 -2
- package/src/ui/docs/content/button.md +33 -8
- package/src/ui/docs/content/calendar.md +1 -1
- package/src/ui/docs/content/card.md +1 -1
- package/src/ui/docs/content/carousel.md +14 -3
- package/src/ui/docs/content/chat.md +1 -1
- package/src/ui/docs/content/cli.md +13 -7
- package/src/ui/docs/content/command.md +34 -2
- package/src/ui/docs/content/composer.md +1 -1
- package/src/ui/docs/content/content.md +5 -4
- package/src/ui/docs/content/customization.md +12 -2
- package/src/ui/docs/content/cycle.md +7 -5
- package/src/ui/docs/content/data-state.md +6 -5
- package/src/ui/docs/content/data.md +3 -3
- package/src/ui/docs/content/detail.md +12 -10
- package/src/ui/docs/content/dialog.md +14 -7
- package/src/ui/docs/content/dictionary-value.md +1 -1
- package/src/ui/docs/content/dock.md +23 -2
- package/src/ui/docs/content/dot.md +0 -2
- package/src/ui/docs/content/drawer.md +7 -4
- package/src/ui/docs/content/empty-value.md +4 -4
- package/src/ui/docs/content/empty.md +1 -4
- package/src/ui/docs/content/events.md +1 -1
- package/src/ui/docs/content/field.md +21 -12
- package/src/ui/docs/content/getting-started.md +4 -2
- package/src/ui/docs/content/icon-picker.md +2 -2
- package/src/ui/docs/content/input-otp.md +2 -0
- package/src/ui/docs/content/input.md +2 -3
- package/src/ui/docs/content/item.md +6 -3
- package/src/ui/docs/content/kbd.md +2 -1
- package/src/ui/docs/content/mcp.md +10 -4
- package/src/ui/docs/content/menu.md +27 -0
- package/src/ui/docs/content/page.md +20 -6
- package/src/ui/docs/content/pagination.md +9 -2
- package/src/ui/docs/content/popover.md +2 -2
- package/src/ui/docs/content/presentation.md +48 -47
- package/src/ui/docs/content/progress.md +2 -6
- package/src/ui/docs/content/runtime.md +8 -5
- package/src/ui/docs/content/scheduler.md +1 -1
- package/src/ui/docs/content/select.md +13 -8
- package/src/ui/docs/content/sidebar.md +3 -2
- package/src/ui/docs/content/skeleton.md +1 -1
- package/src/ui/docs/content/slider.md +4 -4
- package/src/ui/docs/content/spinner.md +3 -3
- package/src/ui/docs/content/tabs.md +22 -12
- package/src/ui/docs/content/testing.md +4 -2
- package/src/ui/docs/content/toast.md +5 -6
- package/src/ui/docs/content/toggle.md +37 -0
- package/src/ui/docs/content/tokens.md +45 -2
- package/src/ui/docs/content/tooltip.md +4 -3
- package/src/ui/docs/content/truncate.md +3 -2
- package/src/ui/docs/content/ui.md +3 -1
- package/src/ui/docs/content/upgrading.md +43 -13
- package/src/ui/docs/doc-client.tsx +1 -1
- package/src/ui/docs/registry.tsx +30 -5
- package/src/ui/meta.ts +4 -4
- package/src/ui/react.tsx +1 -0
- package/src/ui/theme.css +3 -0
|
@@ -92,7 +92,17 @@ Na composição explícita, combine somente as regiões necessárias. Este exemp
|
|
|
92
92
|
uma ação global e o intro para o título:
|
|
93
93
|
|
|
94
94
|
```tsx preview col
|
|
95
|
-
<PageShell
|
|
95
|
+
<PageShell
|
|
96
|
+
navigation={
|
|
97
|
+
<Breadcrumb>
|
|
98
|
+
<BreadcrumbList>
|
|
99
|
+
<BreadcrumbItem>Vendas</BreadcrumbItem>
|
|
100
|
+
<BreadcrumbSeparator />
|
|
101
|
+
<BreadcrumbPage>Clientes</BreadcrumbPage>
|
|
102
|
+
</BreadcrumbList>
|
|
103
|
+
</Breadcrumb>
|
|
104
|
+
}
|
|
105
|
+
>
|
|
96
106
|
<Page>
|
|
97
107
|
<PageHeader>
|
|
98
108
|
<PageActions>
|
|
@@ -172,7 +182,7 @@ e, sem `title`, valem `errorMessage` e `emptyMessage`.
|
|
|
172
182
|
status="empty"
|
|
173
183
|
title="Nenhum relatório"
|
|
174
184
|
description="Crie o primeiro relatório para começar."
|
|
175
|
-
action={<Button>
|
|
185
|
+
action={<Button>Criar relatório</Button>}
|
|
176
186
|
/>
|
|
177
187
|
</Page>
|
|
178
188
|
```
|
|
@@ -185,7 +195,7 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
|
|
|
185
195
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
186
196
|
| ----------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------- |
|
|
187
197
|
| `title` | `ReactNode` | | O h1 da página. |
|
|
188
|
-
| `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho
|
|
198
|
+
| `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho. |
|
|
189
199
|
| `className` | `string` | `max-w-7xl` | Classes do container para substituir o teto padrão de `80rem`. |
|
|
190
200
|
| `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
|
|
191
201
|
|
|
@@ -204,7 +214,7 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
|
|
|
204
214
|
|
|
205
215
|
| Propriedade | Tipo | Descrição |
|
|
206
216
|
| ----------- | ----------------------------- | --------------------------------------------------------------------- |
|
|
207
|
-
| `children` | `ReactNode` |
|
|
217
|
+
| `children` | `ReactNode` | `PageBack` ou `PageNavigation`, título introdutório e, quando necessário, ações ligadas à introdução. |
|
|
208
218
|
| `className` | `string` | Classes adicionais da região introdutória. |
|
|
209
219
|
| demais | Atributos de `HTMLDivElement` | Atributos nativos repassados à região introdutória. |
|
|
210
220
|
|
|
@@ -212,15 +222,19 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
|
|
|
212
222
|
|
|
213
223
|
| Propriedade | Tipo | Descrição |
|
|
214
224
|
| ----------- | ----------- | ---------------------------------------------------------------------------------------- |
|
|
215
|
-
| `className` | `string` | Classes adicionais da região externa do cabeçalho
|
|
225
|
+
| `className` | `string` | Classes adicionais da região externa do cabeçalho, fora de `PageShell`. |
|
|
216
226
|
| `children` | `ReactNode` | `PageBack` ou `PageNavigation`, `PageActions` e, fora do shell, um `PageTitle` opcional. |
|
|
227
|
+
| demais | Atributos de `HTMLDivElement` | Atributos nativos repassados à região externa do cabeçalho, fora de `PageShell`. |
|
|
228
|
+
|
|
229
|
+
Dentro de `PageShell`, `PageHeader` não renderiza uma região própria: devolve somente os filhos,
|
|
230
|
+
que o shell projeta na barra, e ignora `className` e os demais atributos.
|
|
217
231
|
|
|
218
232
|
## Propriedades de PageBack
|
|
219
233
|
|
|
220
234
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
221
235
|
| ------------ | -------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------ |
|
|
222
236
|
| `href` | `string` | obrigatório | Destino explícito da página pai. Sem ele o retorno não é tabulável nem tem nome acessível. |
|
|
223
|
-
| `children` | `ReactNode` |
|
|
237
|
+
| `children` | `ReactNode` | obrigatório | Nome do destino pai usado no rótulo acessível e no tooltip. |
|
|
224
238
|
| `aria-label` | `string` | `Voltar para {children}` | Nome acessível; informe-o quando `children` não for texto simples. |
|
|
225
239
|
| `onClick` | `MouseEventHandler<HTMLAnchorElement>` | | Integração opcional com o roteador do consumidor, junto do `href`, nunca no lugar dele. |
|
|
226
240
|
| `className` | `string` | | Classes adicionais do link renderizado como botão `ghost`. |
|
|
@@ -131,7 +131,7 @@ render(
|
|
|
131
131
|
| `page` | `number` | | Número usado como conteúdo, quando `children` não é informado, e no nome acessível “Página N”. |
|
|
132
132
|
| `isActive` | `boolean` | `false` | Marca a página atual com `aria-current="page"` e tratamento `outline`. |
|
|
133
133
|
| `href` | `string` | | Renderiza um `<a>`. Sem `href`, o componente usa `<button>` e aceita `onClick` e `disabled`. |
|
|
134
|
-
| `size` | `ButtonProps['size']` | `'default'` | A escala única, via `Button`.
|
|
134
|
+
| `size` | `ButtonProps['size']` | `'default'` | A escala única, via `Button`. Os `icon-*` são quadrados. Nos tamanhos textuais, a altura fica fixa em 2.25rem com largura mínima quadrada que cresce para números longos, então `size="sm"` não reduz a altura; para uma barra mais baixa, use um `icon-*` ou ajuste por `className` (ex.: `h-7 min-w-7 text-xs`). |
|
|
135
135
|
|
|
136
136
|
## Propriedades de PaginationPrevious e PaginationNext
|
|
137
137
|
|
|
@@ -139,5 +139,12 @@ render(
|
|
|
139
139
|
|---|---|---|---|
|
|
140
140
|
| `label` | `string` | `'Página anterior'` ou `'Próxima página'` | Nome acessível e texto visível da ação. |
|
|
141
141
|
| `iconOnly` | `boolean` | `false` | Exibe somente a seta; `label` continua disponível para leitura assistiva. |
|
|
142
|
-
| `size` | `ButtonProps['size']` | `'default'`; `'icon'` com `iconOnly` | A escala única; `icon-sm` para o rodapé denso. |
|
|
142
|
+
| `size` | `ButtonProps['size']` | `'default'`; `'icon'` com `iconOnly` | A escala única; `icon-sm` para o rodapé denso. Sem `iconOnly`, a altura permanece 2.25rem em qualquer tamanho textual, como em `PaginationLink`. |
|
|
143
143
|
| `iconClassName` | `string` | | Classes aplicadas ao ícone da seta, quando o glifo da escala não servir. |
|
|
144
|
+
|
|
145
|
+
## Propriedades de PaginationEllipsis
|
|
146
|
+
|
|
147
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
148
|
+
|---|---|---|---|
|
|
149
|
+
| `size` | `'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg'` | `'icon'` | Quadrado da escala única; use o mesmo tamanho das setas ao lado. |
|
|
150
|
+
| `className` | `string` | | Classes adicionais aplicadas à elipse. |
|
|
@@ -29,13 +29,13 @@ detalhes.
|
|
|
29
29
|
|
|
30
30
|
```tsx preview
|
|
31
31
|
<Popover>
|
|
32
|
-
<PopoverTrigger asChild><Button variant="ghost">
|
|
32
|
+
<PopoverTrigger asChild><Button variant="ghost">Início</Button></PopoverTrigger>
|
|
33
33
|
<PopoverContent align="start" className="w-56">
|
|
34
34
|
<PopoverDescription>Alinhado à borda esquerda do gatilho.</PopoverDescription>
|
|
35
35
|
</PopoverContent>
|
|
36
36
|
</Popover>
|
|
37
37
|
<Popover>
|
|
38
|
-
<PopoverTrigger asChild><Button variant="ghost">
|
|
38
|
+
<PopoverTrigger asChild><Button variant="ghost">Fim</Button></PopoverTrigger>
|
|
39
39
|
<PopoverContent align="end" className="w-56">
|
|
40
40
|
<PopoverDescription>Alinhado à borda direita do gatilho.</PopoverDescription>
|
|
41
41
|
</PopoverContent>
|
|
@@ -5,12 +5,14 @@ cabeçalho, body e rodapé.
|
|
|
5
5
|
Dialog e Drawer mantêm no cabeçalho a ordem horizontal de navegação ou retorno, título e ações.
|
|
6
6
|
O retorno aparece em uma surface modal somente
|
|
7
7
|
quando ela foi aberta sobre outro Dialog ou Drawer; a Page ao fundo sustenta o modal, mas não cria
|
|
8
|
-
uma etapa de navegação. Formulários modais
|
|
9
|
-
|
|
8
|
+
uma etapa de navegação. Formulários modais dimensionam o footer pelo conteúdo, com `Cancelar` em
|
|
9
|
+
`ghost` e a ação principal sólida.
|
|
10
10
|
Em Page hospedada por `PageShell`, a barra concentra navegação e ações globais. Uma Presentation
|
|
11
11
|
de listagem materializa título e comandos de header no `Content` que envolve o `ActionList`; assim
|
|
12
|
-
a criação permanece próxima da coleção. Esses comandos usam `default
|
|
13
|
-
|
|
12
|
+
a criação permanece próxima da coleção. Esses comandos usam o tamanho `default`: o que abre outra
|
|
13
|
+
Presentation é um `Button` na variante padrão (`solid`), e uma action `simple` vira um
|
|
14
|
+
`ActionTrigger` na variante `ghost`. Nas demais Presentations, o título abre o conteúdo em
|
|
15
|
+
`PageIntro` e os comandos da superfície seguem a mesma regra.
|
|
14
16
|
|
|
15
17
|
Use esse padrão quando uma lista puder abrir um detalhe lateral, quando a mesma edição precisar
|
|
16
18
|
funcionar em modal e em rota própria ou quando um fluxo começar compacto e crescer sem ganhar uma
|
|
@@ -22,25 +24,20 @@ compõe `PageBody` e, quando necessário, `PageFooter`. Para uma action `list`,
|
|
|
22
24
|
`Content + ActionList`; o header da coleção recebe o título e os comandos declarados no placement
|
|
23
25
|
`header`. Dialog e Drawer continuam usando o header da própria superfície.
|
|
24
26
|
Os comandos da coleção ficam no extremo oposto ao título e permanecem textuais, mesmo quando a
|
|
25
|
-
action declara um ícone. A criação usa `Criar recurso`, sem ícone, em um
|
|
27
|
+
action declara um ícone. A criação usa `Criar recurso`, sem ícone, em um `Button` na variante
|
|
28
|
+
padrão (`solid`) e no tamanho `default`.
|
|
26
29
|
Não envolva a Presentation em um card para simular a página; valide proporção, rolagem e ações no
|
|
27
30
|
shell que efetivamente hospeda a rota.
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
name: "workspace.update",
|
|
32
|
-
kind: "form",
|
|
33
|
-
label: "Editar workspace",
|
|
34
|
-
input: z.object({ name: z.string() }),
|
|
35
|
-
output: z.object({ id: z.string() }),
|
|
36
|
-
fields: { name: { label: "Nome" } },
|
|
37
|
-
});
|
|
32
|
+
O exemplo declara a Presentation sobre um contrato de formulário e alterna a superfície. O
|
|
33
|
+
`DocBrowserActionProvider` simula o cliente de actions; na aplicação, esse papel é do provider real.
|
|
38
34
|
|
|
35
|
+
```tsx live
|
|
39
36
|
const workspacePresentation = definePresentation({
|
|
40
37
|
schemaVersion: 1,
|
|
41
|
-
id: "workspace.
|
|
42
|
-
title: "
|
|
43
|
-
body: { action:
|
|
38
|
+
id: "workspace.create",
|
|
39
|
+
title: "Criar workspace",
|
|
40
|
+
body: { action: docWorkspaceCreate.name },
|
|
44
41
|
});
|
|
45
42
|
|
|
46
43
|
function Example() {
|
|
@@ -55,36 +52,38 @@ function Example() {
|
|
|
55
52
|
);
|
|
56
53
|
|
|
57
54
|
return (
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
55
|
+
<DocBrowserActionProvider>
|
|
56
|
+
<div className="space-y-4">
|
|
57
|
+
<ButtonGroup mode="spaced">
|
|
58
|
+
{["page", "dialog", "drawer"].map((value) => (
|
|
59
|
+
<Button
|
|
60
|
+
key={value}
|
|
61
|
+
size="sm"
|
|
62
|
+
variant={invocation.surface === value ? "solid" : "outline"}
|
|
63
|
+
onClick={() => {
|
|
64
|
+
setInvocation({ ...invocation, surface: value });
|
|
65
|
+
setOpen(true);
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
{value}
|
|
69
|
+
</Button>
|
|
70
|
+
))}
|
|
71
|
+
</ButtonGroup>
|
|
72
|
+
|
|
73
|
+
<Presentation
|
|
74
|
+
definition={workspacePresentation}
|
|
75
|
+
definitions={[workspacePresentation]}
|
|
76
|
+
actions={{ [docWorkspaceCreate.name]: docWorkspaceCreate }}
|
|
77
|
+
invocation={invocation}
|
|
78
|
+
open={invocation.surface === "page" || open}
|
|
79
|
+
onOpenChange={setOpen}
|
|
80
|
+
onInvocationChange={(next) => {
|
|
81
|
+
if (next) setInvocation(next);
|
|
82
|
+
else setOpen(false);
|
|
83
|
+
}}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
</DocBrowserActionProvider>
|
|
88
87
|
);
|
|
89
88
|
}
|
|
90
89
|
|
|
@@ -174,6 +173,8 @@ no manifest e concentre a inspeção na Lens em vez de criar um launcher flutuan
|
|
|
174
173
|
| `bindingContext` | `PresentationBindingContext` | | Rota, item, seleção, sessão e resultado disponíveis. |
|
|
175
174
|
| `onInvocationChange` | `(next: PresentationInvocation \| null) => void` | | Recebe navegação, retorno e fechamento. |
|
|
176
175
|
| `onRefresh` | `(action: string \| null) => void` | | Recebe invalidações declaradas após sucesso. |
|
|
176
|
+
| `listState` | `ActionListState` | | Recorte controlado da action `list` do body, quando a aplicação o sincroniza com a URL. |
|
|
177
|
+
| `onListStateChange` | `(state: ActionListState) => void` | | Recebe cada mudança de recorte ou exibição da lista do body, como busca, filtros, período e página. |
|
|
177
178
|
| `open` | `boolean` | `true` | Estado controlado de Dialog ou Drawer. |
|
|
178
179
|
| `onOpenChange` | `(open: boolean) => void` | | Notifica abertura e fechamento da superfície modal. |
|
|
179
180
|
| `className` | `string` | | Classes adicionais da superfície. |
|
|
@@ -29,13 +29,9 @@ render(
|
|
|
29
29
|
<span className="text-muted-foreground">{step}%</span>
|
|
30
30
|
</div>
|
|
31
31
|
<Progress value={step} />
|
|
32
|
-
<
|
|
33
|
-
type="button"
|
|
34
|
-
onClick={advance}
|
|
35
|
-
className="rounded-md border px-3 py-1.5 text-sm hover:bg-muted"
|
|
36
|
-
>
|
|
32
|
+
<Button variant="outline" size="sm" onClick={advance}>
|
|
37
33
|
Avançar etapa
|
|
38
|
-
</
|
|
34
|
+
</Button>
|
|
39
35
|
</div>,
|
|
40
36
|
)
|
|
41
37
|
```
|
|
@@ -38,16 +38,17 @@ await runtime.start()
|
|
|
38
38
|
|
|
39
39
|
| Capacidade | Fornece | Driver pronto |
|
|
40
40
|
|---|---|---|
|
|
41
|
-
| `server` | monta as actions (HTTP) | `fastifyServer` — `@softize/opus/server/fastify` |
|
|
41
|
+
| `server` | monta as actions (HTTP) | `fastifyServer` — `@softize/opus/server/fastify` · `nodeServer` — `…/server/node` |
|
|
42
42
|
| `data` | `ctx.db` + drift-check + CRUD | `kyselyData`, `kyselyRepo`, `crudActions` — `@softize/opus/data/kysely` |
|
|
43
43
|
| `auth` | `user`/`tenantId`/`can` do contexto | `jwtAuth` — `…/auth/jwt` · `betterAuthSession` — `…/auth/better-auth` |
|
|
44
44
|
| `audit` | trilha por execução de action | `pgAudit` — `…/audit/pg` · `consoleAudit` — `…/audit/console` |
|
|
45
|
-
| `
|
|
46
|
-
| `observability` | span ativo + propagação de trace |
|
|
45
|
+
| `logger` | `ctx.log` estruturado | `pinoLogger` — `@softize/opus/log/pino` |
|
|
46
|
+
| `observability` | span ativo + propagação de trace | `openTelemetryObservability` — `@softize/opus/observability/opentelemetry` |
|
|
47
47
|
| `eventBus` | `ctx.emit` + **reactions** | `mittEvents` — `@softize/opus/events/mitt` |
|
|
48
48
|
| `queue` | jobs em background | `bullmqQueue` — `@softize/opus/queue/bullmq` |
|
|
49
49
|
| `scheduler` | **schedules** (cron/intervalo) | `nodeCronScheduler` — `@softize/opus/scheduler/node-cron` |
|
|
50
50
|
| `storage` | `ctx.storage` (arquivos) | `fsStorage` — `…/storage/fs` · `s3Storage` — `…/storage/s3` |
|
|
51
|
+
| `cache` | `ctx.cache` (leitura, experimental) | `memoryCache` — `@softize/opus/cache/memory` |
|
|
51
52
|
| `ai` | `ctx.ai` (complete/extract) | `anthropicAi` — `@softize/opus/ai/anthropic` |
|
|
52
53
|
| `client` | chamar actions de fora (stubs) | `fetchClient` — `@softize/opus/client/fetch` |
|
|
53
54
|
|
|
@@ -61,7 +62,7 @@ Fora do runtime, mas parte do protocolo: o harness de teste (`runAction`/`testCo
|
|
|
61
62
|
> e o handler decide como degradar.
|
|
62
63
|
|
|
63
64
|
`user`/`tenantId`/`can` (auth) · `db` (data) · `log` (logger) · `emit` (eventBus) ·
|
|
64
|
-
`storage` (storage) · `ai` (ai) · `provenance` (quem disparou: http, schedule,
|
|
65
|
+
`storage` (storage) · `cache` (cache) · `ai` (ai) · `provenance` (quem disparou: http, schedule,
|
|
65
66
|
reaction…) · `trace` (quando configurado) · `meta`.
|
|
66
67
|
|
|
67
68
|
O core não depende de OpenTelemetry. O `ObservabilityAdapter` envolve actions e reactions
|
|
@@ -85,7 +86,9 @@ representa span de erro. Reactions usam `resultKind: 'void'` e rejeitam em falha
|
|
|
85
86
|
> tempo dispara schedule (que executa uma action, com provenance própria).
|
|
86
87
|
|
|
87
88
|
Declarados como as actions e registrados no mesmo `runtime.register` — o manifest
|
|
88
|
-
projeta os três
|
|
89
|
+
projeta os três. `opus introspect` lista reactions, schedules e o wiring entre eles, mas por
|
|
90
|
+
enquanto só reconhece actions declaradas com `defineAction`: as do split `defineContract` +
|
|
91
|
+
`bindAction` ficam de fora do modelo que ele monta.
|
|
89
92
|
|
|
90
93
|
## Referência profunda
|
|
91
94
|
|
|
@@ -19,7 +19,7 @@ interface ScheduleDef {
|
|
|
19
19
|
action: string // action do registry, executada quando dispara
|
|
20
20
|
cron?: string // '0 9 * * *' (9h todo dia)
|
|
21
21
|
every?: string // '1h', '30m', '15s' — atalho de intervalo
|
|
22
|
-
timezone?: string // IANA, ex.: 'America/Sao_Paulo' (
|
|
22
|
+
timezone?: string // IANA, ex.: 'America/Sao_Paulo' (sem ele: hora local do processo)
|
|
23
23
|
input?: unknown | (() => unknown | Promise<unknown>) // estático ou dinâmico
|
|
24
24
|
enabled?: boolean
|
|
25
25
|
}
|
|
@@ -26,8 +26,9 @@ render(
|
|
|
26
26
|
|
|
27
27
|
## Lista pesquisável
|
|
28
28
|
|
|
29
|
-
Use `searchable` quando a quantidade ou os rótulos dificultarem encontrar uma opção. O
|
|
30
|
-
|
|
29
|
+
Use `searchable` quando a quantidade ou os rótulos dificultarem encontrar uma opção. O gatilho
|
|
30
|
+
continua exibindo a escolha; a busca aparece em uma linha no topo da lista e filtra `label`, `hint`
|
|
31
|
+
e `value`.
|
|
31
32
|
|
|
32
33
|
```tsx preview col md
|
|
33
34
|
const [issue, setIssue] = useState('')
|
|
@@ -40,7 +41,7 @@ render(
|
|
|
40
41
|
id="issue"
|
|
41
42
|
value={issue}
|
|
42
43
|
onChange={setIssue}
|
|
43
|
-
placeholder="
|
|
44
|
+
placeholder="Selecione a issue"
|
|
44
45
|
options={[
|
|
45
46
|
{ value: '412', label: 'Ajustar microcopy do handoff', hint: 'SOF-412' },
|
|
46
47
|
{ value: '418', label: 'Preview da sessão cai após deploy', hint: 'SOF-418' },
|
|
@@ -323,7 +324,7 @@ render(
|
|
|
323
324
|
{ value: 'gra-7', label: 'Filtro por filial', hint: 'GRA-7' },
|
|
324
325
|
]}
|
|
325
326
|
trailing={
|
|
326
|
-
<Button variant="ghost" size="icon-xs">
|
|
327
|
+
<Button variant="ghost" size="icon-xs" aria-label="Abrir tarefa">
|
|
327
328
|
<FileText />
|
|
328
329
|
</Button>
|
|
329
330
|
}
|
|
@@ -338,12 +339,12 @@ render(
|
|
|
338
339
|
| `options` | `SelectOption[]` | | As opções: `{ value, label, hint?, content?, triggerLabel?, group?, disabled? }`. |
|
|
339
340
|
| `value` | `string \| string[]` | | O selecionado: string no single, string[] no multiple. |
|
|
340
341
|
| `onChange` | `(value: string) => void \| (value: string[]) => void` | | Chamado ao escolher (e ao remover chip, no multiple) — a assinatura segue o modo. |
|
|
341
|
-
| `native` | `boolean` | `false` | Renderiza o `<select>` do sistema. Exclui busca,
|
|
342
|
-
| `searchable` | `boolean` | `false` |
|
|
342
|
+
| `native` | `boolean` | `false` | Renderiza o `<select>` do sistema. Exclui busca, seleção múltipla e variantes visuais (o browser é quem desenha a lista). |
|
|
343
|
+
| `searchable` | `boolean` | `false` | Acrescenta uma linha de busca no topo da lista, que filtra as opções enquanto a pessoa digita. O gatilho continua exibindo a escolha. |
|
|
343
344
|
| `multiple` | `boolean` | `false` | Chips removíveis, lista que permanece aberta e Selecionar tudo. |
|
|
344
|
-
| `variant` | `'default' \| 'ghost'` | `'default'` | `ghost` = sem
|
|
345
|
+
| `variant` | `'default' \| 'outline' \| 'ghost'` | `'default'` | `outline` = compacto com borda; `ghost` = compacto sem borda nem fundo, para barra do composer. |
|
|
345
346
|
| `placeholder` | `string` | `'Selecione…'` | Texto do campo vazio. |
|
|
346
|
-
| `searchPlaceholder` | `string` | | Placeholder
|
|
347
|
+
| `searchPlaceholder` | `string` | `'Buscar…'` | Placeholder da linha de busca dentro da lista. |
|
|
347
348
|
| `emptyText` | `string` | `'Nada encontrado.'` | Mensagem quando a busca não acha nada. |
|
|
348
349
|
| `onSearch` | `(query: string) => void` | | Busca server-side (debounced, ao abrir e ao digitar): desliga o filtro do cmdk — o pai atualiza `options`. |
|
|
349
350
|
| `loading` | `boolean` | | Mostra Buscando… enquanto o fetch corre (use com `onSearch`). |
|
|
@@ -351,6 +352,10 @@ render(
|
|
|
351
352
|
| `icon` | `React.ReactNode` | | Ícone leading DENTRO do controle (decorativo) — herda `size-4` e o tom muted. |
|
|
352
353
|
| `trailing` | `React.ReactNode` | | Ação custom no FIM do controle (antes do chevron) — o clique não abre a lista. |
|
|
353
354
|
| `size` | `'default' \| 'sm'` | `'default'` | Altura: default (h-9, a do Input e do Button) ou sm (h-8) para toolbar densa. |
|
|
355
|
+
| `shape` | `'default' \| 'pill'` | `'default'` | Geometria do controle; `pill` arredonda as extremidades e preserva a variante visual. |
|
|
354
356
|
| `disabled` | `boolean` | `false` | Esmaece e trava o controle. |
|
|
355
357
|
| `id` | `string` | | Vai para o campo — para parear com o `htmlFor` do Label. |
|
|
358
|
+
| `aria-label` | `string` | | Nome acessível quando não há `Label` associado. |
|
|
359
|
+
| `aria-invalid` | `boolean` | | Comunica e apresenta o estado inválido. |
|
|
360
|
+
| `aria-describedby` | `string` | | Liga o controle a uma ajuda ou mensagem de erro. |
|
|
356
361
|
| `className` | `string` | | Classes da raiz do controle, incluindo campo, ícones e ações, em todos os modos. |
|
|
@@ -63,7 +63,7 @@ uma sidebar fixa, redimensionável ou recolhida.
|
|
|
63
63
|
| `PaneFooter` | Mantém ações persistentes no rodapé. |
|
|
64
64
|
| `SidebarNav` | Apresenta e controla os destinos de navegação. |
|
|
65
65
|
|
|
66
|
-
`PaneContent`
|
|
66
|
+
`PaneContent` continua exportado como alias depreciado de `PaneBody`. Código novo usa
|
|
67
67
|
`PaneBody`.
|
|
68
68
|
|
|
69
69
|
## Escolher a navegação
|
|
@@ -138,7 +138,8 @@ páginas são folhas. Um grupo começa aberto e volta a abrir quando contém a p
|
|
|
138
138
|
|
|
139
139
|
`collapsed` pertence à `Sidebar`. Nesse estado, `SidebarItem` e `SidebarNav` mantêm
|
|
140
140
|
somente os ícones e expõem os rótulos em tooltips. Por isso, todo destino que aparece no modo
|
|
141
|
-
recolhido precisa de um ícone reconhecível e de um `label` completo.
|
|
141
|
+
recolhido precisa de um ícone reconhecível e de um `label` completo. `SidebarNav` já monta o
|
|
142
|
+
`TooltipProvider`; um `SidebarItem` recolhido fora dele depende do provider na raiz do aplicativo.
|
|
142
143
|
|
|
143
144
|
O slot de ícone do `SidebarItem` ocupa `1rem` nos dois estados e normaliza SVGs para essa medida.
|
|
144
145
|
O consumidor escolhe o símbolo e sua cor sem precisar repetir largura ou altura em ícones SVG.
|
|
@@ -15,7 +15,7 @@ avatares e barras com dimensões próximas às linhas de texto esperadas.
|
|
|
15
15
|
|
|
16
16
|
## Card em carregamento
|
|
17
17
|
|
|
18
|
-
O esqueleto reproduz o layout final do card — título, descrição, conteúdo e ações — para tela não pular quando os dados chegarem.
|
|
18
|
+
O esqueleto reproduz o layout final do card — título, descrição, conteúdo e ações — para a tela não pular quando os dados chegarem.
|
|
19
19
|
|
|
20
20
|
```tsx preview col
|
|
21
21
|
<Card>
|
|
@@ -15,9 +15,9 @@ representa um único controle. `min`, `max` e `step` delimitam os valores dispon
|
|
|
15
15
|
const [parallelism, setParallelism] = useState([4])
|
|
16
16
|
|
|
17
17
|
render(
|
|
18
|
-
<div className="grid w-full gap-3">
|
|
18
|
+
<div role="group" aria-labelledby="parallelism-label" className="grid w-full gap-3">
|
|
19
19
|
<div className="flex items-center justify-between">
|
|
20
|
-
<Label>Sessões em paralelo</Label>
|
|
20
|
+
<Label id="parallelism-label">Sessões em paralelo</Label>
|
|
21
21
|
<span className="text-sm text-muted-foreground">{parallelism[0]}</span>
|
|
22
22
|
</div>
|
|
23
23
|
<Slider value={parallelism} onValueChange={setParallelism} min={1} max={8} step={1} />
|
|
@@ -33,9 +33,9 @@ Dois números em `value` criam um intervalo selecionável entre dois controles.
|
|
|
33
33
|
const [budget, setBudget] = useState([20, 60])
|
|
34
34
|
|
|
35
35
|
render(
|
|
36
|
-
<div className="grid w-full gap-3">
|
|
36
|
+
<div role="group" aria-labelledby="budget-label" className="grid w-full gap-3">
|
|
37
37
|
<div className="flex items-center justify-between">
|
|
38
|
-
<Label>Custo estimado (US$)</Label>
|
|
38
|
+
<Label id="budget-label">Custo estimado (US$)</Label>
|
|
39
39
|
<span className="text-sm text-muted-foreground">{budget[0]} – {budget[1]}</span>
|
|
40
40
|
</div>
|
|
41
41
|
<Slider value={budget} onValueChange={setBudget} min={0} max={100} step={5} />
|
|
@@ -14,11 +14,11 @@ de um `lg`. O ícone é decorativo; quem nomeia a espera é o contêiner (`role=
|
|
|
14
14
|
|
|
15
15
|
## No botão
|
|
16
16
|
|
|
17
|
-
Durante uma ação,
|
|
18
|
-
|
|
17
|
+
Durante uma ação, use `busy` no `Button` com um rótulo que descreva o andamento. O botão fica
|
|
18
|
+
desabilitado e o spinner ocupa o lugar do ícone, no glifo do tamanho do botão.
|
|
19
19
|
|
|
20
20
|
```tsx preview
|
|
21
|
-
<Button
|
|
21
|
+
<Button busy>Publicando…</Button>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Em carga de conteúdo
|
|
@@ -4,12 +4,15 @@ Use `Tabs` para alternar painéis relacionados no mesmo contexto. O `value` de c
|
|
|
4
4
|
corresponde ao `TabsContent` que ele abre. `defaultValue` define a aba inicial no modo não
|
|
5
5
|
controlado.
|
|
6
6
|
|
|
7
|
+
`icon` posiciona um ícone decorativo antes do rótulo e normaliza SVGs para `1rem`. Quando a aba
|
|
8
|
+
mostrar somente o ícone, declare `aria-label` para preservar seu nome acessível.
|
|
9
|
+
|
|
7
10
|
```tsx preview col
|
|
8
11
|
<Tabs defaultValue="sessions">
|
|
9
12
|
<TabsList>
|
|
10
|
-
<TabsTrigger value="overview">Visão geral</TabsTrigger>
|
|
11
|
-
<TabsTrigger value="sessions">Sessões</TabsTrigger>
|
|
12
|
-
<TabsTrigger value="skills">Skills</TabsTrigger>
|
|
13
|
+
<TabsTrigger value="overview" icon={<LayoutDashboard />}>Visão geral</TabsTrigger>
|
|
14
|
+
<TabsTrigger value="sessions" icon={<History />}>Sessões</TabsTrigger>
|
|
15
|
+
<TabsTrigger value="skills" icon={<Settings />}>Skills</TabsTrigger>
|
|
13
16
|
</TabsList>
|
|
14
17
|
<TabsContent value="overview">
|
|
15
18
|
<p className="text-sm text-muted-foreground">Resumo do workspace Empresa X.</p>
|
|
@@ -25,8 +28,14 @@ controlado.
|
|
|
25
28
|
|
|
26
29
|
## Variante line
|
|
27
30
|
|
|
28
|
-
Use `variant="line"` em `TabsList` quando a
|
|
29
|
-
cabeçalho.
|
|
31
|
+
Use `variant="line"` em `TabsList` quando a navegação precisar de uma linha-base, como em um
|
|
32
|
+
cabeçalho. Na orientação horizontal, a lista ocupa toda a largura disponível e a aba ativa é
|
|
33
|
+
marcada sobre essa linha, em vez de usar uma superfície preenchida. Dentro de `DrawerBody`, a
|
|
34
|
+
linha atravessa o gutter até as bordas do drawer sem deslocar os rótulos. O mesmo comportamento
|
|
35
|
+
vale para `DialogBody`.
|
|
36
|
+
Os itens removem o padding horizontal, usam `0.75rem` de padding vertical e preservam `1.25rem`
|
|
37
|
+
de espaço entre si. Nessa orientação, a altura é definida pelo conteúdo para que o padding
|
|
38
|
+
vertical amplie a área interativa.
|
|
30
39
|
|
|
31
40
|
```tsx preview col
|
|
32
41
|
<Tabs defaultValue="agents">
|
|
@@ -49,8 +58,8 @@ cabeçalho. A aba ativa é marcada por uma linha em vez de uma superfície preen
|
|
|
49
58
|
|
|
50
59
|
## Vertical
|
|
51
60
|
|
|
52
|
-
Com `orientation="vertical"`, a lista forma uma coluna
|
|
53
|
-
lateral do gatilho.
|
|
61
|
+
Com `orientation="vertical"`, a lista forma uma coluna. O exemplo usa a variante padrão; com
|
|
62
|
+
`variant="line"`, a marca da aba ativa passa para a lateral do gatilho.
|
|
54
63
|
|
|
55
64
|
```tsx preview col
|
|
56
65
|
<Tabs defaultValue="prompt" orientation="vertical">
|
|
@@ -78,9 +87,9 @@ lateral do gatilho.
|
|
|
78
87
|
```tsx preview col
|
|
79
88
|
<Tabs defaultValue="preview" size="sm">
|
|
80
89
|
<TabsList>
|
|
81
|
-
<TabsTrigger value="preview"
|
|
82
|
-
<TabsTrigger value="code"
|
|
83
|
-
<TabsTrigger value="ai"
|
|
90
|
+
<TabsTrigger value="preview">Preview</TabsTrigger>
|
|
91
|
+
<TabsTrigger value="code">Código</TabsTrigger>
|
|
92
|
+
<TabsTrigger value="ai">IA</TabsTrigger>
|
|
84
93
|
</TabsList>
|
|
85
94
|
</Tabs>
|
|
86
95
|
```
|
|
@@ -92,17 +101,18 @@ lateral do gatilho.
|
|
|
92
101
|
| `defaultValue` | `string` | | Aba inicial no modo não controlado. |
|
|
93
102
|
| `value` | `string` | | Aba ativa no modo controlado. Use com `onValueChange`. |
|
|
94
103
|
| `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outra aba. |
|
|
95
|
-
| `size` | `'default' \| 'sm'` | `'default'` | Altura da lista na escala única dos controles (2.25 e 2rem), aplicada em `TabsList`. |
|
|
104
|
+
| `size` | `'default' \| 'sm'` | `'default'` | Altura da lista na escala única dos controles (2.25 e 2rem), aplicada em `TabsList`. Não altera a altura de `line` horizontal, que acompanha o conteúdo. |
|
|
96
105
|
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas. |
|
|
97
106
|
|
|
98
107
|
## Propriedades de TabsList
|
|
99
108
|
|
|
100
109
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
101
110
|
|---|---|---|---|
|
|
102
|
-
| `variant` | `'default' \| 'line'` | `'default'` | `default` usa uma superfície preenchida; `line` marca a aba ativa
|
|
111
|
+
| `variant` | `'default' \| 'line'` | `'default'` | `default` usa uma superfície preenchida; `line` cria uma linha-base horizontal de largura total e marca nela a aba ativa. |
|
|
103
112
|
|
|
104
113
|
## Propriedades de TabsTrigger e TabsContent
|
|
105
114
|
|
|
106
115
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
107
116
|
|---|---|---|---|
|
|
108
117
|
| `value` | `string` | | Identificador que associa o gatilho ao painel correspondente. |
|
|
118
|
+
| `icon` | `ReactNode` | | Ícone decorativo antes do rótulo; SVGs usam `1rem`. |
|
|
@@ -72,10 +72,12 @@ schema zod — matéria-prima do `mockHandler` (modo design) e de fixtures de te
|
|
|
72
72
|
url, datetime) e por nome de campo (email, id, `*At`→data, telefone, cpf/cnpj, nome…), sabor pt-BR.
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
+
import { entityRowSchema } from '@softize/opus/schema'
|
|
75
76
|
import { fake, fakeMany } from '@softize/opus/testing'
|
|
76
77
|
|
|
77
|
-
const
|
|
78
|
-
const
|
|
78
|
+
const eventRowSchema = entityRowSchema(EventEntity) // schema da linha da entidade
|
|
79
|
+
const one = fake(eventRowSchema) // 1 evento válido (safeParse passa)
|
|
80
|
+
const many = fakeMany(eventRowSchema, 20) // 20, estáveis entre execuções
|
|
79
81
|
fake(schema, { seed: 7 }) // seed própria
|
|
80
82
|
```
|
|
81
83
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Use `toast` para informar o resultado temporário de uma ação sem interromper o fluxo. Cada tipo usa o
|
|
4
4
|
ícone correspondente do Opus. Escreva o título como rótulo, sem ponto final, e a descrição como uma
|
|
5
5
|
frase. A moldura do ícone permanece quadrada e alinhada à primeira linha mesmo quando a descrição
|
|
6
|
-
ocupa várias linhas.
|
|
6
|
+
ocupa várias linhas. Corpo e padding seguem os mesmos `0.875rem` e `0.75rem` do Alert; os defaults
|
|
7
|
+
internos do Sonner não definem a densidade da casa.
|
|
7
8
|
|
|
8
9
|
```tsx preview
|
|
9
10
|
<Button variant="outline" onClick={() => toast.success('Workspace criado')}>Sucesso</Button>
|
|
@@ -30,11 +31,9 @@ hierarquia precisar ser diferente. A região fica alinhada ao fim lógico da sup
|
|
|
30
31
|
canto usado pelas ações do Alert. O clique fecha o toast, salvo quando o handler chama
|
|
31
32
|
`event.preventDefault()`.
|
|
32
33
|
|
|
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
34
|
`toast.promise` acompanha uma promessa e atualiza a mesma notificação nos estados de carregamento,
|
|
37
|
-
sucesso ou erro.
|
|
35
|
+
sucesso ou erro. Ela não aceita `actions`; use `toast` com `actions` quando a notificação precisar
|
|
36
|
+
oferecer uma ação.
|
|
38
37
|
|
|
39
38
|
```tsx preview
|
|
40
39
|
<Button
|
|
@@ -87,7 +86,7 @@ Monte um único `Toaster` na raiz do aplicativo. O tema vem da propriedade `them
|
|
|
87
86
|
|---|---|---|---|
|
|
88
87
|
| `description` | `React.ReactNode` | | Complemento exibido abaixo do título. |
|
|
89
88
|
| `actions` | `ToastAction[]` | | Coleção ordenada de ações; a última recebe destaque primário por padrão. |
|
|
90
|
-
| `duration` | `number` |
|
|
89
|
+
| `duration` | `number` | `4000` | Tempo de permanência da notificação, em milissegundos. O `Toaster` pode mudar o padrão, e `toast.loading` não expira sozinho. |
|
|
91
90
|
|
|
92
91
|
## Propriedades de ToastAction
|
|
93
92
|
|
|
@@ -71,6 +71,7 @@ disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
|
|
|
71
71
|
| `defaultPressed` | `boolean` | `false` | Estado inicial no modo não controlado. |
|
|
72
72
|
| `variant` | `'default' \| 'outline'` | `'default'` | default não tem borda (fundo só quando ativo); outline carrega a borda. |
|
|
73
73
|
| `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura na escala única dos controles (2 · 2.25 · 2.5rem) — sm para toolbar densa, lg para alvo mais confortável. |
|
|
74
|
+
| `shape` | `'default' \| 'pill'` | `'default'` | Geometria do controle; `pill` arredonda as extremidades. |
|
|
74
75
|
| `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |
|
|
75
76
|
|
|
76
77
|
## ToggleGroup
|
|
@@ -106,6 +107,39 @@ render(
|
|
|
106
107
|
)
|
|
107
108
|
```
|
|
108
109
|
|
|
110
|
+
### Itens só com ícone e tooltip
|
|
111
|
+
|
|
112
|
+
Quando o item mostra somente um ícone, mantenha o `aria-label` e acrescente uma dica visual. Envolva o
|
|
113
|
+
`ToggleGroupItem` em `TooltipTrigger asChild`: o item preserva o estado selecionado e seus atributos,
|
|
114
|
+
e a dica aparece sem criar outro botão. O `TooltipProvider` da raiz do aplicativo continua necessário.
|
|
115
|
+
|
|
116
|
+
```tsx preview
|
|
117
|
+
const [align, setAlign] = useState('left')
|
|
118
|
+
|
|
119
|
+
render(
|
|
120
|
+
<ToggleGroup type="single" value={align} onValueChange={(v) => v && setAlign(v)}>
|
|
121
|
+
<Tooltip>
|
|
122
|
+
<TooltipTrigger asChild>
|
|
123
|
+
<ToggleGroupItem value="left" aria-label="Alinhar à esquerda"><AlignLeft /></ToggleGroupItem>
|
|
124
|
+
</TooltipTrigger>
|
|
125
|
+
<TooltipContent>Alinhar à esquerda</TooltipContent>
|
|
126
|
+
</Tooltip>
|
|
127
|
+
<Tooltip>
|
|
128
|
+
<TooltipTrigger asChild>
|
|
129
|
+
<ToggleGroupItem value="center" aria-label="Centralizar"><AlignCenter /></ToggleGroupItem>
|
|
130
|
+
</TooltipTrigger>
|
|
131
|
+
<TooltipContent>Centralizar</TooltipContent>
|
|
132
|
+
</Tooltip>
|
|
133
|
+
<Tooltip>
|
|
134
|
+
<TooltipTrigger asChild>
|
|
135
|
+
<ToggleGroupItem value="right" aria-label="Alinhar à direita"><AlignRight /></ToggleGroupItem>
|
|
136
|
+
</TooltipTrigger>
|
|
137
|
+
<TooltipContent>Alinhar à direita</TooltipContent>
|
|
138
|
+
</Tooltip>
|
|
139
|
+
</ToggleGroup>,
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
109
143
|
### Variante e espaçamento
|
|
110
144
|
|
|
111
145
|
`variant`, `size` e `shape` definidos no grupo chegam aos itens por contexto. `spacing` separa os
|
|
@@ -138,3 +172,6 @@ itens; com zero, eles formam um bloco contínuo.
|
|
|
138
172
|
|---|---|---|---|
|
|
139
173
|
| `value` | `string` | | Identificador que entra no valor do grupo quando o item é ativado. |
|
|
140
174
|
| `disabled` | `boolean` | `false` | Bloqueia somente este item e preserva seu estado visual. |
|
|
175
|
+
| `variant` | `'default' \| 'outline'` | `'default'` | Tratamento do item quando o grupo não declara `variant`; o valor do grupo prevalece. |
|
|
176
|
+
| `size` | `'default' \| 'sm' \| 'lg'` | `'default'` | Tamanho do item quando o grupo não declara `size`; o valor do grupo prevalece. |
|
|
177
|
+
| `shape` | `'default' \| 'pill'` | shape do grupo | Geometria deste item; quando informada, prevalece sobre a do grupo. |
|