@softize/opus 30.0.0 → 31.1.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 (64) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/bin/lib/check.mjs +109 -101
  3. package/bin/lib/copy.mjs +2973 -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/0060-surface-composition-separates-chrome-and-intro.md +142 -0
  7. package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
  8. package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
  9. package/docs/adr/0066-civil-date-input-and-calendar-list.md +28 -0
  10. package/docs/adr/README.md +6 -0
  11. package/package.json +1 -1
  12. package/registry/skills/build-opus-ui/SKILL.md +21 -19
  13. package/registry/skills/build-opus-ui/references/evaluations.md +13 -11
  14. package/registry/skills/build-opus-ui/references/ui-patterns.md +24 -27
  15. package/src/core/presentation.ts +938 -32
  16. package/src/core/types.ts +2 -0
  17. package/src/ui/components/patterns/form.tsx +22 -1
  18. package/src/ui/components/patterns/grouped-list.ts +2 -2
  19. package/src/ui/components/patterns/list-calendar.tsx +129 -0
  20. package/src/ui/components/patterns/list.tsx +612 -382
  21. package/src/ui/components/patterns/page-heading-context.tsx +12 -5
  22. package/src/ui/components/patterns/page.tsx +227 -197
  23. package/src/ui/components/patterns/presentation-fields.tsx +246 -0
  24. package/src/ui/components/patterns/presentation-sections.tsx +494 -0
  25. package/src/ui/components/patterns/presentation.tsx +1142 -229
  26. package/src/ui/components/patterns/structural-header.tsx +23 -32
  27. package/src/ui/components/patterns/surface-anatomy.ts +27 -217
  28. package/src/ui/components/patterns/surface.tsx +19 -29
  29. package/src/ui/components/patterns/trigger.tsx +10 -2
  30. package/src/ui/components/primitives/calendar.tsx +39 -18
  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/date-input.tsx +276 -0
  34. package/src/ui/components/primitives/detail.tsx +1 -1
  35. package/src/ui/components/primitives/dialog.tsx +19 -81
  36. package/src/ui/components/primitives/drawer.tsx +17 -79
  37. package/src/ui/components/primitives/field.tsx +1 -1
  38. package/src/ui/components/primitives/pagination.tsx +3 -2
  39. package/src/ui/components/primitives/table.tsx +1 -1
  40. package/src/ui/components/primitives/tabs.tsx +13 -2
  41. package/src/ui/docs/content/action-form.md +6 -1
  42. package/src/ui/docs/content/action-list.md +156 -68
  43. package/src/ui/docs/content/action-trigger.md +5 -0
  44. package/src/ui/docs/content/button.md +5 -6
  45. package/src/ui/docs/content/calendar-month-view.md +50 -0
  46. package/src/ui/docs/content/calendar.md +6 -1
  47. package/src/ui/docs/content/command.md +62 -50
  48. package/src/ui/docs/content/compositions.md +129 -459
  49. package/src/ui/docs/content/date-input.md +67 -0
  50. package/src/ui/docs/content/dialog.md +44 -112
  51. package/src/ui/docs/content/drawer.md +44 -103
  52. package/src/ui/docs/content/field.md +2 -1
  53. package/src/ui/docs/content/input.md +3 -0
  54. package/src/ui/docs/content/page.md +204 -412
  55. package/src/ui/docs/content/presentation.md +371 -23
  56. package/src/ui/docs/content/separator.md +1 -1
  57. package/src/ui/docs/content/surface.md +65 -120
  58. package/src/ui/docs/content/tokens.md +18 -4
  59. package/src/ui/docs/registry.tsx +38 -9
  60. package/src/ui/drivers/context.tsx +11 -4
  61. package/src/ui/drivers/react.tsx +27 -7
  62. package/src/ui/meta.ts +17 -6
  63. package/src/ui/react.tsx +41 -8
  64. 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.
90
-
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
- ```
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.
114
104
 
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
180
-
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`.
183
-
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
- ```
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.
206
138
 
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.
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.
212
142
 
213
- ## Ações de etapa no rodapé
143
+ ## Rodapé de etapa
214
144
 
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,209 +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.
281
-
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.
288
-
289
- ```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
162
+ ## Carregamento, erro e ausência
319
163
 
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.
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.
328
167
 
329
168
  ```tsx preview col
330
- <Page title="Relatório">
331
- <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"
337
- />
338
- </Page>
339
- ```
340
-
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`.
347
-
348
- ```tsx preview col
349
- <Page title="Relatórios">
169
+ <Page title="Clientes">
350
170
  <PageState
351
171
  status="empty"
352
- title="Nenhum relatório"
353
- description="Crie o primeiro relatório para começar."
354
- action={<Button>Criar relatório</Button>}
172
+ title="Nenhum cliente"
173
+ description="Crie um cliente para começar."
355
174
  />
356
175
  </Page>
357
176
  ```
358
177
 
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).
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.
362
180
 
363
- ## Metadados junto à identidade
181
+ ## Ações em um hospedeiro próprio
364
182
 
365
- Use `PageMeta` para badges, autoria e datas relacionados ao registro. A faixa fica
366
- abaixo da linha de título e ações, com espaço próprio; `PageDescription` continua
367
- reservado à orientação textual breve. Os itens quebram em várias linhas quando necessário.
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.
368
186
 
369
- ```tsx preview col
370
- render(
371
- <Page title="Manual de atendimento" description="Orientações para a equipe." meta={<><Badge>Publicado</Badge><span>Por Ana</span></>}>
372
- <p>Conteúdo do manual.</p>
373
- </Page>
374
- );
375
- ```
187
+ ## Migração
376
188
 
377
- A composição aceita um único `PageMeta` e exige um `PageTitle`. Na forma explícita, coloque-o em `PageIntro` ou no `PageHeader` compacto. Não coloque o slot solto no corpo.
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.
378
196
 
379
197
  ## Propriedades de Page
380
198
 
381
- | Propriedade | Tipo | Padrão | Descrição |
382
- | ------------- | -------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
383
- | `description` | `ReactNode` | | Orientação opcional sob o título na forma curta. |
384
- | `meta` | `ReactNode` | | Forma curta: metadados sob o título e a orientação. Exige `title`. |
385
- | `title` | `ReactNode` | | O h1 da página. |
386
- | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho. |
387
- | `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`. |
388
- | `className` | `string` | | Classes do container externo. Para largura interna, use `contentClassName`. |
389
- | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
390
- | 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. |
391
210
 
392
211
  ## Propriedades de PageShell
393
212
 
394
- | Propriedade | Tipo | Descrição |
395
- | ------------ | ----------------------------- | ------------------------------------------------------------------------------------------ |
396
- | `navigation` | `ReactNode` | Navegação contextual composta na linha de controles do header no `PageHeader` descendente. |
397
- | `actions` | `ReactNode` | Ações conhecidas pelo shell, antes das ações declaradas pela `Page`. |
398
- | `children` | `ReactNode` | Rota que renderiza uma `Page` descendente. |
399
- | `className` | `string` | Classes adicionais da moldura. |
400
- | 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. |
401
219
 
402
- `surfaceLayout?: 'sectioned' | 'continuous'` escolhe os divisores; o padrão é `sectioned`.
220
+ A Page não insere divisores entre header, body e footer.
403
221
  `contentClassName?: string` configura largura e alinhamento do conteúdo. O ritmo e os recuos
404
- 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.
405
223
 
406
224
  ## Propriedades de PageHeader
407
225
 
408
- | Propriedade | Tipo | Descrição |
409
- | ----------- | ----------------------------- | ------------------------------------------------------------------------ |
410
- | `className` | `string` | Classes adicionais do cabeçalho estável. |
411
- | `children` | `ReactNode` | `PageBack` ou `PageNavigation`, um `PageTitle` opcional e `PageActions`. |
412
- | 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. |
413
232
 
414
233
  ## Propriedades de PageBack
415
234
 
416
235
  | Propriedade | Tipo | Padrão | Descrição |
417
236
  | ------------ | -------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------ |
418
- | `href` | `string` | obrigatório | Destino explícito da página pai. Sem ele o retorno não é tabulável nem tem nome acessível. |
419
- | `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. |
420
241
  | `aria-label` | `string` | `Voltar para {children}` | Nome acessível; informe-o quando `children` não for texto simples. |
421
242
  | `onClick` | `MouseEventHandler<HTMLAnchorElement>` | | Integração opcional com o roteador do consumidor, junto do `href`, nunca no lugar dele. |
422
243
  | `className` | `string` | | Classes adicionais do link renderizado como botão `ghost`. |
423
244
 
424
- ## Propriedades de PageNavigation
425
-
426
- | Propriedade | Tipo | Descrição |
427
- | ----------- | ----------------------------- | ----------------------------------------------- |
428
- | `children` | `ReactNode` | Trilha estrutural, normalmente um `Breadcrumb`. |
429
- | `className` | `string` | Classes adicionais do container introdutório. |
430
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
431
-
432
245
  ## Propriedades de PageTitle
433
246
 
434
- | Propriedade | Tipo | Descrição |
435
- | ----------- | --------------------------------- | ----------------------------------------------------- |
436
- | `children` | `ReactNode` | Título principal `h1` na intro ou no header compacto. |
437
- | `className` | `string` | Classes adicionais do título. |
438
- | 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. |
439
252
 
440
253
  ## Propriedades de PageActions
441
254
 
@@ -457,7 +270,9 @@ continuam sob responsabilidade do body; não use essa prop para substituir paddi
457
270
 
458
271
  `contentClassName?: string` configura largura e alinhamento do container interno.
459
272
 
460
- `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.
461
276
 
462
277
  | Propriedade | Tipo | Descrição |
463
278
  | ----------- | ----------------------------- | --------------------------------------------------- |
@@ -493,75 +308,52 @@ ocupa a altura.
493
308
 
494
309
  ## Propriedades de PageDescription
495
310
 
496
- | Propriedade | Tipo | Padrão | Descrição |
497
- | ----------- | -------------------------------------- | ------ | ------------------------------------------------------------------------- |
498
- | `children` | `ReactNode` | | Orientação breve e opcional; filho direto da intro ou do header compacto. |
499
- | `className` | `string` | | Ajusta a apresentação do parágrafo. |
500
- | `…props` | `HTMLAttributes<HTMLParagraphElement>` | | Atributos nativos. |
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. |
501
316
 
502
- ## Composição compacta
503
-
504
- Quando o cabeçalho também identifica o conteúdo, mantenha o título nele e omita a intro.
505
- Não declare o mesmo título nas duas regiões.
506
-
507
- ```tsx preview col
508
- <Page>
509
- <PageHeader>
510
- <PageTitle>Preferências</PageTitle>
511
- </PageHeader>
512
- <PageBody>Configurações da conta.</PageBody>
513
- </Page>
514
- ```
515
-
516
- ## Propriedades de PageIntro
517
-
518
- Aceita atributos HTML de `div` e exige um `PageTitle`. Recebe opcionalmente `PageDescription` e
519
- `PageIntroActions`. Deve abrir o `PageBody`; navegação e ações da superfície ficam no header.
520
-
521
- | Propriedade | Tipo | Descrição |
522
- | ----------- | ----------------------------- | ------------------------------------------------------------------------ |
523
- | `children` | `ReactNode` | Um `PageTitle` e, opcionalmente, `PageDescription`, `PageMeta` e `PageIntroActions`. |
524
- | `className` | `string` | Classes adicionais da introdução. |
525
- | demais | Atributos de `HTMLDivElement` | Repassados à região introdutória. |
526
-
527
- ## Propriedades de PageIntroActions
317
+ ## Propriedades de PageMeta
528
318
 
529
- Agrupa ações locais do conteúdo no extremo oposto ao título da intro.
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. |
530
323
 
531
- | Propriedade | Tipo | Descrição |
532
- | ----------- | ----------------------------- | ----------------------------------------------- |
533
- | `children` | `ReactNode` | Controles relacionados ao conteúdo apresentado. |
534
- | `className` | `string` | Classes adicionais do agrupamento. |
535
- | demais | Atributos de `HTMLDivElement` | Repassados ao agrupamento. |
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.
536
328
 
537
- O header ocupa toda a largura disponível. O limite de 80rem e o recuo pertencem ao conteúdo
538
- interno do Body; o viewport ocupa a largura da página para manter sua barra de rolagem na extremidade.
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.
539
332
 
540
- ### Divisão visual das regiões
541
333
 
542
- Use `surfaceLayout="sectioned"` (padrão) para separar header, body e footer com divisores.
543
- Use `surfaceLayout="continuous"` para uma composição sem divisores. O header vazio continua
544
- omitido. Essa escolha é independente de `layout="flow" | "fill"`, que controla a altura e a rolagem.
334
+ ## Página centralizada
545
335
 
546
- ## Largura e rolagem
336
+ Para configurações curtas, escolha uma coluna estreita:
547
337
 
548
- `Page` e `PageBody` aceitam `contentClassName` para o container interno de leitura.
549
- Use `contentClassName="max-w-none"` para largura total ou `max-w-5xl` para uma leitura
550
- mais estreita, mantendo o header e a barra de rolagem na extremidade. `className` em Page
551
- controla a moldura externa; em PageBody, controla o viewport.
338
+ ```tsx
339
+ <Page width="narrow" title="Segurança">
340
+ <SecuritySettings />
341
+ </Page>
342
+ ```
552
343
 
553
- PageShell permite rolagem de contingência quando a rota renderiza um fallback ou um
554
- wrapper sem altura definida. Para manter o header fixo, a rota deve preservar a cadeia
555
- flexível de altura até Page. Uma Page diretamente no shell já segue esse contrato.
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.
556
348
 
557
- ## Propriedades de PageMeta
349
+ ## Largura da coluna
558
350
 
559
- | Propriedade | Tipo | Descrição |
560
- | --- | --- | --- |
561
- | `children` | `ReactNode` | Badges, datas, autoria ou outros metadados do registro. |
562
- | `className` | `string` | Ajusta a faixa de metadados. |
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.
563
355
 
564
- Aceita atributos nativos de `div`. O intervalo superior é de 0,75rem; os itens têm
565
- 0,75rem entre colunas e 0,5rem entre linhas. O componente não insere separadores nem
566
- carrega dados. Omitir o slot não reserva espaço. Metadados não substituem orientações
567
- ou condições necessárias à decisão e não substituem a descrição textual da região.
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.