@softize/opus 27.1.0 → 29.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 (64) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/bin/cli.mjs +68 -3
  3. package/bin/lib/check.mjs +139 -30
  4. package/bin/lib/copy.mjs +505 -67
  5. package/bin/lib/materialize.mjs +99 -1
  6. package/docs/adr/0015-action-size-follows-interaction-density.md +2 -0
  7. package/docs/adr/0028-schedules-run-actions-as-the-system-by-action-opt-in.md +1 -1
  8. package/docs/adr/0029-page-header-is-the-single-page-introduction.md +3 -1
  9. package/docs/adr/0037-design-data-lives-outside-the-contract.md +1 -1
  10. package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +161 -0
  11. package/docs/adr/0061-claude-md-imports-agents-md.md +41 -0
  12. package/docs/adr/README.md +4 -0
  13. package/docs/code-style.md +47 -8
  14. package/docs/protocol.md +1 -1
  15. package/docs/releasing.md +7 -0
  16. package/package.json +1 -1
  17. package/registry/instructions/opus.md +3 -1
  18. package/registry/skills/build-opus-ui/SKILL.md +16 -14
  19. package/registry/skills/build-opus-ui/references/evaluations.md +10 -0
  20. package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -15
  21. package/registry/skills/maintain-opus-docs/SKILL.md +2 -1
  22. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +9 -0
  23. package/registry/skills/maintain-opus-docs/references/evaluations.md +8 -0
  24. package/registry/templates/app/pnpm-workspace.yaml +1 -1
  25. package/src/core/system-actor.ts +1 -1
  26. package/src/ui/components/patterns/list.tsx +63 -54
  27. package/src/ui/components/patterns/page.tsx +146 -38
  28. package/src/ui/components/patterns/presentation.tsx +44 -59
  29. package/src/ui/components/patterns/structural-header.tsx +42 -6
  30. package/src/ui/components/patterns/surface-anatomy.ts +52 -22
  31. package/src/ui/components/patterns/surface.tsx +2 -3
  32. package/src/ui/components/primitives/control.ts +2 -2
  33. package/src/ui/components/primitives/dialog.tsx +7 -2
  34. package/src/ui/components/primitives/drawer.tsx +7 -2
  35. package/src/ui/components/primitives/icon-picker.tsx +271 -34
  36. package/src/ui/components/primitives/pagination.tsx +5 -4
  37. package/src/ui/components/primitives/tabs.tsx +15 -2
  38. package/src/ui/components/primitives/toggle.tsx +1 -1
  39. package/src/ui/docs/content/action-list.md +12 -3
  40. package/src/ui/docs/content/actions.md +1 -1
  41. package/src/ui/docs/content/auth.md +3 -3
  42. package/src/ui/docs/content/button.md +7 -7
  43. package/src/ui/docs/content/cli.md +6 -0
  44. package/src/ui/docs/content/communication.md +10 -8
  45. package/src/ui/docs/content/compositions.md +35 -23
  46. package/src/ui/docs/content/dialog.md +18 -6
  47. package/src/ui/docs/content/drawer.md +17 -5
  48. package/src/ui/docs/content/events.md +13 -13
  49. package/src/ui/docs/content/icon-picker.md +37 -19
  50. package/src/ui/docs/content/input.md +1 -1
  51. package/src/ui/docs/content/installation.md +4 -0
  52. package/src/ui/docs/content/log.md +1 -1
  53. package/src/ui/docs/content/page.md +169 -69
  54. package/src/ui/docs/content/pagination.md +7 -8
  55. package/src/ui/docs/content/presentation.md +4 -3
  56. package/src/ui/docs/content/queue.md +2 -2
  57. package/src/ui/docs/content/router.md +1 -1
  58. package/src/ui/docs/content/scheduler.md +15 -15
  59. package/src/ui/docs/content/surface.md +8 -5
  60. package/src/ui/docs/content/tabs.md +12 -4
  61. package/src/ui/docs/content/testing.md +4 -4
  62. package/src/ui/meta.ts +1 -1
  63. package/src/ui/react.tsx +9 -1
  64. package/src/vite/design.ts +1 -1
@@ -1,21 +1,23 @@
1
1
  ## Esqueleto de página
2
2
 
3
- Use `Page` para manter cabeçalho, estado e conteúdo na mesma anatomia. `PageHeader` é a única
4
- introdução estrutural: reúne navegação contextual opcional, título, orientação opcional e ações. O container é
5
- centralizado e ocupa a largura disponível até `80rem` (`max-w-7xl`). Use `className` somente quando
6
- a composição pedir outro teto ou largura total.
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.
7
7
 
8
- A forma curta é o padrão para páginas comuns e cria `PageHeader` e `PageBody`. A forma explícita
9
- exige exatamente um heading principal. Use `PageTitle` no cabeçalho, `Surface level={1}` no body,
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
10
  ou deixe um `PageState` ativo assumir esse papel. O cabeçalho pode ser omitido quando o próprio
11
11
  conteúdo nomeia a página. Contadores e outros indicadores pertencem ao conteúdo que os explica.
12
12
 
13
- A `Page` é contínua por definição e não há divisores entre suas regiões. O `layout` da `Page` não
14
- é a anatomia de superfície de
15
- [`Surface`](/ui/surface), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) e [`Pane`](/ui/pane) — aqui ele
16
- decide a ocupação de altura. `flow`, o padrão, deixa a página crescer e a rolagem acontecer na
17
- janela; `fill` limita a página à altura do shell para que uma região interna, como uma tabela longa
18
- ou um split, assuma a rolagem.
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.
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.
19
21
 
20
22
  `PageShell` não inclui sidebar nem inventa breadcrumb. Ele ocupa o painel principal já delimitado e
21
23
  entrega ao `PageHeader` descendente a navegação e as ações conhecidas pela aplicação, sem criar uma
@@ -31,7 +33,11 @@ render(
31
33
  <div className="w-full overflow-hidden rounded-lg border border-border">
32
34
  <Page
33
35
  title="Workspaces"
34
- actions={<Button variant="outline">Exportar</Button>}
36
+ actions={
37
+ <Button variant="outline" size="sm">
38
+ Exportar
39
+ </Button>
40
+ }
35
41
  >
36
42
  <div className="rounded-lg border border-dashed border-border p-10 text-center text-sm text-muted-foreground">
37
43
  O conteúdo da página (tabela, cards, grid…).
@@ -43,13 +49,16 @@ render(
43
49
 
44
50
  ## Orientar sobre a finalidade
45
51
 
46
- Use `description` na forma curta ou `PageDescription` em `PageHeader` quando uma frase breve
52
+ Use `description` na forma curta ou `PageDescription` junto ao título em `PageIntro` ou `PageHeader` quando uma frase breve
47
53
  ajudar a reconhecer a finalidade da página. Omita texto que só repita o título. Regras de negócio,
48
54
  limites e consequências ficam nos campos, ações ou corpo em que são necessários. Pular o
49
55
  subheading não deve comprometer a decisão nem a conclusão correta da tarefa.
50
56
 
51
57
  ```tsx
52
- <Page title="Conhecimento" description="Consulte os materiais de apoio da sua área.">
58
+ <Page
59
+ title="Conhecimento"
60
+ description="Consulte os materiais de apoio da sua área."
61
+ >
53
62
  <KnowledgeList />
54
63
  </Page>
55
64
  ```
@@ -65,9 +74,13 @@ da linha do título como ícone; o nome acessível e a dica nativa do navegador
65
74
  <Page>
66
75
  <PageHeader>
67
76
  <PageBack href="/customers">Clientes</PageBack>
68
- <PageTitle>Qualidade da base</PageTitle>
69
77
  </PageHeader>
70
- <PageBody>Conteúdo da análise.</PageBody>
78
+ <PageBody>
79
+ <PageIntro>
80
+ <PageTitle>Qualidade da base</PageTitle>
81
+ </PageIntro>
82
+ Conteúdo da análise.
83
+ </PageBody>
71
84
  </Page>
72
85
  ```
73
86
 
@@ -89,9 +102,13 @@ ocupa a mesma posição introdutória sem transformar a trilha em ação.
89
102
  </BreadcrumbList>
90
103
  </Breadcrumb>
91
104
  </PageNavigation>
92
- <PageTitle>Carla Souza</PageTitle>
93
105
  </PageHeader>
94
- <PageBody>Dados do cliente.</PageBody>
106
+ <PageBody>
107
+ <PageIntro>
108
+ <PageTitle>Carla Souza</PageTitle>
109
+ </PageIntro>
110
+ Dados do cliente.
111
+ </PageBody>
95
112
  </Page>
96
113
  ```
97
114
 
@@ -99,7 +116,7 @@ ocupa a mesma posição introdutória sem transformar a trilha em ação.
99
116
 
100
117
  Use `PageShell` quando o shell conhece o breadcrumb e a rota conhece ações globais ou uma
101
118
  introdução. Não crie um cabeçalho paralelo no layout nem esconda slots de `Page` com CSS. O Opus compõe a
102
- navegação e as ações do shell no `PageHeader` rolável da página ativa.
119
+ navegação e as ações do shell no `PageHeader` estável da página ativa.
103
120
 
104
121
  ```tsx preview col
105
122
  <PageShell
@@ -113,7 +130,14 @@ navegação e as ações do shell no `PageHeader` rolável da página ativa.
113
130
  </Breadcrumb>
114
131
  }
115
132
  >
116
- <Page title="Clientes" actions={<Button variant="outline">Exportar</Button>}>
133
+ <Page
134
+ title="Clientes"
135
+ actions={
136
+ <Button variant="outline" size="sm">
137
+ Exportar
138
+ </Button>
139
+ }
140
+ >
117
141
  Conteúdo da listagem.
118
142
  </Page>
119
143
  </PageShell>
@@ -122,7 +146,7 @@ navegação e as ações do shell no `PageHeader` rolável da página ativa.
122
146
  Durante `PageState`, o cabeçalho inteiro desaparece e o título do estado assume o heading principal.
123
147
  Se uma ação não puder ser executada sem o conteúdo, a própria rota deve omiti-la naquele estado.
124
148
 
125
- Na composição explícita, combine navegação, título e ações no mesmo cabeçalho:
149
+ Na composição explícita, separe navegação e ações da superfície do título no corpo:
126
150
 
127
151
  ```tsx preview col
128
152
  <PageShell
@@ -138,12 +162,16 @@ Na composição explícita, combine navegação, título e ações no mesmo cabe
138
162
  >
139
163
  <Page>
140
164
  <PageHeader>
141
- <PageTitle>Clientes</PageTitle>
142
165
  <PageActions>
143
- <Button>Exportar</Button>
166
+ <Button size="sm">Exportar</Button>
144
167
  </PageActions>
145
168
  </PageHeader>
146
- <PageBody>Conteúdo da listagem.</PageBody>
169
+ <PageBody>
170
+ <PageIntro>
171
+ <PageTitle>Clientes</PageTitle>
172
+ </PageIntro>
173
+ Conteúdo da listagem.
174
+ </PageBody>
147
175
  </Page>
148
176
  </PageShell>
149
177
  ```
@@ -157,12 +185,17 @@ forma curta com `PageHeader` ou `PageBody`.
157
185
  render(
158
186
  <Page>
159
187
  <PageHeader>
160
- <PageTitle>Workspaces</PageTitle>
161
188
  <PageActions>
162
- <Button variant="outline">Exportar</Button>
189
+ <Button variant="outline" size="sm">
190
+ Exportar
191
+ </Button>
163
192
  </PageActions>
164
193
  </PageHeader>
165
194
  <PageBody>
195
+ <PageIntro>
196
+ <PageTitle>Workspaces</PageTitle>
197
+ </PageIntro>
198
+
166
199
  <div className="rounded-lg border border-dashed border-border p-10 text-center">
167
200
  O conteúdo da página.
168
201
  </div>
@@ -185,10 +218,12 @@ no fim da linha.
185
218
 
186
219
  ```tsx preview col
187
220
  <Page>
188
- <PageHeader>
189
- <PageTitle>Importar clientes</PageTitle>
190
- </PageHeader>
191
- <PageBody>Revise os 128 registros antes de confirmar.</PageBody>
221
+ <PageBody>
222
+ <PageIntro>
223
+ <PageTitle>Importar clientes</PageTitle>
224
+ </PageIntro>
225
+ Revise os 128 registros antes de confirmar.
226
+ </PageBody>
192
227
  <PageFooter>
193
228
  <ButtonGroup mode="spaced">
194
229
  <Button variant="ghost">Cancelar</Button>
@@ -209,10 +244,11 @@ rolagem, como o `PageBody` do exemplo.
209
244
  render(
210
245
  <div className="h-72 overflow-hidden rounded-lg border border-border">
211
246
  <Page layout="fill">
212
- <PageHeader>
213
- <PageTitle>Ordens de serviço</PageTitle>
214
- </PageHeader>
215
247
  <PageBody className="min-h-0 flex-1 overflow-y-auto">
248
+ <PageIntro>
249
+ <PageTitle>Ordens de serviço</PageTitle>
250
+ </PageIntro>
251
+
216
252
  <div className="space-y-2">
217
253
  {[
218
254
  "OS-1842",
@@ -263,7 +299,11 @@ function Example() {
263
299
  <PageActionsTarget target={target}>
264
300
  <Page
265
301
  title="Clientes"
266
- actions={<Button variant="outline">Exportar</Button>}
302
+ actions={
303
+ <Button variant="outline" size="sm">
304
+ Exportar
305
+ </Button>
306
+ }
267
307
  >
268
308
  Conteúdo da listagem.
269
309
  </Page>
@@ -322,31 +362,35 @@ estado na própria seção com [`DataState`](/ui/data-state), [`ActionView`](/ui
322
362
 
323
363
  ## Propriedades de Page
324
364
 
325
- | Propriedade | Tipo | Padrão | Descrição |
326
- | ----------- | -------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
327
- | `description` | `ReactNode` | | Orientação opcional sob o título na forma curta. |
328
- | `title` | `ReactNode` | | O h1 da página. |
329
- | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho. |
330
- | `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`. |
331
- | `className` | `string` | `max-w-7xl` | Classes do container para substituir o teto padrão de `80rem`. |
332
- | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
333
- | demais | Atributos de `HTMLElement` | | Atributos nativos repassados ao elemento `main`, como `id` ou `aria-label`. `className` vai para o container interno. |
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. |
334
374
 
335
375
  ## Propriedades de PageShell
336
376
 
337
- | Propriedade | Tipo | Descrição |
338
- | ------------ | ----------------------------- | -------------------------------------------------------------------------- |
339
- | `navigation` | `ReactNode` | Navegação contextual composta acima do título no `PageHeader` descendente. |
340
- | `actions` | `ReactNode` | Ações conhecidas pelo shell, antes das ações declaradas pela `Page`. |
341
- | `children` | `ReactNode` | Rota que renderiza uma `Page` descendente. |
342
- | `className` | `string` | Classes adicionais da moldura. |
343
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados à moldura. |
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. |
384
+
385
+ `surfaceLayout?: 'sectioned' | 'continuous'` escolhe os divisores; o padrão é `sectioned`.
386
+ `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.
344
388
 
345
389
  ## Propriedades de PageHeader
346
390
 
347
391
  | Propriedade | Tipo | Descrição |
348
392
  | ----------- | ----------------------------- | ------------------------------------------------------------------------ |
349
- | `className` | `string` | Classes adicionais do cabeçalho rolável. |
393
+ | `className` | `string` | Classes adicionais do cabeçalho estável. |
350
394
  | `children` | `ReactNode` | `PageBack` ou `PageNavigation`, um `PageTitle` opcional e `PageActions`. |
351
395
  | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao cabeçalho. |
352
396
 
@@ -370,11 +414,11 @@ estado na própria seção com [`DataState`](/ui/data-state), [`ActionView`](/ui
370
414
 
371
415
  ## Propriedades de PageTitle
372
416
 
373
- | Propriedade | Tipo | Descrição |
374
- | ----------- | --------------------------------- | ---------------------------------------- |
375
- | `children` | `ReactNode` | Título principal `h1` de `PageHeader`. |
376
- | `className` | `string` | Classes adicionais do título. |
377
- | demais | Atributos de `HTMLHeadingElement` | Atributos nativos repassados ao heading. |
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. |
378
422
 
379
423
  ## Propriedades de PageActions
380
424
 
@@ -394,14 +438,15 @@ estado na própria seção com [`DataState`](/ui/data-state), [`ActionView`](/ui
394
438
 
395
439
  ## Propriedades de PageBody
396
440
 
397
- `PageBody` separa seus blocos diretos por `1.5rem`; o inset da página continua pertencendo a
398
- `Page`. Uma grade, lista compacta ou linha horizontal fica dentro de um wrapper próprio.
441
+ `contentClassName?: string` configura largura e alinhamento do container interno.
399
442
 
400
- | Propriedade | Tipo | Descrição |
401
- | ----------- | ----------------------------- | --------------------------------------------------------- |
402
- | `children` | `ReactNode` | Blocos principais, separados pelo ritmo estrutural. |
403
- | `className` | `string` | Classes de ocupação, overflow, alinhamento ou tipografia. |
404
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
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.
444
+
445
+ | Propriedade | Tipo | Descrição |
446
+ | ----------- | ----------------------------- | --------------------------------------------------- |
447
+ | `children` | `ReactNode` | Blocos principais, separados pelo ritmo estrutural. |
448
+ | `className` | `string` | Classes do viewport: ocupação e overflow. |
449
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
405
450
 
406
451
  Em uma `Page` com `layout="fill"`, o `PageBody` vira coluna flexível sozinho quando contém uma `ActionList` que
407
452
  ocupa a altura.
@@ -431,8 +476,63 @@ ocupa a altura.
431
476
 
432
477
  ## Propriedades de PageDescription
433
478
 
434
- | Propriedade | Tipo | Padrão | Descrição |
435
- | --- | --- | --- | --- |
436
- | `children` | `ReactNode` | | Orientação breve e opcional; filho direto de `PageHeader`. |
437
- | `className` | `string` | | Ajusta a apresentação do parágrafo. |
438
- | `…props` | `HTMLAttributes<HTMLParagraphElement>` | | Atributos nativos. |
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
486
+
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.
489
+
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
+ ```
498
+
499
+ ## Propriedades de PageIntro
500
+
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.
503
+
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
+
510
+ ## Propriedades de PageIntroActions
511
+
512
+ Agrupa ações locais do conteúdo no extremo oposto ao título da intro.
513
+
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
524
+
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.
528
+
529
+ ## Largura e rolagem
530
+
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.
535
+
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.
@@ -33,9 +33,8 @@ a largura cresce quando o número precisa de mais espaço.
33
33
  ## Números longos
34
34
 
35
35
  A largura mínima é quadrada e cresce conforme o conteúdo. Na escala densa de um rodapé, as setas e a
36
- elipse usam `size="icon-sm"`, o quadrado de `1.75rem` da escala única, com ícone de `0.875rem`. Os
37
- números não têm um degrau textual de `1.75rem` na escala e, por isso, recebem a mesma medida por
38
- `className`, como no exemplo.
36
+ elipse usam `size="icon-sm"`, o quadrado de `2rem` da escala única, com ícone de `0.875rem`. Os
37
+ números usam `size="sm"`, com a mesma altura e largura mínima, crescendo para acomodar os dígitos.
39
38
 
40
39
  ```tsx preview
41
40
  <Pagination>
@@ -44,16 +43,16 @@ números não têm um degrau textual de `1.75rem` na escala e, por isso, recebem
44
43
  <PaginationPrevious href="#" iconOnly size="icon-sm" />
45
44
  </PaginationItem>
46
45
  <PaginationItem>
47
- <PaginationLink href="#" page={1} className="h-7 min-w-7 text-xs" />
46
+ <PaginationLink href="#" page={1} size="sm" className="text-xs" />
48
47
  </PaginationItem>
49
48
  <PaginationItem>
50
49
  <PaginationEllipsis size="icon-sm" />
51
50
  </PaginationItem>
52
51
  <PaginationItem>
53
- <PaginationLink href="#" page={5726} className="h-7 min-w-7 text-xs" />
52
+ <PaginationLink href="#" page={5726} size="sm" className="text-xs" />
54
53
  </PaginationItem>
55
54
  <PaginationItem>
56
- <PaginationLink href="#" page={5727} isActive className="h-7 min-w-7 text-xs" />
55
+ <PaginationLink href="#" page={5727} isActive size="sm" className="text-xs" />
57
56
  </PaginationItem>
58
57
  <PaginationItem>
59
58
  <PaginationNext href="#" iconOnly size="icon-sm" />
@@ -135,7 +134,7 @@ render(
135
134
  | `page` | `number` | | Número usado como conteúdo, quando `children` não é informado, e no nome acessível “Página N”. |
136
135
  | `isActive` | `boolean` | `false` | Marca a página atual com `aria-current="page"` e tratamento `outline`. |
137
136
  | `href` | `string` | | Renderiza um `<a>`. Sem `href`, o componente usa `<button>` e aceita `onClick` e `disabled`. |
138
- | `size` | `ButtonProps['size']` | `'default'` | A escala única, via `Button`. Os `icon-*` são quadrados. Nos tamanhos textuais, a altura fica fixa em 2.25rem com largura mínima quadrada que cresce para números longos, então `size="sm"` não reduz a altura; para uma barra mais baixa, use um `icon-*` ou ajuste por `className` (ex.: `h-7 min-w-7 text-xs`). |
137
+ | `size` | `ButtonProps['size']` | `'default'` | A escala única, via `Button`. Os `icon-*` são quadrados; os tamanhos textuais preservam a mesma altura, com largura mínima quadrada que cresce para números longos. |
139
138
 
140
139
  ## Propriedades de PaginationPrevious e PaginationNext
141
140
 
@@ -143,7 +142,7 @@ render(
143
142
  |---|---|---|---|
144
143
  | `label` | `string` | `'Página anterior'` ou `'Próxima página'` | Nome acessível e texto visível da ação. |
145
144
  | `iconOnly` | `boolean` | `false` | Exibe somente a seta; `label` continua disponível para leitura assistiva. |
146
- | `size` | `ButtonProps['size']` | `'default'`; `'icon'` com `iconOnly` | A escala única; `icon-sm` para o rodapé denso. Sem `iconOnly`, a altura permanece 2.25rem em qualquer tamanho textual, como em `PaginationLink`. |
145
+ | `size` | `ButtonProps['size']` | `'default'`; `'icon'` com `iconOnly` | A escala única; `icon-sm` para o rodapé denso. Com ou sem `iconOnly`, a altura acompanha o tamanho escolhido, como em `PaginationLink`. |
147
146
  | `iconClassName` | `string` | | Classes aplicadas ao ícone da seta, quando o glifo da escala não servir. |
148
147
 
149
148
  ## Propriedades de PaginationEllipsis
@@ -89,14 +89,15 @@ fundo sustenta o modal, mas não é uma etapa para onde voltar. Formulários mod
89
89
  rodapé pelo conteúdo, com `Cancelar` em `ghost` e a ação principal sólida.
90
90
 
91
91
  Dentro de [`PageShell`](/ui/page), a superfície `page` usa a anatomia real da aplicação. O
92
- `PageHeader` reúne a navegação contextual, o título e as ações globais; o corpo vai para `PageBody`,
93
- com `PageFooter` quando há ações de rodapé.
92
+ `PageHeader` reúne navegação e ações globais; o título abre o corpo na intro, e `PageFooter`
93
+ recebe ações de rodapé. Comandos textuais nos headers de todas as superfícies usam `sm`; retorno e assistente
94
+ usam `icon-sm`. O rodapé preserva `default`.
94
95
 
95
96
  Uma Presentation de listagem exibida como página muda essa distribuição para manter a criação perto
96
97
  da coleção. O `PageBody` recebe um [`Surface`](/ui/surface) com a
97
98
  [`ActionList`](/ui/action-list), e o cabeçalho desse `Surface` recebe o título e os comandos
98
99
  declarados com `placement: "header"`, no extremo oposto ao título. Os comandos de cabeçalho usam o
99
- tamanho `default` e permanecem textuais, mesmo quando a action declara um ícone: o que abre outra
100
+ tamanho `sm` e permanecem textuais, mesmo quando a action declara um ícone: o que abre outra
100
101
  Presentation é um `Button` sólido, e uma action `simple` vira um
101
102
  [`ActionTrigger`](/ui/action-trigger) `ghost`. O rótulo vem do `label` da action, como `Criar workspace`.
102
103
 
@@ -59,11 +59,11 @@ const runtime = createRuntime({
59
59
  queue,
60
60
  })
61
61
 
62
- export const relatorioGerar = bindAction(relatorioGerarContract, {
62
+ export const reportGenerate = bindAction(reportGenerateContract, {
63
63
  background: { enabled: true, retry: { attempts: 3 }, progress: true },
64
64
  handler: async (ctx, input, loaded, progress) => {
65
65
  await progress?.report({ percent: 50, message: 'Consultando dados' })
66
- return gerarRelatorio(input)
66
+ return generateReport(input)
67
67
  },
68
68
  })
69
69
  ```
@@ -76,5 +76,5 @@ o erro de uso.
76
76
 
77
77
  `navigate` espera um caminho da própria origem e não valida destinos. Quando o destino vem de fora,
78
78
  como o `?redirect=` de um pós-login, valide-o antes de navegar: resolva com
79
- `new URL(valor, origin)` e compare o `origin` do resultado, em vez de conferir apenas o prefixo do
79
+ `new URL(target, origin)` e compare o `origin` do resultado, em vez de conferir apenas o prefixo do
80
80
  texto.
@@ -47,26 +47,26 @@ Declare o schedule com `defineSchedule` e registre-o no domínio, ao lado da act
47
47
 
48
48
  ```ts
49
49
  import { createRuntime, defineDomain, defineSchedule } from '@softize/opus/core'
50
- import { caixaFechar } from './caixa-fechar.ts' // a action 'caixa.fechar', preparada abaixo
50
+ import { ledgerClose } from './ledger-close.ts' // a action 'ledger.close', preparada abaixo
51
51
 
52
- const fecharDia = defineSchedule({
53
- name: 'caixa.fechar-dia',
54
- action: 'caixa.fechar',
52
+ const closeDay = defineSchedule({
53
+ name: 'ledger.close-day',
54
+ action: 'ledger.close',
55
55
  cron: '0 23 * * *',
56
56
  timezone: 'America/Sao_Paulo',
57
57
  })
58
58
 
59
- export const caixaDomain = defineDomain({
60
- name: 'caixa',
61
- actions: { caixaFechar },
62
- schedules: [fecharDia],
59
+ export const ledgerDomain = defineDomain({
60
+ name: 'ledger',
61
+ actions: { ledgerClose },
62
+ schedules: [closeDay],
63
63
  })
64
64
 
65
65
  const runtime = createRuntime({
66
66
  // …server/data…
67
67
  scheduler,
68
68
  })
69
- runtime.register([caixaDomain])
69
+ runtime.register([ledgerDomain])
70
70
  await runtime.start()
71
71
  ```
72
72
 
@@ -91,18 +91,18 @@ recusa o sistema até que o contrato dela aceite essa execução com `automatabl
91
91
  ```ts
92
92
  import { defineContract, isSystemActor } from '@softize/opus/core'
93
93
 
94
- export const caixaFecharContract = defineContract({
95
- name: 'caixa.fechar',
94
+ export const ledgerCloseContract = defineContract({
95
+ name: 'ledger.close',
96
96
  kind: 'simple',
97
97
  input: z.object({}),
98
- output: z.object({ fechados: z.number() }),
98
+ output: z.object({ closedEntries: z.number() }),
99
99
  automatable: true,
100
100
  })
101
101
 
102
- export const caixaFechar = bindAction(caixaFecharContract, {
102
+ export const ledgerClose = bindAction(ledgerCloseContract, {
103
103
  // O sistema não tem permissões: aceite-o de forma explícita ao lado da regra das pessoas.
104
- authorize: (ctx) => isSystemActor(ctx) || ctx.can('caixa:fechar'),
105
- handler: async (ctx) => ({ fechados: await caixa.fecharDia() }),
104
+ authorize: (ctx) => isSystemActor(ctx) || ctx.can('ledger:close'),
105
+ handler: async (ctx) => ({ closedEntries: await ledger.closeDay() }),
106
106
  })
107
107
  ```
108
108
 
@@ -16,7 +16,7 @@ render(
16
16
  title="Dispositivos conectados"
17
17
  count={3}
18
18
  description="Sessões com acesso à sua conta."
19
- actions={<Button variant="outline">Encerrar outras sessões</Button>}
19
+ actions={<Button variant="outline" size="sm">Encerrar outras sessões</Button>}
20
20
  >
21
21
  <p className="text-sm text-muted-foreground">MacBook Pro · ativo agora</p>
22
22
  </Surface>,
@@ -50,7 +50,10 @@ Três propriedades independentes definem a aparência:
50
50
  - `layout` escolhe entre o ritmo contínuo e as faixas com divisores.
51
51
 
52
52
  Uma superfície com moldura ou com fundo passa a aplicar o recuo de `1rem` nas suas regiões; você não
53
- escreve classes de padding no header, no corpo ou no rodapé.
53
+ escreve classes de padding no header, no corpo ou no rodapé. O header delimitado usa
54
+ `1rem` em todos os lados e linha mínima de `2rem`, como Page, Dialog e Drawer.
55
+ Declare `sm` para botões textuais e `icon-sm` para ícones; Pane usa a mesma geometria
56
+ quando hospeda Surface. Seções sem moldura e legendas recortadas não ganham padding de barra.
54
57
 
55
58
  ```tsx preview col
56
59
  render(
@@ -400,7 +403,7 @@ render(
400
403
  as="section"
401
404
  level={1}
402
405
  title="Clientes"
403
- actions={<Button>Criar cliente</Button>}
406
+ actions={<Button size="sm">Criar cliente</Button>}
404
407
  >
405
408
  <p className="text-sm text-muted-foreground">
406
409
  A lista de clientes ocupa o corpo.
@@ -409,7 +412,7 @@ render(
409
412
  );
410
413
  ```
411
414
 
412
- A criação usa um `Button` textual na variante padrão e no tamanho `default`, sem ícone, nomeado
415
+ A criação usa um `Button` textual na variante padrão e no tamanho `sm`, sem ícone, nomeado
413
416
  `Criar {recurso}`; o diálogo aberto por ele repete esse título, e a edição usa `Editar {recurso}`.
414
417
 
415
418
  Em uma [`Page`](/ui/page) com `layout="fill"`, a coleção ocupa a altura da página e rola só os
@@ -495,7 +498,7 @@ As demais propriedades são as nativas do elemento escolhido em `as`.
495
498
 
496
499
  ## Propriedades de SurfaceBody
497
500
 
498
- Os filhos diretos recebem o ritmo estrutural de `1.5rem`. O layout da `Surface` decide o inset;
501
+ Os filhos diretos recebem o ritmo estrutural de `1rem`. O layout da `Surface` decide o inset;
499
502
  um wrapper filho declara relações locais mais compactas.
500
503
 
501
504
  | Propriedade | Tipo | Padrão | Descrição |
@@ -38,25 +38,30 @@ mostrar somente o ícone, declare `aria-label` para preservar seu nome acessíve
38
38
  </Tabs>
39
39
  ```
40
40
 
41
+ A barra e o painel ficam separados por `1rem`. O painel organiza seus blocos diretos com
42
+ o mesmo intervalo. Sem moldura, não há padding inferior: o hospedeiro fornece o recuo externo.
43
+ Não adicione margem ou padding para repetir esses intervalos.
44
+
41
45
  ## Emoldurar abas e painéis
42
46
 
43
47
  Use `framed` quando a navegação e seus painéis precisarem formar um único bloco. A propriedade
44
48
  reúne borda, raio e recorte no próprio `Tabs`, mas não aplica fundo: o bloco herda a
45
49
  superfície em que foi composto. Por isso, não envolva `Tabs` em um `Surface` somente para obter essa
46
- moldura.
50
+ moldura. O painel horizontal recebe `1rem` nas laterais e embaixo; o intervalo da barra
51
+ fornece o espaço superior. Na orientação vertical, a moldura recebe `1rem` ao redor da composição.
47
52
 
48
53
  ```tsx preview col
49
- <Tabs defaultValue="overview" framed className="gap-0">
54
+ <Tabs defaultValue="overview" framed>
50
55
  <TabsList>
51
56
  <TabsListItem value="overview">Visão geral</TabsListItem>
52
57
  <TabsListItem value="history">Histórico</TabsListItem>
53
58
  </TabsList>
54
- <TabsPanel value="overview" className="p-4">
59
+ <TabsPanel value="overview">
55
60
  <p className="text-sm text-muted-foreground">
56
61
  Resumo do workspace Empresa X.
57
62
  </p>
58
63
  </TabsPanel>
59
- <TabsPanel value="history" className="p-4">
64
+ <TabsPanel value="history">
60
65
  <p className="text-sm text-muted-foreground">
61
66
  Alterações recentes do workspace.
62
67
  </p>
@@ -196,3 +201,6 @@ do gatilho.
196
201
  | ------------ | -------- | ------ | ----------------------------------------------------------------------- |
197
202
  | `value` | `string` | | Identificador do painel, igual ao `value` do `TabsListItem` que o abre. |
198
203
  | `forceMount` | `true` | | Mantém o painel montado mesmo quando outra aba está ativa. |
204
+
205
+ Painéis com `forceMount` continuam montados quando inativos, mas ficam ocultos. Isso preserva
206
+ o estado de editores sem exibir simultaneamente o conteúdo de abas diferentes.