@softize/opus 29.0.0 → 31.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 (59) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/bin/lib/check.mjs +178 -94
  3. package/bin/lib/copy.mjs +2970 -1801
  4. package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +52 -0
  5. package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +27 -2
  6. package/docs/adr/0045-surface-replaces-content-and-card.md +3 -0
  7. package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
  8. package/docs/adr/0062-listas-contidas-e-texto-flexivel.md +68 -0
  9. package/docs/adr/0063-metadados-das-superficies.md +44 -0
  10. package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
  11. package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
  12. package/docs/adr/README.md +8 -0
  13. package/package.json +1 -1
  14. package/registry/skills/build-opus-ui/SKILL.md +21 -19
  15. package/registry/skills/build-opus-ui/references/evaluations.md +21 -10
  16. package/registry/skills/build-opus-ui/references/ui-patterns.md +33 -28
  17. package/src/core/presentation.ts +938 -32
  18. package/src/core/types.ts +2 -1
  19. package/src/ui/components/patterns/form.tsx +2 -0
  20. package/src/ui/components/patterns/grouped-list.ts +2 -2
  21. package/src/ui/components/patterns/list.tsx +588 -365
  22. package/src/ui/components/patterns/page-heading-context.tsx +12 -5
  23. package/src/ui/components/patterns/page.tsx +238 -181
  24. package/src/ui/components/patterns/presentation-fields.tsx +246 -0
  25. package/src/ui/components/patterns/presentation-sections.tsx +494 -0
  26. package/src/ui/components/patterns/presentation.tsx +1142 -229
  27. package/src/ui/components/patterns/structural-header.tsx +47 -34
  28. package/src/ui/components/patterns/surface-anatomy.ts +27 -217
  29. package/src/ui/components/patterns/surface.tsx +55 -37
  30. package/src/ui/components/patterns/trigger.tsx +10 -2
  31. package/src/ui/components/primitives/close-button.tsx +11 -3
  32. package/src/ui/components/primitives/command.tsx +2 -8
  33. package/src/ui/components/primitives/detail.tsx +1 -1
  34. package/src/ui/components/primitives/dialog.tsx +59 -89
  35. package/src/ui/components/primitives/drawer.tsx +52 -87
  36. package/src/ui/components/primitives/field.tsx +1 -1
  37. package/src/ui/components/primitives/pagination.tsx +3 -2
  38. package/src/ui/components/primitives/table.tsx +3 -3
  39. package/src/ui/components/primitives/tabs.tsx +13 -2
  40. package/src/ui/docs/content/action-form.md +2 -1
  41. package/src/ui/docs/content/action-list.md +146 -73
  42. package/src/ui/docs/content/action-trigger.md +5 -0
  43. package/src/ui/docs/content/button.md +5 -6
  44. package/src/ui/docs/content/command.md +62 -50
  45. package/src/ui/docs/content/compositions.md +129 -459
  46. package/src/ui/docs/content/dialog.md +72 -101
  47. package/src/ui/docs/content/drawer.md +69 -92
  48. package/src/ui/docs/content/field.md +2 -1
  49. package/src/ui/docs/content/page.md +207 -386
  50. package/src/ui/docs/content/presentation.md +371 -23
  51. package/src/ui/docs/content/separator.md +1 -1
  52. package/src/ui/docs/content/surface.md +94 -116
  53. package/src/ui/docs/content/table.md +7 -0
  54. package/src/ui/docs/content/tokens.md +18 -4
  55. package/src/ui/drivers/context.tsx +11 -4
  56. package/src/ui/drivers/react.tsx +27 -7
  57. package/src/ui/meta.ts +5 -5
  58. package/src/ui/react.tsx +38 -8
  59. package/src/ui/theme.css +44 -33
@@ -1,229 +1,155 @@
1
- ## Esqueleto de página
1
+ ## Página com cabeçalho único
2
2
 
3
- Use `Page` para manter cabeçalho, estado e conteúdo na mesma anatomia. `PageHeader` recebe navegação e ações da superfície;
4
- `PageIntro` abre o corpo com título e orientação. Na composição compacta, o título fica no header e a intro é omitida. O conteúdo interno do body é
5
- centralizado e ocupa a largura disponível até `80rem` (`max-w-7xl`). O header e o viewport
6
- de rolagem ocupam toda a largura do painel.
3
+ Use `Page` para reunir título, ações e conteúdo em uma coluna aberta, sem divisores
4
+ entre regiões. A coluna tem padding de `2,5rem` em todos os lados, intervalo de `1,5rem`
5
+ entre cabeçalho e conteúdo, `1rem` entre as demais regiões e título de `1,875rem`.
6
+ A largura e a ocupação de altura são independentes:
7
+ `flow` rola a página inteira; `fill` mantém o cabeçalho visível e entrega a altura restante
8
+ ao conteúdo. Drawer e Dialog conservam seus recuos de `1rem` e superfícies delimitadas.
7
9
 
8
- A forma curta é o padrão para páginas comuns e cria `PageIntro` dentro de `PageBody` e um `PageHeader` quando existem controles. A forma explícita
9
- exige exatamente um heading principal. Use `PageTitle` na intro ou no cabeçalho, `Surface level={1}` no body,
10
- ou deixe um `PageState` ativo assumir esse papel. O cabeçalho pode ser omitido quando o próprio
11
- conteúdo nomeia a página. Contadores e outros indicadores pertencem ao conteúdo que os explica.
10
+ A forma curta cobre páginas comuns:
12
11
 
13
- Use `surfaceLayout="sectioned"` (padrão) para separar as regiões por bordas ou
14
- `surfaceLayout="continuous"` para uma superfície contínua. O `layout` decide a ocupação de altura:
15
- `flow`, o padrão, mantém a rolagem vertical em `PageBody`; `fill` permite que uma região interna,
16
- como uma tabela longa ou um split, assuma a rolagem. Header e footer ficam fora desse viewport.
12
+ ```tsx preview col
13
+ <Page title="Clientes" actions={<Button size="default">Criar cliente</Button>}>
14
+ <p>Conteúdo da listagem.</p>
15
+ </Page>
16
+ ```
17
17
 
18
- Nos botões da barra superior, declare `size="sm"` para texto e `size="icon-sm"` para ícones.
19
- `PageHeader` reserva uma linha mínima de `2rem`, mesmo sem ações; conteúdo maior pode expandi-la.
20
- `PageBack` já usa `icon-sm`. A mesma escala vale para ações nos headers de Dialog, Drawer e Surface, inclusive criação de coleções.
18
+ Use `default` para ações textuais do cabeçalho e `icon` para ícones. A linha reserva
19
+ `2,25rem` mesmo sem botões, evitando variação na altura. Drawer, Dialog e Surface compartilham
20
+ essa escala nos headers. Controles do body e dos menus mantêm sua escala local.
21
21
 
22
- `PageShell` não inclui sidebar nem inventa breadcrumb. Ele ocupa o painel principal já delimitado e
23
- entrega ao `PageHeader` descendente a navegação e as ações conhecidas pela aplicação, sem criar uma
24
- barra visual. Tabs ficam reservados a recortes da mesma superfície. Canvas e outros workspaces
25
- espaciais imersivos podem usar um shell próprio.
22
+ `PageActions` usa `ButtonGroup` internamente, sem moldura e com o espaçamento padrão de `0,25rem`.
23
+ O voltar e as ações fornecidas pelo shell e pela página entram no mesmo grupo, nessa ordem.
26
24
 
27
- Estados integrais de carregamento, falha ou ausência são compostos no body com `PageState`,
28
- detalhado abaixo. `Page` não recebe flags de dados: uma página pode agregar fontes independentes e
29
- uma falha parcial não deve ocultar as demais seções.
25
+ ## Composição explícita
26
+
27
+ Use os slots para acrescentar metadados ou compor as ações diretamente. Declare um título
28
+ principal no header. Não misture `title` da forma curta com `PageHeader` ou `PageBody`.
30
29
 
31
30
  ```tsx preview col
32
- render(
33
- <div className="w-full overflow-hidden rounded-lg border border-border">
34
- <Page
35
- title="Workspaces"
36
- actions={
37
- <Button variant="outline" size="sm">
38
- Exportar
39
- </Button>
40
- }
41
- >
42
- <div className="rounded-lg border border-dashed border-border p-10 text-center text-sm text-muted-foreground">
43
- O conteúdo da página (tabela, cards, grid…).
44
- </div>
45
- </Page>
46
- </div>,
47
- );
31
+ <Page>
32
+ <PageHeader>
33
+ <PageTitle>Carla Souza</PageTitle>
34
+ <PageMeta>Atualizado hoje · Por: Marina</PageMeta>
35
+ <PageActions>
36
+ <Button size="default">Editar</Button>
37
+ </PageActions>
38
+ </PageHeader>
39
+ <PageBody>Dados do cliente.</PageBody>
40
+ </Page>
48
41
  ```
49
42
 
50
- ## Orientar sobre a finalidade
43
+ `description` e `PageDescription` são orientações breves e opcionais. Regras necessárias
44
+ à decisão pertencem aos campos, às ações ou ao corpo. `PageMeta` recebe badges, autoria e
45
+ datas; o slot ausente não reserva espaço.
51
46
 
52
- Use `description` na forma curta ou `PageDescription` junto ao título em `PageIntro` ou `PageHeader` quando uma frase breve
53
- ajudar a reconhecer a finalidade da página. Omita texto que só repita o título. Regras de negócio,
54
- limites e consequências ficam nos campos, ações ou corpo em que são necessários. Pular o
55
- subheading não deve comprometer a decisão nem a conclusão correta da tarefa.
47
+ ## Abas no cabeçalho
56
48
 
57
- ```tsx
58
- <Page
59
- title="Conhecimento"
60
- description="Consulte os materiais de apoio da sua área."
61
- >
62
- <KnowledgeList />
63
- </Page>
49
+ Use `PageHeader.tabs` para reunir as abas ao cabeçalho. Com `layout="fill"`, elas
50
+ permanecem visíveis durante a rolagem dos resultados.
51
+ Envolva a página em `Tabs`, coloque `TabsList` no header e `TabsPanel` no body.
52
+ O cabeçalho fornece o alinhamento; seleção, indicador ativo e teclado continuam no Tabs. Ações da coleção ficam na barra da listagem dentro do painel ativo. `PageActions`
53
+ recebe somente ações gerais da página, sem repetir o título no painel.
54
+
55
+ ```tsx preview col
56
+ <Tabs defaultValue="deliveries" className="min-h-0 flex-1">
57
+ <Page>
58
+ <PageHeader
59
+ tabs={
60
+ <TabsList aria-label="Configurações de e-mail">
61
+ <TabsListItem value="deliveries">Envios</TabsListItem>
62
+ <TabsListItem value="senders">Remetentes</TabsListItem>
63
+ </TabsList>
64
+ }
65
+ >
66
+ <PageTitle>E-mails</PageTitle>
67
+ </PageHeader>
68
+ <PageBody>
69
+ <TabsPanel value="deliveries">Acompanhe as entregas de e-mail.</TabsPanel>
70
+ <TabsPanel value="senders">Configure os remetentes.</TabsPanel>
71
+ </PageBody>
72
+ </Page>
73
+ </Tabs>
64
74
  ```
65
75
 
76
+ `DrawerHeader`, `DialogHeader` e `SurfaceHeader` oferecem a mesma região `tabs`.
77
+ Ela recebe abas horizontais. Alertas e legendas de fieldset não aceitam essa região.
78
+ Para listas que ocupam a altura disponível, use `Page layout="fill"`; o `TabsPanel`
79
+ repassa essa altura à lista ativa. Sem `tabs`, a geometria do header permanece igual.
80
+
66
81
  ## Retorno para a página pai
67
82
 
68
- Use `PageBack` em uma subpágina simples. O destino é explícito para continuar correto após refresh ou
69
- acesso por link direto; não derive esse retorno do histórico do navegador. O controle aparece acima
70
- da linha do título como ícone; o nome acessível e a dica nativa do navegador (atributo
71
- `title`) derivam do destino.
83
+ Use `PageBack` com `href` explícito, que continue correto após acesso por link direto.
84
+ Para retorno controlado por uma pilha de Presentation, use `onBack` no lugar de `href`: ele
85
+ renderiza um botão acessível e aceita `disabled` durante operações.
86
+ Ele aparece como primeiro ícone das ações, em `ghost`, com nome acessível e tooltip.
87
+ O aplicativo precisa de `TooltipProvider`, como nos demais controles com tooltip.
72
88
 
73
89
  ```tsx preview col
74
90
  <Page>
75
91
  <PageHeader>
76
92
  <PageBack href="/customers">Clientes</PageBack>
93
+ <PageTitle>Carla Souza</PageTitle>
94
+ <PageActions>
95
+ <Button size="default">Editar</Button>
96
+ </PageActions>
77
97
  </PageHeader>
78
- <PageBody>
79
- <PageIntro>
80
- <PageTitle>Qualidade da base</PageTitle>
81
- </PageIntro>
82
- Conteúdo da análise.
83
- </PageBody>
98
+ <PageBody>Dados do cliente.</PageBody>
84
99
  </Page>
85
100
  ```
86
101
 
87
- Não combine `PageBack` com breadcrumb. Use o retorno para um único pai conhecido. Quando houver
88
- mais de um ancestral relevante, envolva o [`Breadcrumb`](/ui/breadcrumb) em `PageNavigation`; ele
89
- ocupa a mesma posição introdutória sem transformar a trilha em ação.
102
+ O retorno também pode ser declarado primeiro dentro de `PageActions`. Páginas raiz
103
+ não precisam dele. A navegação corrente não recebe uma segunda barra de breadcrumb.
90
104
 
91
- ```tsx preview col
92
- <Page>
93
- <PageHeader>
94
- <PageNavigation>
95
- <Breadcrumb>
96
- <BreadcrumbList>
97
- <BreadcrumbItem>Vendas</BreadcrumbItem>
98
- <BreadcrumbSeparator />
99
- <BreadcrumbItem>Clientes</BreadcrumbItem>
100
- <BreadcrumbSeparator />
101
- <BreadcrumbPage>Carla Souza</BreadcrumbPage>
102
- </BreadcrumbList>
103
- </Breadcrumb>
104
- </PageNavigation>
105
- </PageHeader>
106
- <PageBody>
107
- <PageIntro>
108
- <PageTitle>Carla Souza</PageTitle>
109
- </PageIntro>
110
- Dados do cliente.
111
- </PageBody>
112
- </Page>
113
- ```
114
-
115
- ## Contexto conhecido pelo shell
105
+ ## Ações conhecidas pelo shell
116
106
 
117
- Use `PageShell` quando o shell conhece o breadcrumb e a rota conhece ações globais ou uma
118
- introdução. Não crie um cabeçalho paralelo no layout nem esconda slots de `Page` com CSS. O Opus compõe a
119
- navegação e as ações do shell no `PageHeader` estável da página ativa.
107
+ `PageShell` entrega ações à Page descendente sem desenhar outro cabeçalho. Declare o retorno
108
+ antes das demais ações. Isso permite à aplicação escolher o pai e à rota cuidar do conteúdo.
120
109
 
121
110
  ```tsx preview col
122
- <PageShell
123
- navigation={
124
- <Breadcrumb>
125
- <BreadcrumbList>
126
- <BreadcrumbItem>Vendas</BreadcrumbItem>
127
- <BreadcrumbSeparator />
128
- <BreadcrumbPage>Clientes</BreadcrumbPage>
129
- </BreadcrumbList>
130
- </Breadcrumb>
131
- }
132
- >
133
- <Page
134
- title="Clientes"
135
- actions={
136
- <Button variant="outline" size="sm">
137
- Exportar
138
- </Button>
139
- }
140
- >
141
- Conteúdo da listagem.
111
+ <PageShell actions={<PageBack href="/customers">Clientes</PageBack>}>
112
+ <Page title="Carla Souza" actions={<Button size="default">Editar</Button>}>
113
+ Dados do cliente.
142
114
  </Page>
143
115
  </PageShell>
144
116
  ```
145
117
 
146
- Durante `PageState`, o cabeçalho inteiro desaparece e o título do estado assume o heading principal.
147
- Se uma ação não puder ser executada sem o conteúdo, a própria rota deve omiti-la naquele estado.
118
+ ## Listas e rolagem
148
119
 
149
- Na composição explícita, separe navegação e ações da superfície do título no corpo:
120
+ Use `layout="fill"` quando a lista deve ocupar a altura disponível. `ActionList` recebe a
121
+ altura por `PageBody` e mantém sua própria rolagem. O título pertence ao header da Page;
122
+ criação e outras operações da coleção ficam em `ActionList.toolbarActions`. Uma `Surface`
123
+ no body representa uma seção subordinada, não outro título principal.
150
124
 
151
- ```tsx preview col
152
- <PageShell
153
- navigation={
154
- <Breadcrumb>
155
- <BreadcrumbList>
156
- <BreadcrumbItem>Vendas</BreadcrumbItem>
157
- <BreadcrumbSeparator />
158
- <BreadcrumbPage>Clientes</BreadcrumbPage>
159
- </BreadcrumbList>
160
- </Breadcrumb>
161
- }
162
- >
163
- <Page>
164
- <PageHeader>
165
- <PageActions>
166
- <Button size="sm">Exportar</Button>
167
- </PageActions>
168
- </PageHeader>
169
- <PageBody>
170
- <PageIntro>
171
- <PageTitle>Clientes</PageTitle>
172
- </PageIntro>
173
- Conteúdo da listagem.
174
- </PageBody>
175
- </Page>
176
- </PageShell>
125
+ ```tsx
126
+ <Page title="Clientes" layout="fill">
127
+ <ActionList
128
+ action={customerListContract}
129
+ input={{}}
130
+ toolbarActions={<Button aria-label="Criar cliente">Criar</Button>}
131
+ />
132
+ </Page>
177
133
  ```
178
134
 
179
- ## Composição explícita
135
+ `flow`, o padrão, rola título e conteúdo juntos. `fill` mantém o header visível e permite
136
+ que uma região interna assuma a rolagem. Preserve a cadeia de altura no layout que hospeda
137
+ a Page; não acrescente outro contêiner vertical com rolagem ao redor.
180
138
 
181
- Use os slots quando a página precisar compor o cabeçalho diretamente. Não misture propriedades da
182
- forma curta com `PageHeader` ou `PageBody`.
139
+ O body separa seus blocos diretos por `1rem`. Uma grade ou grupo com ritmo próprio fica
140
+ num wrapper filho. O padding externo pertence à coluna; PageBody não acrescenta outro
141
+ recuo ao conteúdo.
183
142
 
184
- ```tsx preview col
185
- render(
186
- <Page>
187
- <PageHeader>
188
- <PageActions>
189
- <Button variant="outline" size="sm">
190
- Exportar
191
- </Button>
192
- </PageActions>
193
- </PageHeader>
194
- <PageBody>
195
- <PageIntro>
196
- <PageTitle>Workspaces</PageTitle>
197
- </PageIntro>
198
-
199
- <div className="rounded-lg border border-dashed border-border p-10 text-center">
200
- O conteúdo da página.
201
- </div>
202
- </PageBody>
203
- </Page>,
204
- );
205
- ```
206
-
207
- Em uma página de listagem, [`Surface`](/ui/surface) pode fornecer o título e as ações da coleção,
208
- deixando `Page` apenas com `PageBody`. Se `PageShell` fornecer navegação ou ações nesse caso, `Page`
209
- materializa somente o `PageHeader` necessário para recebê-las, sem duplicar o heading de `Surface`.
210
- [Composições](/ui/compositions) compara essa forma, com o título no corpo, à forma compacta, com o
211
- título no cabeçalho.
143
+ ## Rodapé de etapa
212
144
 
213
- ## Ações de etapa no rodapé
214
-
215
- Use `PageFooter` quando a página for uma etapa de um fluxo e a decisão precisar ficar ao alcance ao
216
- fim do conteúdo, como confirmar uma importação. O rodapé fica depois do body, com as ações alinhadas
217
- no fim da linha.
145
+ Use `PageFooter` quando a confirmação precisa permanecer disponível ao fim de uma etapa.
218
146
 
219
147
  ```tsx preview col
220
148
  <Page>
221
- <PageBody>
222
- <PageIntro>
223
- <PageTitle>Importar clientes</PageTitle>
224
- </PageIntro>
225
- Revise os 128 registros antes de confirmar.
226
- </PageBody>
149
+ <PageHeader>
150
+ <PageTitle>Importar clientes</PageTitle>
151
+ </PageHeader>
152
+ <PageBody>Revise os registros antes de confirmar.</PageBody>
227
153
  <PageFooter>
228
154
  <ButtonGroup mode="spaced">
229
155
  <Button variant="ghost">Cancelar</Button>
@@ -233,192 +159,96 @@ no fim da linha.
233
159
  </Page>
234
160
  ```
235
161
 
236
- ## Ocupar a altura disponível
237
-
238
- Use `layout="fill"` quando uma região interna, como uma tabela longa ou um split, precisar rolar
239
- dentro da página em vez de a página inteira rolar. A página passa a ocupar exatamente a altura do
240
- contêiner. Para uma região que você mesmo compõe, dê `min-h-0 flex-1` à que assume a folga e a
241
- rolagem, como o `PageBody` do exemplo.
242
-
243
- ```tsx preview col
244
- render(
245
- <div className="h-72 overflow-hidden rounded-lg border border-border">
246
- <Page layout="fill">
247
- <PageBody className="min-h-0 flex-1 overflow-y-auto">
248
- <PageIntro>
249
- <PageTitle>Ordens de serviço</PageTitle>
250
- </PageIntro>
251
-
252
- <div className="space-y-2">
253
- {[
254
- "OS-1842",
255
- "OS-1839",
256
- "OS-1835",
257
- "OS-1830",
258
- "OS-1827",
259
- "OS-1821",
260
- "OS-1818",
261
- ].map((id) => (
262
- <div
263
- key={id}
264
- className="rounded-md border border-border p-3 text-sm"
265
- >
266
- {id}
267
- </div>
268
- ))}
269
- </div>
270
- </PageBody>
271
- </Page>
272
- </div>,
273
- );
274
- ```
275
-
276
- Uma [`ActionList`](/ui/action-list) não precisa dessas classes. Filha de `PageBody`, ou de um
277
- [`Surface`](/ui/surface) dentro dele, ela recebe a altura da página e assume `layout="fill"`
278
- sozinha: `PageBody`, `Surface` e `SurfaceBody` passam a repassar a altura até ela, o cabeçalho da
279
- tabela fica fixo e só os resultados rolam. As demais seções do `PageBody` mantêm a altura do
280
- próprio conteúdo, e uma página `fill` sem lista não muda.
162
+ ## Carregamento, erro e ausência
281
163
 
282
- ## Levar as ações para um hospedeiro próprio
283
-
284
- Use `PageActionsTarget` somente quando um hospedeiro próprio tiver uma região externa para elas: as
285
- `PageActions` da árvore interna passam a ser
286
- renderizadas no elemento indicado em `target`. Enquanto `target` for `null`, fora de um shell, as
287
- ações continuam no cabeçalho da página.
164
+ `PageState` substitui o conteúdo durante um estado integral e assume o heading principal.
165
+ O header fica oculto nesse período; quando o conteúdo volta a ficar pronto, ele reaparece.
166
+ Uma falha parcial pertence à seção afetada e não deve ocultar as demais.
288
167
 
289
168
  ```tsx preview col
290
- function Example() {
291
- const [target, setTarget] = useState<HTMLElement | null>(null);
292
-
293
- return (
294
- <div className="space-y-3">
295
- <div
296
- ref={setTarget}
297
- className="flex justify-end rounded-lg border border-border p-2"
298
- />
299
- <PageActionsTarget target={target}>
300
- <Page
301
- title="Clientes"
302
- actions={
303
- <Button variant="outline" size="sm">
304
- Exportar
305
- </Button>
306
- }
307
- >
308
- Conteúdo da listagem.
309
- </Page>
310
- </PageActionsTarget>
311
- </div>
312
- );
313
- }
314
-
315
- render(<Example />);
316
- ```
317
-
318
- ## Estados integrais
319
-
320
- Use `PageState` quando carregamento, falha ou ausência substituírem todo o conteúdo principal. Na
321
- forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
322
- explícita, coloque-o sozinho dentro de `PageBody`. Enquanto `status` for `loading`, `error` ou
323
- `empty`, `Page` oculta o cabeçalho inteiro — incluindo a navegação e as ações recebidas de
324
- `PageShell` — e o estado ocupa a altura disponível. Uma subpágina que dependa do retorno oferece a
325
- saída pelo `action` do próprio `PageState`. O título do estado assume o heading principal. Esse
326
- registro também funciona quando um componente intermediário decide qual `PageState` renderizar. Em
327
- `ready`, o cabeçalho e o conteúdo voltam à composição normal.
328
-
329
- ```tsx preview col
330
- <Page title="Relatório">
169
+ <Page title="Clientes">
331
170
  <PageState
332
- status="error"
333
- title="Não foi possível carregar o relatório"
334
- description="Tente novamente. Se o problema continuar, volte mais tarde."
335
- onRetry={() => {}}
336
- retryLabel="Tentar novamente"
171
+ status="empty"
172
+ title="Nenhum cliente"
173
+ description="Crie um cliente para começar."
337
174
  />
338
175
  </Page>
339
176
  ```
340
177
 
341
- `loading` centraliza o `Spinner` num contêiner `role="status"`; `error` usa a mesma anatomia visual
342
- centralizada dos outros estados, conserva `role="alert"` e oferece uma ação `outline` textual quando
343
- há `onRetry`; `empty` centraliza `Empty` sem moldura; e `ready` entrega os filhos sem
344
- acrescentar uma superfície. A moldura tracejada continua reservada ao `Empty` usado diretamente para
345
- representar uma região disponível para criar ou vincular. `title` e `description` nomeiam a situação
346
- e, sem `title`, valem `errorMessage` e `emptyMessage`.
178
+ Use `onRetry` para oferecer recuperação. Não crie loaders e vazios paralelos a `ActionList`
179
+ quando os dados pertencem a uma coleção: a lista já governa esses estados.
347
180
 
348
- ```tsx preview col
349
- <Page title="Relatórios">
350
- <PageState
351
- status="empty"
352
- title="Nenhum relatório"
353
- description="Crie o primeiro relatório para começar."
354
- action={<Button>Criar relatório</Button>}
355
- />
356
- </Page>
357
- ```
181
+ ## Ações em um hospedeiro próprio
182
+
183
+ `PageActionsTarget` encaminha as ações para um elemento externo quando um hospedeiro precisa
184
+ dessa integração. Com `target={null}`, elas permanecem no cabeçalho. O destino deve preservar
185
+ nome acessível, ordem de foco e a associação com a página.
358
186
 
359
- Não use `PageState` para uma falha parcial. Se outra parte da página continua utilizável, mantenha o
360
- estado na própria seção com [`DataState`](/ui/data-state), [`ActionView`](/ui/action-view),
361
- [`ActionList`](/ui/action-list) ou [`Alert`](/ui/alert).
187
+ ## Migração
188
+
189
+ Mova `PageIntro` para `PageHeader` e `PageIntroActions` para `PageActions`. Remova o breadcrumb
190
+ e use `PageBack` quando houver um pai relevante. Retire limites de largura e classes locais
191
+ de título e padding que duplicavam o padrão. `PageIntro`, `PageIntroActions` e `PageNavigation`
192
+ foram removidos, sem aliases de compatibilidade. As opções
193
+ `flow` e `fill` continuam disponíveis. Remova `composition` e `pageComposition`: Page
194
+ tem uma única aparência. Para preservar a coluna intermediária de antigos documentos,
195
+ declare `width="default"` ou `page: { width: "default" }`. Sem largura explícita, a Page é ampla.
362
196
 
363
197
  ## Propriedades de Page
364
198
 
365
- | Propriedade | Tipo | Padrão | Descrição |
366
- | ------------- | -------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
367
- | `description` | `ReactNode` | | Orientação opcional sob o título na forma curta. |
368
- | `title` | `ReactNode` | | O h1 da página. |
369
- | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho. |
370
- | `layout` | `'flow' \| 'fill'` | `'flow'` | Ocupação de altura, não anatomia: `fill` limita a página ao shell para que uma região interna role e leva essa altura até uma `ActionList` composta em `PageBody`. |
371
- | `className` | `string` | | Classes do container externo. Para largura interna, use `contentClassName`. |
372
- | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
373
- | demais | Atributos de `HTMLElement` | | Atributos nativos repassados ao elemento `main`, como `id` ou `aria-label`. `className` vai para a moldura da página. |
199
+ | Propriedade | Tipo | Padrão | Descrição |
200
+ | ------------- | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
201
+ | `description` | `ReactNode` | | Orientação opcional sob o título na forma curta. |
202
+ | `meta` | `ReactNode` | | Forma curta: metadados sob o título e a orientação. Exige `title`. |
203
+ | `title` | `ReactNode` | | O h1 da página. |
204
+ | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho. |
205
+ | `layout` | `'flow' \| 'fill'` | `'flow'` | Ocupação de altura, não anatomia: `fill` limita a página ao shell para que uma região interna role e leva essa altura até uma `ActionList` composta em `PageBody`. |
206
+ | `className` | `string` | | Classes adicionais da coluna. Para escolher sua largura, use `width`. |
207
+ | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
208
+ | demais | Atributos de `HTMLElement` | | Atributos nativos repassados ao elemento `main`, como `id` ou `aria-label`. `className` vai para a moldura da página. |
209
+ | `width` | `'narrow' \| 'default' \| 'wide'` | `'wide'` | Limita a coluna inteira a 42rem, 58rem ou à largura disponível. |
374
210
 
375
211
  ## Propriedades de PageShell
376
212
 
377
- | Propriedade | Tipo | Descrição |
378
- | ------------ | ----------------------------- | ------------------------------------------------------------------------------------------ |
379
- | `navigation` | `ReactNode` | Navegação contextual composta na linha de controles do header no `PageHeader` descendente. |
380
- | `actions` | `ReactNode` | Ações conhecidas pelo shell, antes das ações declaradas pela `Page`. |
381
- | `children` | `ReactNode` | Rota que renderiza uma `Page` descendente. |
382
- | `className` | `string` | Classes adicionais da moldura. |
383
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados à moldura. |
213
+ | Propriedade | Tipo | Descrição |
214
+ | ----------- | ----------------------------- | -------------------------------------------------------------------- |
215
+ | `actions` | `ReactNode` | Ações conhecidas pelo shell, antes das ações declaradas pela `Page`. |
216
+ | `children` | `ReactNode` | Rota que renderiza uma `Page` descendente. |
217
+ | `className` | `string` | Classes adicionais da moldura. |
218
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados à moldura. |
384
219
 
385
- `surfaceLayout?: 'sectioned' | 'continuous'` escolhe os divisores; o padrão é `sectioned`.
220
+ A Page não insere divisores entre header, body e footer.
386
221
  `contentClassName?: string` configura largura e alinhamento do conteúdo. O ritmo e os recuos
387
- continuam sob responsabilidade do body; não use essa prop para substituir padding ou gap.
222
+ pertencem à Page; não use essa prop para substituir padding ou gap.
388
223
 
389
224
  ## Propriedades de PageHeader
390
225
 
391
- | Propriedade | Tipo | Descrição |
392
- | ----------- | ----------------------------- | ------------------------------------------------------------------------ |
393
- | `className` | `string` | Classes adicionais do cabeçalho estável. |
394
- | `children` | `ReactNode` | `PageBack` ou `PageNavigation`, um `PageTitle` opcional e `PageActions`. |
395
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao cabeçalho. |
226
+ | Propriedade | Tipo | Descrição |
227
+ | ----------- | ----------------------------- | ------------------------------------------------------------------------- |
228
+ | `tabs` | `ReactNode` | `TabsList` sob o título, controlado por um `Tabs` ancestral. |
229
+ | `className` | `string` | Classes adicionais do cabeçalho estável. |
230
+ | `children` | `ReactNode` | `PageTitle`, metadados e ações; `PageBack` é inserido primeiro nas ações. |
231
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao cabeçalho. |
396
232
 
397
233
  ## Propriedades de PageBack
398
234
 
399
235
  | Propriedade | Tipo | Padrão | Descrição |
400
236
  | ------------ | -------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------ |
401
- | `href` | `string` | obrigatório | Destino explícito da página pai. Sem ele o retorno não é tabulável nem tem nome acessível. |
402
- | `children` | `ReactNode` | obrigatório | Nome do destino pai usado no rótulo acessível e na dica nativa (`title`). |
237
+ | `href` | `string` | | Destino explícito da página pai; obrigatório quando não há `onBack`. |
238
+ | `onBack` | `() => void` | | Retorno controlado pela pilha; renderiza botão e não aceita `href`. |
239
+ | `disabled` | `boolean` | `false` | Bloqueia o retorno quando usado com `onBack`. |
240
+ | `children` | `ReactNode` | obrigatório | Nome do destino pai usado no rótulo acessível e na tooltip. |
403
241
  | `aria-label` | `string` | `Voltar para {children}` | Nome acessível; informe-o quando `children` não for texto simples. |
404
242
  | `onClick` | `MouseEventHandler<HTMLAnchorElement>` | | Integração opcional com o roteador do consumidor, junto do `href`, nunca no lugar dele. |
405
243
  | `className` | `string` | | Classes adicionais do link renderizado como botão `ghost`. |
406
244
 
407
- ## Propriedades de PageNavigation
408
-
409
- | Propriedade | Tipo | Descrição |
410
- | ----------- | ----------------------------- | ----------------------------------------------- |
411
- | `children` | `ReactNode` | Trilha estrutural, normalmente um `Breadcrumb`. |
412
- | `className` | `string` | Classes adicionais do container introdutório. |
413
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
414
-
415
245
  ## Propriedades de PageTitle
416
246
 
417
- | Propriedade | Tipo | Descrição |
418
- | ----------- | --------------------------------- | ----------------------------------------------------- |
419
- | `children` | `ReactNode` | Título principal `h1` na intro ou no header compacto. |
420
- | `className` | `string` | Classes adicionais do título. |
421
- | demais | Atributos de `HTMLHeadingElement` | Atributos nativos repassados ao heading. |
247
+ | Propriedade | Tipo | Descrição |
248
+ | ----------- | --------------------------------- | ---------------------------------------- |
249
+ | `children` | `ReactNode` | Título principal `h1` no header. |
250
+ | `className` | `string` | Classes adicionais do título. |
251
+ | demais | Atributos de `HTMLHeadingElement` | Atributos nativos repassados ao heading. |
422
252
 
423
253
  ## Propriedades de PageActions
424
254
 
@@ -440,7 +270,9 @@ continuam sob responsabilidade do body; não use essa prop para substituir paddi
440
270
 
441
271
  `contentClassName?: string` configura largura e alinhamento do container interno.
442
272
 
443
- `PageBody` separa seus blocos diretos por `1rem` e fornece os recuos internos. Uma grade, lista compacta ou linha horizontal fica dentro de um wrapper próprio.
273
+ O recuo externo permanece na coluna mesmo quando o body usa `flush`.
274
+
275
+ `PageBody` separa seus blocos diretos por `1rem`; o recuo externo pertence à coluna. Uma grade, lista compacta ou linha horizontal fica dentro de um wrapper próprio.
444
276
 
445
277
  | Propriedade | Tipo | Descrição |
446
278
  | ----------- | ----------------------------- | --------------------------------------------------- |
@@ -476,63 +308,52 @@ ocupa a altura.
476
308
 
477
309
  ## Propriedades de PageDescription
478
310
 
479
- | Propriedade | Tipo | Padrão | Descrição |
480
- | ----------- | -------------------------------------- | ------ | ------------------------------------------------------------------------- |
481
- | `children` | `ReactNode` | | Orientação breve e opcional; filho direto da intro ou do header compacto. |
482
- | `className` | `string` | | Ajusta a apresentação do parágrafo. |
483
- | `…props` | `HTMLAttributes<HTMLParagraphElement>` | | Atributos nativos. |
484
-
485
- ## Composição compacta
311
+ | Propriedade | Tipo | Padrão | Descrição |
312
+ | ----------- | -------------------------------------- | ------ | ---------------------------------------------------- |
313
+ | `children` | `ReactNode` | | Orientação breve e opcional; filho direto do header. |
314
+ | `className` | `string` | | Ajusta a apresentação do parágrafo. |
315
+ | `…props` | `HTMLAttributes<HTMLParagraphElement>` | | Atributos nativos. |
486
316
 
487
- Quando o cabeçalho também identifica o conteúdo, mantenha o título nele e omita a intro.
488
- Não declare o mesmo título nas duas regiões.
317
+ ## Propriedades de PageMeta
489
318
 
490
- ```tsx preview col
491
- <Page>
492
- <PageHeader>
493
- <PageTitle>Preferências</PageTitle>
494
- </PageHeader>
495
- <PageBody>Configurações da conta.</PageBody>
496
- </Page>
497
- ```
319
+ | Propriedade | Tipo | Descrição |
320
+ | ----------- | ----------- | ------------------------------------------------------- |
321
+ | `children` | `ReactNode` | Badges, datas, autoria ou outros metadados do registro. |
322
+ | `className` | `string` | Ajusta a faixa de metadados. |
498
323
 
499
- ## Propriedades de PageIntro
324
+ Aceita atributos nativos de `div`. O intervalo superior é de 0,75rem; os itens têm
325
+ 0,75rem entre colunas e 0,5rem entre linhas. O componente não insere separadores nem
326
+ carrega dados. Omitir o slot não reserva espaço. Metadados não substituem orientações
327
+ ou condições necessárias à decisão e não substituem a descrição textual da região.
500
328
 
501
- Aceita atributos HTML de `div` e exige um `PageTitle`. Recebe opcionalmente `PageDescription` e
502
- `PageIntroActions`. Deve abrir o `PageBody`; navegação e ações da superfície ficam no header.
329
+ Presentation com `heading: "content"` recebe uma Page completa, inclusive quando o conteúdo
330
+ vem de um componente de rota. O runtime rejeita conteúdo sem Page e dois rodapés concorrentes
331
+ (PageFooter próprio e comandos de footer da Presentation), em vez de descartar ações.
503
332
 
504
- | Propriedade | Tipo | Descrição |
505
- | ----------- | ----------------------------- | ------------------------------------------------------------------------ |
506
- | `children` | `ReactNode` | Um `PageTitle` e, opcionalmente, `PageDescription` e `PageIntroActions`. |
507
- | `className` | `string` | Classes adicionais da introdução. |
508
- | demais | Atributos de `HTMLDivElement` | Repassados à região introdutória. |
509
333
 
510
- ## Propriedades de PageIntroActions
334
+ ## Página centralizada
511
335
 
512
- Agrupa ações locais do conteúdo no extremo oposto ao título da intro.
336
+ Para configurações curtas, escolha uma coluna estreita:
513
337
 
514
- | Propriedade | Tipo | Descrição |
515
- | ----------- | ----------------------------- | ----------------------------------------------- |
516
- | `children` | `ReactNode` | Controles relacionados ao conteúdo apresentado. |
517
- | `className` | `string` | Classes adicionais do agrupamento. |
518
- | demais | Atributos de `HTMLDivElement` | Repassados ao agrupamento. |
519
-
520
- O header ocupa toda a largura disponível. O limite de 80rem e o recuo pertencem ao conteúdo
521
- interno do Body; o viewport ocupa a largura da página para manter sua barra de rolagem na extremidade.
522
-
523
- ### Divisão visual das regiões
338
+ ```tsx
339
+ <Page width="narrow" title="Segurança">
340
+ <SecuritySettings />
341
+ </Page>
342
+ ```
524
343
 
525
- Use `surfaceLayout="sectioned"` (padrão) para separar header, body e footer com divisores.
526
- Use `surfaceLayout="continuous"` para uma composição sem divisores. O header vazio continua
527
- omitido. Essa escolha é independente de `layout="flow" | "fill"`, que controla a altura e a rolagem.
344
+ Título, conteúdo e rodapé compartilham o mesmo limite de largura. Com `layout="flow"`,
345
+ rolam juntos e a barra permanece na borda da Page. Com `layout="fill"`, o título permanece
346
+ visível e a lista recebe a altura restante para rolar seus resultados. Sem lista, o body rola.
347
+ As duas ocupações usam a mesma aparência e o mesmo padding.
528
348
 
529
- ## Largura e rolagem
349
+ ## Largura da coluna
530
350
 
531
- `Page` e `PageBody` aceitam `contentClassName` para o container interno de leitura.
532
- Use `contentClassName="max-w-none"` para largura total ou `max-w-5xl` para uma leitura
533
- mais estreita, mantendo o header e a barra de rolagem na extremidade. `className` em Page
534
- controla a moldura externa; em PageBody, controla o viewport.
351
+ Use `width="narrow"` para preferências curtas, `width="default"` para conteúdo intermediário e
352
+ `width="wide"` para tabelas que precisam da largura disponível. Os limites são 42rem, 58rem e
353
+ sem teto, respectivamente, incluindo o padding da coluna. Header, Body e Footer compartilham
354
+ esse limite; os espaçamentos internos não mudam.
535
355
 
536
- PageShell permite rolagem de contingência quando a rota renderiza um fallback ou um
537
- wrapper sem altura definida. Para manter o header fixo, a rota deve preservar a cadeia
538
- flexível de altura até Page. Uma Page diretamente no shell já segue esse contrato.
356
+ Sem `width`, a Page ocupa a largura disponível. Na declaração da Presentation, use
357
+ `page: { width: "wide" }`. Quando o conteúdo fornece uma Page completa, ela herda essa
358
+ largura e pode substituí-la com sua própria prop `width`.
359
+ O dimensionamento de Dialog e Drawer permanece independente.