@softize/opus 13.1.0 → 15.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 (72) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/bin/cli.mjs +2 -0
  3. package/bin/lib/check.mjs +33 -5
  4. package/bin/lib/cli-shared.mjs +30 -1
  5. package/bin/lib/copy.mjs +279 -6
  6. package/bin/lib/db.mjs +2 -0
  7. package/docs/adr/0004-page-content-state-is-composed.md +39 -5
  8. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +9 -3
  9. package/docs/adr/0009-page-title-does-not-carry-a-counter.md +57 -0
  10. package/docs/adr/0010-page-header-owns-page-chrome.md +73 -0
  11. package/docs/code-style.md +4 -1
  12. package/docs/data-layer.md +9 -0
  13. package/package.json +1 -1
  14. package/registry/instructions/opus.md +3 -3
  15. package/registry/skills/build-opus-ui/SKILL.md +3 -2
  16. package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -6
  17. package/registry/templates/app/src/App.tsx +11 -6
  18. package/src/core/types.ts +3 -4
  19. package/src/ui/components/patterns/action-list-dialog.tsx +10 -3
  20. package/src/ui/components/patterns/confirm.tsx +2 -31
  21. package/src/ui/components/patterns/content-header.tsx +42 -141
  22. package/src/ui/components/patterns/data-state.tsx +42 -68
  23. package/src/ui/components/patterns/form.tsx +15 -15
  24. package/src/ui/components/patterns/list.tsx +55 -34
  25. package/src/ui/components/patterns/page-state.tsx +81 -51
  26. package/src/ui/components/patterns/page.tsx +228 -97
  27. package/src/ui/components/patterns/state-surface.tsx +262 -0
  28. package/src/ui/components/patterns/surface-header.tsx +204 -0
  29. package/src/ui/components/patterns/trigger.tsx +9 -10
  30. package/src/ui/components/patterns/view.tsx +14 -16
  31. package/src/ui/components/primitives/alert.tsx +1 -33
  32. package/src/ui/components/primitives/avatar.tsx +15 -5
  33. package/src/ui/components/primitives/badge.tsx +2 -43
  34. package/src/ui/components/primitives/button-group.tsx +34 -8
  35. package/src/ui/components/primitives/button.tsx +31 -35
  36. package/src/ui/components/primitives/control.ts +69 -0
  37. package/src/ui/components/primitives/dot.tsx +1 -30
  38. package/src/ui/components/primitives/input-group.tsx +11 -8
  39. package/src/ui/components/primitives/item.tsx +3 -1
  40. package/src/ui/components/primitives/menu.tsx +1 -7
  41. package/src/ui/components/primitives/pagination.tsx +16 -8
  42. package/src/ui/components/primitives/select.tsx +2 -2
  43. package/src/ui/components/primitives/spinner.tsx +13 -16
  44. package/src/ui/components/primitives/switch.tsx +4 -1
  45. package/src/ui/components/primitives/tabs.tsx +5 -3
  46. package/src/ui/components/primitives/toggle.tsx +9 -4
  47. package/src/ui/docs/content/action-form.md +26 -0
  48. package/src/ui/docs/content/action-list-dialog.md +2 -2
  49. package/src/ui/docs/content/action-list.md +35 -2
  50. package/src/ui/docs/content/action-trigger.md +5 -4
  51. package/src/ui/docs/content/action-view.md +3 -2
  52. package/src/ui/docs/content/alert.md +16 -4
  53. package/src/ui/docs/content/avatar.md +7 -3
  54. package/src/ui/docs/content/button.md +48 -17
  55. package/src/ui/docs/content/communication.md +36 -0
  56. package/src/ui/docs/content/content.md +5 -4
  57. package/src/ui/docs/content/data-state.md +17 -13
  58. package/src/ui/docs/content/dialog.md +1 -4
  59. package/src/ui/docs/content/input.md +1 -1
  60. package/src/ui/docs/content/item.md +1 -1
  61. package/src/ui/docs/content/page.md +160 -37
  62. package/src/ui/docs/content/pagination.md +11 -9
  63. package/src/ui/docs/content/semantic-context.md +3 -2
  64. package/src/ui/docs/content/sidebar.md +2 -42
  65. package/src/ui/docs/content/spinner.md +9 -6
  66. package/src/ui/docs/content/switch.md +1 -1
  67. package/src/ui/docs/content/tabs.md +1 -1
  68. package/src/ui/docs/content/toggle.md +1 -1
  69. package/src/ui/drivers/react.tsx +1 -6
  70. package/src/ui/meta.ts +8 -8
  71. package/src/ui/react.tsx +16 -18
  72. package/src/ui/components/patterns/shell-nav.tsx +0 -154
@@ -1,20 +1,22 @@
1
1
  ## Esqueleto de página
2
2
 
3
- Use `Page` para manter título, contexto, ações e conteúdo no mesmo ritmo visual nas telas do
4
- back-office. Em larguras amplas, as ações ficam no extremo oposto e acompanham a base do conjunto
5
- formado pelo título e pela descrição; em larguras estreitas, passam para uma linha abaixo do
6
- contexto. O container é centralizado e ocupa a largura disponível até `80rem` (`max-w-7xl`). Use
7
- `className` somente quando a composição pedir explicitamente outro teto ou largura total. A área
8
- abaixo do cabeçalho permanece livre para tabelas, cards ou outras composições.
3
+ Use `Page` para manter navegação contextual, título, ações e conteúdo na mesma anatomia. O
4
+ `PageHeader` padrão acompanha o conteúdo dentro do container; `variant="bar"` transforma o mesmo
5
+ cabeçalho em uma faixa compacta no topo. Não monte um chrome paralelo para repetir essas regiões.
6
+
7
+ Em larguras amplas, as ações ficam no extremo oposto e acompanham a base do título e da descrição;
8
+ em larguras estreitas, passam para uma linha abaixo. O container é centralizado e ocupa a largura
9
+ disponível até `80rem` (`max-w-7xl`). Use `className` somente quando a composição pedir outro teto
10
+ ou largura total.
9
11
 
10
12
  A forma curta é o padrão para páginas comuns. Ela cria internamente `PageHeader` e `PageBody`;
11
- portanto, não produz uma estrutura visual ou semântica diferente da forma explícita.
13
+ portanto, não produz uma estrutura visual ou semântica diferente da forma explícita. O cabeçalho é a
14
+ mesma base estrutural de `Content`, mas reconhece somente título, descrição e ações. Contadores e
15
+ outros indicadores pertencem ao conteúdo que os explica.
12
16
 
13
- `Page` é o esqueleto de páginas e recursos delimitados. Ele também pode ocupar o painel principal
14
- de um shell com sidebar; a navegação lateral não exige remover o teto nem reconstruir o cabeçalho.
15
- Uma navegação contextual para outra página pode ocupar `actions`, e tabs ficam reservados a
17
+ `Page` também pode ocupar o painel principal de um shell com sidebar. Tabs ficam reservados a
16
18
  recortes da mesma superfície. Canvas e outros workspaces espaciais imersivos podem usar um shell
17
- próprio quando o cabeçalho reduzir a área útil ou duplicar controles persistentes da superfície.
19
+ próprio quando o cabeçalho reduzir a área útil ou duplicar controles persistentes.
18
20
 
19
21
  Estados integrais de carregamento, falha ou ausência são compostos no body com `PageState`,
20
22
  detalhado abaixo. `Page` não recebe flags de dados: uma página pode agregar fontes independentes e
@@ -25,7 +27,6 @@ render(
25
27
  <div className="w-full overflow-hidden rounded-lg border border-border">
26
28
  <Page
27
29
  title="Workspaces"
28
- count={3}
29
30
  description="Ambientes compartilhados pela equipe."
30
31
  actions={
31
32
  <Button>
@@ -38,16 +39,58 @@ render(
38
39
  </div>
39
40
  </Page>
40
41
  </div>,
41
- )
42
+ );
42
43
  ```
43
44
 
44
- ## Ações no chrome do shell
45
+ ## Retorno para a página pai
46
+
47
+ Use `PageBack` em uma subpágina simples. O destino é explícito para continuar correto após refresh ou
48
+ acesso por link direto; não derive esse retorno do histórico do navegador. No header padrão, o
49
+ controle aparece acima do título com ícone e rótulo.
45
50
 
46
- Quando o shell reserva uma barra própria para contexto e ações, envolva sua região de conteúdo com
47
- `PageActionsTarget` e passe o elemento de destino em `target`. As ações declaradas em `Page`
48
- continuam pertencendo semanticamente ao cabeçalho da página, mas são projetadas nesse elemento.
49
- Com `target={null}`, elas permanecem na posição padrão; isso permite montar o alvo por `ref` sem
50
- uma renderização intermediária inconsistente.
51
+ ```tsx preview col
52
+ <Page>
53
+ <PageHeader>
54
+ <PageBack href="/customers">Clientes</PageBack>
55
+ <PageTitle>Qualidade da base</PageTitle>
56
+ <PageDescription>Revise conflitos e canais de contato.</PageDescription>
57
+ </PageHeader>
58
+ <PageBody>Conteúdo da análise.</PageBody>
59
+ </Page>
60
+ ```
61
+
62
+ Não combine `PageBack` com breadcrumb. Use o retorno para um único pai conhecido. Quando houver
63
+ mais de um ancestral relevante, envolva o `Breadcrumb` em `PageNavigation`; ele ocupa a mesma
64
+ posição introdutória sem transformar a trilha em ação.
65
+
66
+ ## Cabeçalho em barra
67
+
68
+ Use `variant="bar"` quando título, retorno e ações precisarem formar uma faixa compacta e persistente
69
+ no topo da página. `Page` estende a borda por toda a largura e mantém o conteúdo da barra alinhado ao
70
+ mesmo teto do body. Nesse modo, `PageBack` vira icon-only e recebe tooltip e nome acessível “Voltar
71
+ para {destino}”. Mantenha também as ações compactas: use `sm` em botões com texto e `icon-sm` em
72
+ botões que exibem somente um ícone.
73
+
74
+ ```tsx preview col
75
+ <Page className="max-w-none">
76
+ <PageHeader variant="bar">
77
+ <PageBack href="/customers">Clientes</PageBack>
78
+ <PageTitle>Qualidade da base</PageTitle>
79
+ <PageActions>
80
+ <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
81
+ <Ellipsis />
82
+ </Button>
83
+ </PageActions>
84
+ </PageHeader>
85
+ <PageBody>Conteúdo da análise.</PageBody>
86
+ </Page>
87
+ ```
88
+
89
+ Uma página comum não ganha a barra apenas por estar dentro de um shell. Escolha essa variante quando
90
+ a faixa acrescentar contexto ou ações persistentes; sem isso, mantenha o header padrão.
91
+
92
+ `PageActionsTarget` continua disponível para um workspace imersivo que já possua um chrome próprio.
93
+ Ele projeta somente `PageActions` no elemento informado; não cria uma segunda região de cabeçalho.
51
94
 
52
95
  ## Composição explícita
53
96
 
@@ -59,9 +102,12 @@ render(
59
102
  <Page>
60
103
  <PageHeader>
61
104
  <PageTitle>Workspaces</PageTitle>
62
- <PageMeta>3</PageMeta>
63
105
  <PageDescription>Ambientes compartilhados pela equipe.</PageDescription>
64
- <PageActions><Button><Plus /> Novo workspace</Button></PageActions>
106
+ <PageActions>
107
+ <Button>
108
+ <Plus /> Novo workspace
109
+ </Button>
110
+ </PageActions>
65
111
  </PageHeader>
66
112
  <PageBody>
67
113
  <div className="rounded-lg border border-dashed border-border p-10 text-center">
@@ -69,15 +115,18 @@ render(
69
115
  </div>
70
116
  </PageBody>
71
117
  </Page>,
72
- )
118
+ );
73
119
  ```
74
120
 
75
121
  ## Estados integrais
76
122
 
77
123
  Use `PageState` quando carregamento, falha ou ausência substituírem todo o conteúdo principal. Na
78
124
  forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
79
- explícita, coloque-o dentro de `PageBody`. O cabeçalho continua visível e o estado recebe composição,
80
- altura e semântica acessível consistentes.
125
+ explícita, coloque-o sozinho dentro de `PageBody`. Enquanto `status` for `loading`, `error` ou
126
+ `empty`, `Page` oculta o cabeçalho e o estado ocupa a altura disponível. O título do estado assume o
127
+ heading principal. Esse registro também funciona quando um componente intermediário decide qual
128
+ `PageState` renderizar. Em `ready`, o cabeçalho e o conteúdo voltam à composição normal. O cabeçalho some inteiro, incluindo o `PageBack`: uma subpágina que dependa desse retorno
129
+ oferece a saída pelo `action` do próprio `PageState` (ADR 0004, adendo).
81
130
 
82
131
  ```tsx preview col
83
132
  <Page title="Relatório">
@@ -85,13 +134,18 @@ altura e semântica acessível consistentes.
85
134
  status="error"
86
135
  title="Não foi possível carregar o relatório"
87
136
  description="Tente novamente. Se o problema continuar, volte mais tarde."
88
- action={<Button>Tentar novamente</Button>}
137
+ onRetry={() => {}}
138
+ retryLabel="Tentar novamente"
89
139
  />
90
140
  </Page>
91
141
  ```
92
142
 
93
- `loading` centraliza o `Spinner`; `error` compõe `Alert`; `empty` compõe `Empty`; e `ready` entrega
94
- os filhos sem acrescentar uma superfície.
143
+ `loading` centraliza o `Spinner` num contêiner `role="status"`; `error` usa a mesma anatomia visual
144
+ centralizada dos outros estados, conserva `role="alert"` e oferece uma ação `outline` textual quando
145
+ há `onRetry`; `empty` centraliza `Empty` sem moldura; e `ready` entrega os filhos sem
146
+ acrescentar uma superfície. A moldura tracejada continua reservada ao `Empty` usado diretamente para
147
+ representar uma região disponível para criar ou vincular. `title` e `description` nomeiam a situação
148
+ e, sem `title`, valem `errorMessage` e `emptyMessage`.
95
149
 
96
150
  ```tsx preview col
97
151
  <Page title="Relatórios">
@@ -111,20 +165,89 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
111
165
 
112
166
  | Propriedade | Tipo | Padrão | Descrição |
113
167
  | ------------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------- |
114
- | `title` | `string` | | O h1 da página. |
115
- | `count` | `number` | | Total de itens ao lado do título (mono, esmaecido). |
168
+ | `title` | `ReactNode` | | O h1 da página. |
116
169
  | `description` | `ReactNode` | | Linha de contexto sob o título (ex.: "N no total · X ativos"). |
117
170
  | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho; em telas estreitas, ficam abaixo do contexto. |
118
171
  | `className` | `string` | `max-w-7xl` | Classes do container para substituir o teto padrão de `80rem`. |
119
172
  | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
120
173
 
174
+ ## Propriedades de PageHeader
175
+
176
+ | Propriedade | Tipo | Padrão | Descrição |
177
+ | ----------- | ---------------------- | ----------- | ---------------------------------------------------------------- |
178
+ | `variant` | `'default' \| 'bar'` | `'default'` | Apresentação no container ou como faixa compacta no topo. |
179
+ | `className` | `string` | | Classes adicionais da região externa do cabeçalho. |
180
+ | `children` | `ReactNode` | | Um `PageTitle` e, opcionalmente, `PageBack` ou `PageNavigation`, descrição e ações. |
181
+
182
+ ## Propriedades de PageBack
183
+
184
+ | Propriedade | Tipo | Padrão | Descrição |
185
+ | ------------ | ---------------------------- | ------------------------- | ----------------------------------------------------------------------- |
186
+ | `href` | `string` | obrigatório | Destino explícito da página pai. Sem ele o retorno não é tabulável nem tem nome acessível. |
187
+ | `children` | `ReactNode` | | Nome visível do destino no header padrão e conteúdo do tooltip na barra. |
188
+ | `aria-label` | `string` | `Voltar para {children}` | Nome acessível; informe-o quando `children` não for texto simples. |
189
+ | `onClick` | `MouseEventHandler<HTMLAnchorElement>` | | Integração opcional com o roteador do consumidor, junto do `href`, nunca no lugar dele. |
190
+ | `className` | `string` | | Classes adicionais do link renderizado como botão `ghost`. |
191
+
192
+ ## Propriedades de PageNavigation
193
+
194
+ | Propriedade | Tipo | Descrição |
195
+ | ----------- | ----------------------------- | ----------------------------------------------- |
196
+ | `children` | `ReactNode` | Trilha estrutural, normalmente um `Breadcrumb`. |
197
+ | `className` | `string` | Classes adicionais do container introdutório. |
198
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
199
+
200
+ ## Propriedades de PageTitle
201
+
202
+ | Propriedade | Tipo | Descrição |
203
+ | ----------- | --------------------------------- | ------------------------------------------------------ |
204
+ | `children` | `ReactNode` | Título principal `h1`; compacto na variante `bar`. |
205
+ | `className` | `string` | Classes adicionais do título. |
206
+ | demais | Atributos de `HTMLHeadingElement` | Atributos nativos repassados ao heading. |
207
+
208
+ ## Propriedades de PageDescription
209
+
210
+ | Propriedade | Tipo | Descrição |
211
+ | ----------- | ----------------------------------- | ---------------------------------------- |
212
+ | `children` | `ReactNode` | Contexto apresentado abaixo do título. |
213
+ | `className` | `string` | Classes adicionais da descrição. |
214
+ | demais | Atributos de `HTMLParagraphElement` | Atributos nativos repassados ao parágrafo. |
215
+
216
+ ## Propriedades de PageActions
217
+
218
+ | Propriedade | Tipo | Descrição |
219
+ | ----------- | ------------------------------ | -------------------------------------------- |
220
+ | `children` | `ReactNode` | Ações no extremo oposto do cabeçalho. |
221
+ | `className` | `string` | Classes adicionais da região de ações. |
222
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
223
+
224
+ ## Propriedades de PageBody
225
+
226
+ | Propriedade | Tipo | Descrição |
227
+ | ----------- | ----------------------------- | ----------------------------------------------------- |
228
+ | `children` | `ReactNode` | Conteúdo principal; recebe o container na barra. |
229
+ | `className` | `string` | Classes adicionais da região principal. |
230
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
231
+
232
+ ## Propriedades de PageActionsTarget
233
+
234
+ | Propriedade | Tipo | Descrição |
235
+ | ----------- | -------------------- | ----------------------------------------------------------------------- |
236
+ | `target` | `HTMLElement \| null` | Destino externo das ações; `null` mantém as ações no header. |
237
+ | `children` | `ReactNode` | Árvore de página que poderá declarar `PageActions`. |
238
+
121
239
  ## Propriedades de PageState
122
240
 
123
- | Propriedade | Tipo | Padrão | Descrição |
124
- |---|---|---|---|
125
- | `status` | `'loading' \| 'error' \| 'empty' \| 'ready'` | | Estado integral do conteúdo. |
126
- | `title` | `ReactNode` | Texto seguro por estado | Situação reconhecível pela pessoa. |
127
- | `description` | `ReactNode` | | Impacto ou próximo passo aplicável. |
128
- | `icon` | `ReactNode` | Alerta no erro | Ícone decorativo do estado. |
129
- | `action` | `ReactNode` | | Recuperação, seleção ou criação aplicável. |
130
- | `children` | `ReactNode` | | Conteúdo renderizado somente em `ready`. |
241
+ | Propriedade | Tipo | Padrão | Descrição |
242
+ | -------------- | -------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------- |
243
+ | `status` | `'loading' \| 'error' \| 'empty' \| 'ready'` | | Estado integral do conteúdo. |
244
+ | `title` | `ReactNode` | Texto seguro por estado | Situação reconhecível pela pessoa. |
245
+ | `description` | `ReactNode` | | Impacto ou próximo passo aplicável. |
246
+ | `icon` | `ReactNode` | Alerta no erro | Ícone decorativo do estado. |
247
+ | `action` | `ReactNode` | | Seleção ou criação aplicável ao estado. |
248
+ | `emptyMessage` | `string` | `'Nada por aqui'` | Título do vazio quando `title` não é informado. |
249
+ | `errorMessage` | `string` | `'Não foi possível carregar esta página'` | Título do erro quando `title` não é informado. |
250
+ | `onRetry` | `() => void \| Promise<void>` | | Recuperação do erro: acrescenta um botão `outline` textual ao lado de `action`. |
251
+ | `retryLabel` | `string` | `'Tentar de novo'` | Texto do botão de recuperação. |
252
+ | `children` | `ReactNode` | | Conteúdo renderizado somente em `ready`. |
253
+ | `className` | `string` | | Classes da superfície de estado. |
@@ -29,21 +29,21 @@ rodapé.
29
29
 
30
30
  ## Números longos
31
31
 
32
- A largura mínima é quadrada e cresce conforme o conteúdo. Na escala densa de um rodapé, ajuste por
33
- `className` (`h-7 min-w-7 text-xs` nos números; `size-7` mais `iconClassName="size-3.5"` nas
34
- setas com `iconOnly`).
32
+ A largura mínima é quadrada e cresce conforme o conteúdo. Na escala densa de um rodapé, as setas e a
33
+ elipse usam `size="icon-sm"` (o quadrado de 1.75rem da escala única, com o glifo de 0.875rem); os
34
+ números, que não têm um degrau de 1.75rem na escala, ajustam por `className` (`h-7 min-w-7 text-xs`).
35
35
 
36
36
  ```tsx preview
37
37
  <Pagination>
38
38
  <PaginationContent className="gap-0.5">
39
39
  <PaginationItem>
40
- <PaginationPrevious href="#" iconOnly className="size-7" iconClassName="size-3.5" />
40
+ <PaginationPrevious href="#" iconOnly size="icon-sm" />
41
41
  </PaginationItem>
42
42
  <PaginationItem>
43
43
  <PaginationLink href="#" page={1} className="h-7 min-w-7 text-xs" />
44
44
  </PaginationItem>
45
45
  <PaginationItem>
46
- <PaginationEllipsis className="size-7" />
46
+ <PaginationEllipsis size="icon-sm" />
47
47
  </PaginationItem>
48
48
  <PaginationItem>
49
49
  <PaginationLink href="#" page={5726} className="h-7 min-w-7 text-xs" />
@@ -52,7 +52,7 @@ setas com `iconOnly`).
52
52
  <PaginationLink href="#" page={5727} isActive className="h-7 min-w-7 text-xs" />
53
53
  </PaginationItem>
54
54
  <PaginationItem>
55
- <PaginationNext href="#" iconOnly className="size-7" iconClassName="size-3.5" />
55
+ <PaginationNext href="#" iconOnly size="icon-sm" />
56
56
  </PaginationItem>
57
57
  </PaginationContent>
58
58
  </Pagination>
@@ -61,7 +61,8 @@ setas com `iconOnly`).
61
61
  ## Com elipse
62
62
 
63
63
  `PaginationEllipsis` marca, de forma decorativa e com `aria-hidden`, uma sequência de páginas que
64
- não cabe na barra.
64
+ não cabe na barra. `size` aceita os quadrados da escala (`icon-xs`, `icon-sm`, `icon`, `icon-lg`) para
65
+ parear com as setas.
65
66
 
66
67
  ```tsx preview
67
68
  <Pagination>
@@ -130,7 +131,7 @@ render(
130
131
  | `page` | `number` | | Número usado como conteúdo, quando `children` não é informado, e no nome acessível “Página N”. |
131
132
  | `isActive` | `boolean` | `false` | Marca a página atual com `aria-current="page"` e tratamento `outline`. |
132
133
  | `href` | `string` | | Renderiza um `<a>`. Sem `href`, o componente usa `<button>` e aceita `onClick` e `disabled`. |
133
- | `size` | `'default' \| 'sm' \| 'lg' \| 'icon' \| 'icon-sm' \| 'icon-xs'` | `'default'` | Escala herdada de `Button`. A largura mínima cresce para acomodar números longos. |
134
+ | `size` | `ButtonProps['size']` | `'default'` | A escala única, via `Button`. A largura mínima cresce para acomodar números longos; os `icon-*` são quadrados. |
134
135
 
135
136
  ## Propriedades de PaginationPrevious e PaginationNext
136
137
 
@@ -138,4 +139,5 @@ render(
138
139
  |---|---|---|---|
139
140
  | `label` | `string` | `'Página anterior'` ou `'Próxima página'` | Nome acessível e texto visível da ação. |
140
141
  | `iconOnly` | `boolean` | `false` | Exibe somente a seta; `label` continua disponível para leitura assistiva. |
141
- | `iconClassName` | `string` | | Classes aplicadas ao ícone da seta. |
142
+ | `size` | `ButtonProps['size']` | `'default'`; `'icon'` com `iconOnly` | A escala única; `icon-sm` para o rodapé denso. |
143
+ | `iconClassName` | `string` | | Classes aplicadas ao ícone da seta, quando o glifo da escala não servir. |
@@ -59,5 +59,6 @@ const status = t.dict(
59
59
 
60
60
  ## Compatibilidade
61
61
 
62
- `tone` em dicionários e variantes semânticas antigas continuam aceitos durante a migração. Código
63
- novo usa `context`; não misture o contrato antigo e o novo na mesma ocorrência.
62
+ `tone` em dicionários continua aceito durante a migração; código novo usa `context`. As variantes
63
+ semânticas antigas dos componentes (`default`, `secondary`, `destructive`, `success`, `warning`,
64
+ `info`) saíram na 14.0.0: `variant` só descreve tratamento visual e o significado é sempre `context`.
@@ -61,7 +61,7 @@ uma sidebar fixa, redimensionável ou recolhida.
61
61
  | `PaneHeader` | Mantém identidade, contexto ou ações no topo. |
62
62
  | `PaneBody` | Ocupa o espaço restante e concentra a rolagem vertical. |
63
63
  | `PaneFooter` | Mantém ações persistentes no rodapé. |
64
- | `SidebarNav` ou `ShellNav` | Apresenta e controla os destinos de navegação. |
64
+ | `SidebarNav` | Apresenta e controla os destinos de navegação. |
65
65
 
66
66
  `PaneContent` permanece como alias temporário de `PaneBody` durante a versão 12. Código novo usa
67
67
  `PaneBody`.
@@ -134,26 +134,9 @@ render(
134
134
  Esse é o padrão usado pelo `DocBrowser`: seções são rótulos, grupos nomeados são nós expansíveis e
135
135
  páginas são folhas. Um grupo começa aberto e volta a abrir quando contém a página ativa.
136
136
 
137
- `ShellNav` continua disponível para uma navegação plana com cabeçalho próprio e grupos ancorados no
138
- rodapé, mas está descontinuado: código novo usa `SidebarNav`, que cobre o mesmo caso integrado à
139
- `Sidebar`. Ele gerencia a rolagem internamente e se adapta quando estiver dentro de uma `Sidebar`
140
- recolhida.
141
-
142
- ```tsx
143
- <Sidebar collapsed={collapsed}>
144
- <ShellNav
145
- heading={<ShellNavHeading title="Relatórios" action={<CreateReportButton />} />}
146
- groups={reportGroups}
147
- footer={settingsGroups}
148
- activeId={activeId}
149
- onSelect={navigateToReport}
150
- />
151
- </Sidebar>
152
- ```
153
-
154
137
  ## Recolher a coluna
155
138
 
156
- `collapsed` pertence à `Sidebar`. Nesse estado, `SidebarItem`, `SidebarNav` e `ShellNav` mantêm
139
+ `collapsed` pertence à `Sidebar`. Nesse estado, `SidebarItem` e `SidebarNav` mantêm
157
140
  somente os ícones e expõem os rótulos em tooltips. Por isso, todo destino que aparece no modo
158
141
  recolhido precisa de um ícone reconhecível e de um `label` completo.
159
142
 
@@ -329,26 +312,3 @@ O driver de drag-and-drop continua externo e fornece seus atributos por `dragPro
329
312
  |---|---|---|---|
330
313
  | `className` | `string` | | Ajusta o grupo sem substituir o recuo, o espaçamento e a guia vertical padrão. |
331
314
  | `children` | `ReactNode` | | Itens ou grupos que descendem do nó anterior. |
332
-
333
- ## Propriedades de ShellNav
334
-
335
- | Propriedade | Tipo | Padrão | Descrição |
336
- |---|---|---|---|
337
- | `groups` | `ShellNavGroup[]` | | Grupos planos exibidos na região rolável. Grupos vazios são omitidos. |
338
- | `activeId` | `string` | | Identificador do destino atual. |
339
- | `onSelect` | `(id: string) => void` | | Recebe o identificador selecionado. |
340
- | `heading` | `ReactNode` | | Conteúdo fixo acima da navegação; fica oculto no modo recolhido. |
341
- | `footer` | `ShellNavGroup[]` | | Grupos ancorados abaixo da região rolável. |
342
- | `navLabel` | `string` | `'Navegação'` | Nome acessível da landmark `nav`. |
343
- | `className` | `string` | | Ajusta a coluna da navegação. A largura vem do contêiner. |
344
-
345
- Cada `ShellNavGroup` recebe `label` opcional e `items`. Um `ShellNavItem` declara `id`, `label`,
346
- `icon`, `badge` e `disabled`.
347
-
348
- ## Propriedades de ShellNavHeading
349
-
350
- | Propriedade | Tipo | Padrão | Descrição |
351
- |---|---|---|---|
352
- | `title` | `ReactNode` | | Título da navegação. |
353
- | `action` | `ReactNode` | | Ação relacionada apresentada no extremo oposto. |
354
- | `className` | `string` | | Ajusta a faixa de cabeçalho. |
@@ -1,9 +1,12 @@
1
1
  ## Carregamento sem progresso conhecido
2
2
 
3
- Use `Spinner` quando a duração ou o progresso da espera não forem conhecidos. `sm` atende ações
4
- compactas; `lg`, estados mais amplos. O componente possui o nome acessível “Carregando”.
3
+ Use `Spinner` quando a duração ou o progresso da espera não forem conhecidos. `size` usa os nomes da
4
+ escala dos controles e mede o glifo do controle homônimo: `sm` é o ícone de um `Button` `sm`, `lg` o
5
+ de um `lg`. O ícone é decorativo; quem nomeia a espera é o contêiner (`role="status"`, como fazem
6
+ `DataState` e `PageState`) ou o texto ao lado.
5
7
 
6
8
  ```tsx preview
9
+ <Spinner size="xs" />
7
10
  <Spinner size="sm" />
8
11
  <Spinner />
9
12
  <Spinner size="lg" />
@@ -20,11 +23,11 @@ andamento.
20
23
 
21
24
  ## Em carga de conteúdo
22
25
 
23
- Espera curta sem forma definida. Quando o conteúdo tem forma conhecida (lista, card), prefira
24
- Skeleton.
26
+ Espera curta sem forma definida; o contêiner nomeia o estado. Para uma consulta inteira, `DataState`
27
+ já monta esse contêiner. Quando o conteúdo tem forma conhecida (lista, card), prefira Skeleton.
25
28
 
26
29
  ```tsx preview
27
- <div className="flex items-center gap-2 text-sm text-muted-foreground">
30
+ <div role="status" className="flex items-center gap-2 text-sm text-muted-foreground">
28
31
  <Spinner />
29
32
  <span>Carregando sessões…</span>
30
33
  </div>
@@ -34,4 +37,4 @@ Skeleton.
34
37
 
35
38
  | Propriedade | Tipo | Padrão | Descrição |
36
39
  |---|---|---|---|
37
- | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | O tamanho sm para dentro de botão, lg para estados de página. |
40
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'default'` | O glifo do controle homônimo na escala única (0.875 · 0.875 · 1 · 1.25rem). |
@@ -66,5 +66,5 @@ disabled esmaece e bloqueia a chave — ligada ou desligada — e o rótulo em p
66
66
  | `checked` | `boolean` | | O estado, no modo controlado — parear com onCheckedChange. |
67
67
  | `onCheckedChange` | `(checked: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
68
68
  | `defaultChecked` | `boolean` | `false` | Estado inicial no modo não controlado. |
69
- | `size` | `'sm' \| 'default'` | `'default'` | Tamanho da chave — sm para densidade em linha de lista. |
69
+ | `size` | `'sm' \| 'default'` | `'default'` | Tamanho da chave, com os nomes da escala única — sm para densidade em linha de lista. |
70
70
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia — o Label em par esmaece junto (peer-disabled). |
@@ -92,7 +92,7 @@ lateral do gatilho.
92
92
  | `defaultValue` | `string` | | Aba inicial no modo não controlado. |
93
93
  | `value` | `string` | | Aba ativa no modo controlado. Use com `onValueChange`. |
94
94
  | `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outra aba. |
95
- | `size` | `'default' \| 'sm'` | `'default'` | Escala de altura compartilhada com `TabsList`. |
95
+ | `size` | `'default' \| 'sm'` | `'default'` | Altura da lista na escala única dos controles (2.25 e 2rem), aplicada em `TabsList`. |
96
96
  | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas. |
97
97
 
98
98
  ## Propriedades de TabsList
@@ -70,7 +70,7 @@ disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
70
70
  | `onPressedChange` | `(pressed: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
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
- | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura do botão — sm para toolbar densa, lg para alvo mais confortável. |
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
74
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |
75
75
 
76
76
  ## ToggleGroup
@@ -2,7 +2,7 @@
2
2
  * @softize/opus/ui/react — React driver
3
3
  *
4
4
  * Hooks + Provider pra invocar actions client-side.
5
- * - `OpusProvider` — injeta ClientAdapter no contexto (`TbdlibProvider` é alias em retirada)
5
+ * - `OpusProvider` — injeta ClientAdapter no contexto
6
6
  * - `useAction(action)` — invoca actions simple/form/view
7
7
  * - `useLookupAction(action)` — variante pra search (output Paginated)
8
8
  *
@@ -83,11 +83,6 @@ export function OpusProvider({
83
83
  return <OpusContext.Provider value={value}>{children}</OpusContext.Provider>
84
84
  }
85
85
 
86
- /** @deprecated Renomeado para `OpusProvider`; o alias segue até a próxima série. */
87
- export const TbdlibProvider = OpusProvider
88
- /** @deprecated Use `OpusProviderProps`. */
89
- export type TbdlibProviderProps = OpusProviderProps
90
-
91
86
  function useClient(): ClientAdapter {
92
87
  const ctx = useContext(OpusContext)
93
88
  if (ctx === null) {
package/src/ui/meta.ts CHANGED
@@ -27,7 +27,7 @@ export const componentMeta = {
27
27
  name: "alert",
28
28
  ancestry: "opus",
29
29
  whenToUse:
30
- "Aviso inline no fluxo da página — `context` declara neutral/info/success/warning/danger e `variant` escolhe subtle/outline (ADR 0006). Forma curta: `<Alert title description icon context />`; para conteúdo rico, componha AlertMedia + AlertHeader (AlertTitle e AlertDescription) + AlertActions. A mídia mantém uma moldura tonal quadrada, mesmo com descrição multilinha. O texto comunica o significado sem depender só da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
30
+ "Aviso inline no fluxo da página — `context` declara neutral/info/success/warning/danger e `variant` escolhe subtle/outline (ADR 0006). Forma curta: `<Alert title description icon context />`; para conteúdo rico, componha AlertMedia + AlertHeader (AlertTitle e AlertDescription) + AlertActions. Ações usam Button ghost como ponto de partida; tentativas repetidas podem usar somente o ícone, com nome acessível e tooltip. A mídia mantém uma moldura tonal quadrada, mesmo com descrição multilinha. O texto comunica o significado sem depender só da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
31
31
  },
32
32
  badge: {
33
33
  name: "badge",
@@ -69,7 +69,7 @@ export const componentMeta = {
69
69
  name: "button",
70
70
  ancestry: "shadcn",
71
71
  whenToUse:
72
- "Inicie uma ação com um controle clicável. Use `context` para o significado, `variant` para o tratamento visual e `size` para a escala; `busy` comunica o andamento e impede um novo acionamento. Para ações relacionadas, use ButtonGroup.",
72
+ "Inicie uma ação com um controle clicável. Use `context` para o significado, `variant` para o tratamento visual e `size` para a escala compartilhada (`xs`…`lg` e os quadrados `icon-*`); `icon` recebe um nó e `busy` comunica o andamento e impede um novo acionamento. Para ações relacionadas, use ButtonGroup conectado ou espaçado.",
73
73
  },
74
74
  card: {
75
75
  name: "card",
@@ -117,7 +117,7 @@ export const componentMeta = {
117
117
  name: "content-header",
118
118
  ancestry: "opus",
119
119
  whenToUse:
120
- "Estruture o cabeçalho de um Content com título, descrição, metadados e ações. No caso comum, declare esses valores diretamente em Content; componha ContentHeader apenas quando precisar controlar a anatomia.",
120
+ "Estruture uma região de conteúdo com título, contador, descrição e ações. No caso comum, declare esses valores diretamente em Content; componha ContentHeader apenas quando precisar controlar a anatomia. Contadores pertencem a Content e não ao título da Page.",
121
121
  },
122
122
  copyable: {
123
123
  name: "copyable",
@@ -129,7 +129,7 @@ export const componentMeta = {
129
129
  name: "dialog",
130
130
  ancestry: "opus",
131
131
  whenToUse:
132
- "Abra conteúdo ou uma tarefa em uma janela modal com foco contido. Use o modo padrão quando a superfície puder ser dispensada e `mode=\"alert\"` quando exigir resposta explícita. Para o caso imperativo comum, use `dialog.alert`, `dialog.confirm`, `dialog.prompt` ou `dialog.choose`. Distribua conteúdo próprio entre cabeçalho, corpo rolável e rodapé de ações.",
132
+ 'Abra conteúdo ou uma tarefa em uma janela modal com foco contido. Use o modo padrão quando a superfície puder ser dispensada e `mode="alert"` quando exigir resposta explícita. Para o caso imperativo comum, use `dialog.alert`, `dialog.confirm`, `dialog.prompt` ou `dialog.choose`. Distribua conteúdo próprio entre cabeçalho, corpo rolável e rodapé de ações.',
133
133
  },
134
134
  input: {
135
135
  name: "input",
@@ -183,7 +183,7 @@ export const componentMeta = {
183
183
  name: "spinner",
184
184
  ancestry: "shadcn",
185
185
  whenToUse:
186
- "Indique uma espera sem progresso determinado, como uma ação ou consulta em andamento. Para reservar a forma do conteúdo, use Skeleton.",
186
+ 'Indique uma espera sem progresso determinado, como uma ação ou consulta em andamento. O ícone é decorativo: o contêiner (`role="status"`) ou o texto ao lado nomeia a espera. Para reservar a forma do conteúdo, use Skeleton.',
187
187
  },
188
188
  table: {
189
189
  name: "table",
@@ -327,7 +327,7 @@ export const componentMeta = {
327
327
  name: "sidebar",
328
328
  ancestry: "opus",
329
329
  whenToUse:
330
- "Organize navegação global ou contextual em uma coluna lateral. Split e Pane definem posição e largura; Sidebar fornece a superfície e o colapso, enquanto PaneHeader, PaneBody e PaneFooter estruturam as regiões fixa e rolável. Use SidebarNav para grupos planos, componha árvores com SidebarItem e SidebarTreeGroup e use ShellNav quando a navegação precisar de cabeçalho e rodapé próprios.",
330
+ "Organize navegação global ou contextual em uma coluna lateral. Split e Pane definem posição e largura; Sidebar fornece a superfície e o colapso, enquanto PaneHeader, PaneBody e PaneFooter estruturam as regiões fixa e rolável. Use SidebarNav para grupos planos e componha árvores com SidebarItem e SidebarTreeGroup; cabeçalho e rodapé próprios ficam em PaneHeader e PaneFooter.",
331
331
  },
332
332
  "scroll-area": {
333
333
  name: "scroll-area",
@@ -400,7 +400,7 @@ export const componentMeta = {
400
400
  name: "page",
401
401
  ancestry: "opus",
402
402
  whenToUse:
403
- "O esqueleto de página do back-office: <main> + container centralizado com teto padrão de 80rem (`max-w-7xl`). O shorthand com title, description, count e actions cria a mesma anatomia de PageHeader(PageTitle/PageDescription/PageMeta/PageActions) + PageBody disponível na forma explícita. PageActionsTarget projeta as ações no chrome reservado pelo shell sem retirar sua declaração da Page. `className` substitui o teto quando a composição pede outra largura. Quando todo o body estiver carregando, falhar ou estiver vazio, use PageState. Para listagem em modal, ActionListDialog.",
403
+ "O esqueleto de página do back-office: <main> + container centralizado com teto padrão de 80rem (`max-w-7xl`). O shorthand cobre título, descrição e ações; a forma explícita acrescenta PageBack para retorno simples ou PageNavigation para uma trilha e permite `PageHeader variant=\"bar\"` quando a mesma anatomia precisar virar uma faixa compacta. No header padrão, PageBack fica acima do título; na barra, vira icon-only com tooltip. PageActionsTarget fica restrito a workspaces imersivos com chrome próprio. Quando todo o body estiver carregando, falhar ou estiver vazio, use PageState: ele oculta o header e ocupa a área disponível, centralizado e sem moldura. Para uma região disponível à criação ou vínculo, use Empty.",
404
404
  },
405
405
  router: {
406
406
  name: "router",
@@ -412,7 +412,7 @@ export const componentMeta = {
412
412
  name: "data-state",
413
413
  ancestry: "opus",
414
414
  whenToUse:
415
- "Coordene carregamento, erro, vazio e conteúdo de uma consulta assíncrona. Use DataState dentro da estrutura que receberá os dados; para uma região disponível à criação, use Empty. Ações em andamento pertencem ao estado `busy` do controle que as iniciou.",
415
+ "Coordene carregamento, erro, vazio e conteúdo de uma consulta assíncrona com as mesmas superfícies de PageState: `emptyMessage` compõe Empty com moldura sólida, o erro é um Alert com `onRetry` e `retryLabel`. Use DataState dentro da estrutura que receberá os dados; para uma região disponível à criação, use Empty. Ações em andamento pertencem ao estado `busy` do controle que as iniciou.",
416
416
  },
417
417
  "action-list-dialog": {
418
418
  name: "action-list-dialog",