@softize/opus 22.2.0 → 24.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 (115) hide show
  1. package/CHANGELOG.md +120 -1
  2. package/bin/cli.mjs +3 -9
  3. package/bin/lib/check.mjs +242 -49
  4. package/bin/lib/copy.mjs +17 -35
  5. package/bin/lib/gen-runner.mjs +2 -0
  6. package/bin/lib/gen-stubs.mjs +3 -1
  7. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +1 -1
  8. package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +6 -0
  9. package/docs/adr/0032-tab-baseline-respects-the-container-inset.md +16 -12
  10. package/docs/adr/0034-tabs-can-own-a-frame-without-owning-a-surface.md +8 -6
  11. package/docs/adr/0036-tabs-declares-trigger-distribution.md +11 -8
  12. package/docs/adr/0037-design-data-lives-outside-the-contract.md +1 -1
  13. package/docs/adr/0038-content-level-defines-primary-presentation.md +62 -0
  14. package/docs/adr/0039-filter-presentation-is-independent-from-filter-type.md +62 -0
  15. package/docs/adr/0040-tabs-use-a-single-navigation-presentation.md +59 -0
  16. package/docs/adr/0042-toggle-group-shares-the-grouped-control-grammar.md +79 -0
  17. package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +73 -0
  18. package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +133 -0
  19. package/docs/adr/0045-surface-replaces-content-and-card.md +230 -0
  20. package/docs/adr/0046-structural-body-owns-content-rhythm.md +103 -0
  21. package/docs/adr/0047-pane-is-only-a-split-layout-unit.md +71 -0
  22. package/docs/adr/0048-modal-intro-separates-content-from-chrome.md +34 -0
  23. package/docs/code-style.md +1 -1
  24. package/package.json +5 -1
  25. package/registry/skills/build-opus-ui/SKILL.md +11 -11
  26. package/registry/skills/build-opus-ui/references/evaluations.md +10 -9
  27. package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -16
  28. package/registry/skills/create-opus-action/references/contract-and-binding.md +3 -3
  29. package/registry/templates/app/src/App.tsx +24 -12
  30. package/src/core/contracts.ts +1 -1
  31. package/src/core/runtime.ts +4 -37
  32. package/src/core/types.ts +5 -23
  33. package/src/design/index.ts +14 -3
  34. package/src/testing/index.ts +6 -26
  35. package/src/ui/appearance.ts +149 -0
  36. package/src/ui/components/patterns/action-form-card.tsx +46 -33
  37. package/src/ui/components/patterns/action-list-dialog.tsx +2 -4
  38. package/src/ui/components/patterns/confirm.tsx +3 -1
  39. package/src/ui/components/patterns/fill-region.ts +8 -7
  40. package/src/ui/components/patterns/form-dialog.tsx +1 -3
  41. package/src/ui/components/patterns/form.tsx +8 -7
  42. package/src/ui/components/patterns/list.tsx +64 -14
  43. package/src/ui/components/patterns/page.tsx +15 -11
  44. package/src/ui/components/patterns/pane.tsx +9 -240
  45. package/src/ui/components/patterns/presentation.tsx +14 -14
  46. package/src/ui/components/patterns/sidebar.tsx +7 -17
  47. package/src/ui/components/patterns/split.tsx +111 -59
  48. package/src/ui/components/patterns/{surface-header.tsx → structural-header.tsx} +50 -19
  49. package/src/ui/components/patterns/structural-media.tsx +26 -0
  50. package/src/ui/components/patterns/surface-anatomy.ts +71 -61
  51. package/src/ui/components/patterns/surface-assistant.tsx +2 -4
  52. package/src/ui/components/patterns/surface.tsx +620 -0
  53. package/src/ui/components/patterns/trigger.tsx +11 -9
  54. package/src/ui/components/primitives/ask.tsx +155 -83
  55. package/src/ui/components/primitives/button.tsx +11 -9
  56. package/src/ui/components/primitives/checkbox.tsx +8 -8
  57. package/src/ui/components/primitives/command.tsx +1 -1
  58. package/src/ui/components/primitives/composer.tsx +47 -45
  59. package/src/ui/components/primitives/detail.tsx +9 -2
  60. package/src/ui/components/primitives/dialog.tsx +60 -26
  61. package/src/ui/components/primitives/drawer.tsx +58 -12
  62. package/src/ui/components/primitives/icon-picker.tsx +93 -70
  63. package/src/ui/components/primitives/input-group.tsx +35 -28
  64. package/src/ui/components/primitives/input-otp.tsx +16 -16
  65. package/src/ui/components/primitives/input.tsx +20 -10
  66. package/src/ui/components/primitives/item.tsx +9 -12
  67. package/src/ui/components/primitives/menu.tsx +44 -65
  68. package/src/ui/components/primitives/metric-card.tsx +75 -59
  69. package/src/ui/components/primitives/radio-group.tsx +9 -9
  70. package/src/ui/components/primitives/select.tsx +344 -209
  71. package/src/ui/components/primitives/switch.tsx +10 -10
  72. package/src/ui/components/primitives/table.tsx +29 -24
  73. package/src/ui/components/primitives/tabs.tsx +58 -88
  74. package/src/ui/components/primitives/textarea.tsx +6 -6
  75. package/src/ui/components/primitives/toggle-group-context.ts +24 -0
  76. package/src/ui/components/primitives/toggle-group.tsx +116 -74
  77. package/src/ui/components/primitives/toggle.tsx +82 -16
  78. package/src/ui/docs/DocBrowser.tsx +77 -69
  79. package/src/ui/docs/content/action-form-card.md +9 -9
  80. package/src/ui/docs/content/action-list.md +85 -70
  81. package/src/ui/docs/content/action-view.md +33 -18
  82. package/src/ui/docs/content/actions.md +6 -7
  83. package/src/ui/docs/content/button.md +1 -1
  84. package/src/ui/docs/content/communication.md +1 -1
  85. package/src/ui/docs/content/customization.md +64 -11
  86. package/src/ui/docs/content/detail.md +8 -6
  87. package/src/ui/docs/content/dialog.md +100 -58
  88. package/src/ui/docs/content/drawer.md +63 -19
  89. package/src/ui/docs/content/field.md +14 -15
  90. package/src/ui/docs/content/icon-tile.md +14 -13
  91. package/src/ui/docs/content/page.md +34 -26
  92. package/src/ui/docs/content/pane.md +41 -290
  93. package/src/ui/docs/content/presentation.md +3 -3
  94. package/src/ui/docs/content/semantic-context.md +0 -1
  95. package/src/ui/docs/content/separator.md +6 -6
  96. package/src/ui/docs/content/sidebar.md +68 -266
  97. package/src/ui/docs/content/skeleton.md +20 -18
  98. package/src/ui/docs/content/split.md +14 -14
  99. package/src/ui/docs/content/surface.md +513 -0
  100. package/src/ui/docs/content/tabs.md +82 -83
  101. package/src/ui/docs/content/testing.md +2 -3
  102. package/src/ui/docs/content/toggle.md +120 -63
  103. package/src/ui/docs/content/tokens.md +124 -40
  104. package/src/ui/docs/registry.tsx +4 -6
  105. package/src/ui/drivers/react.tsx +4 -3
  106. package/src/ui/index.ts +30 -27
  107. package/src/ui/meta.ts +15 -27
  108. package/src/ui/react.tsx +42 -46
  109. package/src/ui/theme.css +311 -64
  110. package/src/vite/design.ts +23 -21
  111. package/src/ui/components/patterns/content-header.tsx +0 -532
  112. package/src/ui/components/patterns/surface-media.tsx +0 -69
  113. package/src/ui/components/primitives/card.tsx +0 -191
  114. package/src/ui/docs/content/card.md +0 -292
  115. package/src/ui/docs/content/content.md +0 -276
@@ -6,13 +6,13 @@ centralizado e ocupa a largura disponível até `80rem` (`max-w-7xl`). Use `clas
6
6
  a composição pedir outro teto ou largura total.
7
7
 
8
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 header, `Content level={1}` no body, ou
9
+ exige exatamente um heading principal. Use `PageTitle` no header, `Surface level={1}` no body, ou
10
10
  deixe um `PageState` ativo assumir esse papel. O header pode ser omitido quando o próprio conteúdo
11
11
  nomeia a página. Contadores e outros indicadores pertencem ao conteúdo que os explica.
12
12
 
13
13
  A `Page` é contínua por definição e não há divisores entre suas regiões. O `layout` da `Page` não
14
14
  é a anatomia de superfície de
15
- [`Card`](/ui/card), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) e [`Pane`](/ui/pane) — aqui ele
15
+ [`Surface`](/ui/surface), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) e [`Pane`](/ui/pane) — aqui ele
16
16
  decide a ocupação de altura. `flow`, o padrão, deixa a página crescer e a rolagem acontecer na
17
17
  janela; `fill` limita a página à altura do shell para que uma região interna, como uma tabela longa
18
18
  ou um split, assuma a rolagem.
@@ -85,7 +85,7 @@ ocupa a mesma posição introdutória sem transformar a trilha em ação.
85
85
  ## Contexto conhecido pelo shell
86
86
 
87
87
  Use `PageShell` quando o shell conhece o breadcrumb e a rota conhece ações globais ou uma
88
- introdução. Não crie um `PaneHeader` paralelo nem esconda slots de `Page` com CSS. O Opus compõe a
88
+ introdução. Não crie um cabeçalho paralelo no layout nem esconda slots de `Page` com CSS. O Opus compõe a
89
89
  navegação e as ações do shell no `PageHeader` rolável da página ativa.
90
90
 
91
91
  ```tsx preview col
@@ -158,9 +158,9 @@ render(
158
158
  );
159
159
  ```
160
160
 
161
- Em uma página de listagem, [`Content`](/ui/content) pode fornecer o título e as ações da coleção,
161
+ Em uma página de listagem, [`Surface`](/ui/surface) pode fornecer o título e as ações da coleção,
162
162
  deixando `Page` apenas com `PageBody`. Se `PageShell` fornecer navegação ou ações nesse caso, `Page`
163
- materializa somente o `PageHeader` necessário para recebê-las, sem duplicar o heading de `Content`.
163
+ materializa somente o `PageHeader` necessário para recebê-las, sem duplicar o heading de `Surface`.
164
164
 
165
165
  ## Ações de etapa no rodapé
166
166
 
@@ -197,20 +197,25 @@ render(
197
197
  <PageHeader>
198
198
  <PageTitle>Ordens de serviço</PageTitle>
199
199
  </PageHeader>
200
- <PageBody className="min-h-0 flex-1 space-y-2 overflow-y-auto">
201
- {[
202
- "OS-1842",
203
- "OS-1839",
204
- "OS-1835",
205
- "OS-1830",
206
- "OS-1827",
207
- "OS-1821",
208
- "OS-1818",
209
- ].map((id) => (
210
- <div key={id} className="rounded-md border border-border p-3 text-sm">
211
- {id}
212
- </div>
213
- ))}
200
+ <PageBody className="min-h-0 flex-1 overflow-y-auto">
201
+ <div className="space-y-2">
202
+ {[
203
+ "OS-1842",
204
+ "OS-1839",
205
+ "OS-1835",
206
+ "OS-1830",
207
+ "OS-1827",
208
+ "OS-1821",
209
+ "OS-1818",
210
+ ].map((id) => (
211
+ <div
212
+ key={id}
213
+ className="rounded-md border border-border p-3 text-sm"
214
+ >
215
+ {id}
216
+ </div>
217
+ ))}
218
+ </div>
214
219
  </PageBody>
215
220
  </Page>
216
221
  </div>,
@@ -218,8 +223,8 @@ render(
218
223
  ```
219
224
 
220
225
  Uma [`ActionList`](/ui/action-list) não precisa dessas classes. Filha de `PageBody`, ou de um
221
- [`Content`](/ui/content) dentro dele, ela recebe a altura da página e assume `layout="fill"`
222
- sozinha: `PageBody`, `Content` e `ContentBody` passam a repassar a altura até ela, o cabeçalho da
226
+ [`Surface`](/ui/surface) dentro dele, ela recebe a altura da página e assume `layout="fill"`
227
+ sozinha: `PageBody`, `Surface` e `SurfaceBody` passam a repassar a altura até ela, o cabeçalho da
223
228
  tabela fica fixo e só os resultados rolam. As demais seções do `PageBody` mantêm a altura do
224
229
  próprio conteúdo, e uma página `fill` sem lista não muda.
225
230
 
@@ -373,11 +378,14 @@ estado na própria seção com [`DataState`](/ui/data-state), [`ActionView`](/ui
373
378
 
374
379
  ## Propriedades de PageBody
375
380
 
376
- | Propriedade | Tipo | Descrição |
377
- | ----------- | ----------------------------- | ------------------------------------------ |
378
- | `children` | `ReactNode` | Conteúdo principal da página. |
379
- | `className` | `string` | Classes adicionais da região principal. |
380
- | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
381
+ `PageBody` separa seus blocos diretos por `1.5rem`; o inset da página continua pertencendo a
382
+ `Page`. Uma grade, lista compacta ou linha horizontal fica dentro de um wrapper próprio.
383
+
384
+ | Propriedade | Tipo | Descrição |
385
+ | ----------- | ----------------------------- | --------------------------------------------------------- |
386
+ | `children` | `ReactNode` | Blocos principais, separados pelo ritmo estrutural. |
387
+ | `className` | `string` | Classes de ocupação, overflow, alinhamento ou tipografia. |
388
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
381
389
 
382
390
  Em uma `Page` com `layout="fill"`, o `PageBody` vira coluna flexível sozinho quando contém uma `ActionList` que
383
391
  ocupa a altura.
@@ -1,320 +1,71 @@
1
- ## A coluna encaixada em um layout
1
+ ## Uma unidade de layout do Split
2
2
 
3
- Use `Pane` para a coluna ou faixa que ocupa uma das posições de um [`Split`](/ui/split): a
4
- navegação à esquerda, o inspetor à direita, a lista que abre o detalhe ao lado. O `Split` decide a
5
- relação espacial e o redimensionamento; o `Pane` decide o que existe dentro da área recebida.
6
-
7
- No formato mais simples, o pane é uma caixa com recuo e o conteúdo é seu.
3
+ Use `Pane` somente para declarar uma coluna ou faixa dentro de [`Split`](/ui/split). Ele informa
4
+ identidade e limites de tamanho, mas não cria superfície, recuo, borda, fundo, rolagem ou regiões
5
+ internas. Essa separação mantém o redimensionamento independente da apresentação.
8
6
 
9
7
  ```tsx preview
10
8
  render(
11
9
  <div className="h-56 overflow-hidden rounded-lg border border-border">
12
10
  <Split>
13
- <Pane initialSize="16rem" className="bg-muted/30">
14
- <p className="text-sm text-muted-foreground">Navegação.</p>
11
+ <Pane initialSize="16rem">
12
+ <Surface framed className="h-full">
13
+ <SurfaceBody>
14
+ <p className="text-sm text-muted-foreground">Navegação.</p>
15
+ </SurfaceBody>
16
+ </Surface>
15
17
  </Pane>
16
18
  <Pane grow>
17
- <p className="text-sm text-muted-foreground">Conteúdo.</p>
19
+ <main className="h-full overflow-y-auto p-6">
20
+ <p className="text-sm text-muted-foreground">Conteúdo.</p>
21
+ </main>
18
22
  </Pane>
19
23
  </Split>
20
24
  </div>,
21
25
  );
22
26
  ```
23
27
 
24
- ## Cabeçalho, corpo e rodapé
25
-
26
- Quando a área precisa de regiões fixas e de um corpo que rola, componha os slots. `PaneHeader`
27
- nomeia a região, `PaneBody` ocupa o espaço restante e concentra a rolagem vertical, e `PaneFooter`
28
- mantém à vista o que não pode sair da tela.
29
-
30
- ```tsx preview
31
- render(
32
- <div className="h-72 overflow-hidden rounded-lg border border-border">
33
- <Split>
34
- <Pane initialSize="18rem">
35
- <PaneHeader>
36
- <PaneMedia>
37
- <MessagesSquare />
38
- </PaneMedia>
39
- <PaneTitle>Conversas</PaneTitle>
40
- <PaneActions>
41
- <Button variant="ghost" size="icon-sm" aria-label="Nova conversa">
42
- <SquarePen />
43
- </Button>
44
- </PaneActions>
45
- </PaneHeader>
46
- <PaneBody className="space-y-1">
47
- <p className="text-sm">Revisão do contrato</p>
48
- <p className="text-sm text-muted-foreground">
49
- Importação de clientes
50
- </p>
51
- <p className="text-sm text-muted-foreground">Fila de execuções</p>
52
- </PaneBody>
53
- <PaneFooter>
54
- <Button variant="ghost" size="sm">
55
- Ver arquivadas
56
- </Button>
57
- </PaneFooter>
58
- </Pane>
59
- <Pane grow>
60
- <p className="text-sm text-muted-foreground">Conversa selecionada.</p>
61
- </Pane>
62
- </Split>
63
- </div>,
64
- );
65
- ```
66
-
67
- O cabeçalho reconhece quatro slots — `PaneMedia`, `PaneTitle`, `PaneDescription` e `PaneActions` —
68
- e monta a linha sozinho: mídia, título e descrição de um lado, ações no extremo oposto. A ordem em
69
- que os slots são escritos não altera a posição. Cada slot aparece no máximo uma vez: repetir um
70
- deles interrompe a renderização com um erro que lista os slots aceitos.
71
-
72
- Título e descrição truncam quando a coluna encolhe, em vez de quebrar a altura da faixa.
28
+ Quando a região precisa de cabeçalho, corpo, rodapé ou aparência elevada, componha uma
29
+ [`Surface`](/ui/surface) dentro do pane. Quando o filho já é uma estrutura completa, como
30
+ `Sidebar`, ele pode ocupar o pane diretamente.
73
31
 
74
- Nas ações do cabeçalho, use `Button` `ghost` no tamanho `icon-sm` (1.75rem), como nos exemplos. O
75
- pane é uma superfície densa, com título e descrição em escala menor, e o quadrado menor acompanha
76
- essa escala. [`Dialog`](/ui/dialog) e [`Drawer`](/ui/drawer) usam `icon` (2.25rem) no voltar e nas
77
- ações do cabeçalho, e a [`Presentation`](/ui/presentation) usa o mesmo tamanho no voltar e no botão
78
- que abre o assistente.
32
+ ## Redimensionamento
79
33
 
80
- ## Busca ou marca no cabeçalho
81
-
82
- Uma coluna às vezes precisa, no topo, de algo que não é título nem ação: uma busca que filtra a
83
- lista, a marca de uma barra lateral. Escreva esse conteúdo direto dentro do `PaneHeader`, ao lado
84
- dos slots. Só o `Pane` aceita conteúdo livre no cabeçalho; os headers de `Card`, `Dialog` e `Drawer`
85
- aceitam apenas os próprios slots.
34
+ Em um `Split` redimensionável, use `id` estável em cada pane. Números representam porcentagens;
35
+ strings preservam unidades explícitas.
86
36
 
87
37
  ```tsx preview
88
38
  render(
89
39
  <div className="h-56 overflow-hidden rounded-lg border border-border">
90
- <Split>
91
- <Pane initialSize="18rem">
92
- <PaneHeader>
93
- <Input
94
- icon={<Search />}
95
- placeholder="Buscar conversa"
96
- aria-label="Buscar conversa"
40
+ <Split id="workspace" resizable>
41
+ <Pane id="navigation" initialSize="18rem" minSize="14rem" maxSize="28rem">
42
+ <Sidebar className="w-full">
43
+ <SidebarNav
44
+ navLabel="Projeto"
45
+ activeId="overview"
46
+ groups={[{ items: [{ id: "overview", label: "Visão geral" }] }]}
97
47
  />
98
- <PaneActions>
99
- <Button variant="ghost" size="icon-sm" aria-label="Nova conversa">
100
- <SquarePen />
101
- </Button>
102
- </PaneActions>
103
- </PaneHeader>
104
- <PaneBody className="space-y-1">
105
- <p className="text-sm">Revisão do contrato</p>
106
- <p className="text-sm text-muted-foreground">
107
- Importação de clientes
108
- </p>
109
- </PaneBody>
48
+ </Sidebar>
110
49
  </Pane>
111
- <Pane grow>
112
- <p className="text-sm text-muted-foreground">Conversa selecionada.</p>
50
+ <Pane id="content" grow minSize="20rem">
51
+ <main className="h-full overflow-y-auto p-6">Conteúdo principal.</main>
113
52
  </Pane>
114
53
  </Split>
115
54
  </div>,
116
55
  );
117
56
  ```
118
57
 
119
- O conteúdo livre ocupa o lugar do título e absorve a largura disponível, por isso as ações
120
- continuam no extremo oposto. Quando há título, o conteúdo livre vem sempre depois do título e da descrição,
121
- qualquer que seja a ordem no JSX: uma busca escrita junto de um `PaneTitle` aparece abaixo dele, não
122
- ao lado. Para algo antes do título, use `PaneMedia`; para algo ao lado, use `PaneActions`.
123
-
124
- ## Escolher entre seccionado e contínuo
125
-
126
- `layout` declara a anatomia da superfície inteira e fica no root; os slots leem esse valor e não o
127
- recebem. Cada valor é um pacote de recuo, ritmo vertical e divisores.
128
-
129
- | Aspecto | `sectioned` (padrão) | `continuous` |
130
- | ------------------ | ------------------------- | -------------------------------- |
131
- | Divisores | entre as regiões vizinhas | nenhum |
132
- | Faixa do cabeçalho | altura fixa de `3.75rem` | acompanha o conteúdo |
133
- | Ritmo vertical | regiões simétricas | o cabeçalho se aproxima do corpo |
134
-
135
- O padrão `sectioned` é o pane de operação: a faixa do cabeçalho preserva uma medida fixa para que
136
- painéis irmãos mantenham o mesmo ritmo. Use `continuous` quando o pane for um bloco de leitura
137
- contínuo, sem fronteiras a marcar.
138
-
139
- Os divisores são derivados da vizinhança: cada região desenha a linha quando há uma região do outro
140
- lado. Um cabeçalho sem corpo não fecha nada, e um cabeçalho seguido direto de um rodapé produz uma
141
- linha só. A tela não escreve `border-b` nem `border-t`.
142
-
143
- No `continuous`, um cabeçalho sem corpo nem rodapé fecha o pane com o mesmo recuo que tem em cima.
144
- Uma classe `pb-*` no `PaneHeader` não altera esse recuo: a regra só vale quando o cabeçalho é a
145
- última região e tem precedência sobre o `className`. No `sectioned`, a faixa tem altura fixa e
146
- centraliza a linha, então não há recuo de baixo a ajustar.
147
-
148
- ## Recuo do pane e recuo das regiões
149
-
150
- `inset` é o respiro interno do pane sem slots: `md` por padrão, com `none`, `sm` e `lg`
151
- disponíveis. Quando `PaneHeader`, `PaneBody` ou `PaneFooter` são filhos **diretos** do pane, o recuo
152
- passa a ser de cada região e o `inset` vira `none` sozinho — é o que permite ao divisor alcançar a
153
- borda da coluna.
154
-
155
- O ajuste enxerga só o primeiro nível. Se os slots vierem dentro de outro componente — é o caso da
156
- `Sidebar`, que traz a superfície e o colapso —, o pane não sabe que eles existem: declare
157
- `inset="none"` você mesmo, ou a coluna ganha um recuo que empurra o divisor para dentro.
158
-
159
- ## A matriz de layouts e slots
160
-
161
- As regiões são independentes: a coluna usa só as que precisa, nos dois layouts, e os divisores
162
- acompanham as regiões presentes.
163
-
164
- ```tsx preview col
165
- render(
166
- <div className="grid grid-cols-2 gap-4">
167
- <div className="h-56 overflow-hidden rounded-lg border border-border">
168
- <Pane className="h-full">
169
- <PaneHeader>
170
- <PaneTitle>Seccionado</PaneTitle>
171
- <PaneActions>
172
- <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
173
- <Ellipsis />
174
- </Button>
175
- </PaneActions>
176
- </PaneHeader>
177
- <PaneBody>
178
- <p className="text-sm text-muted-foreground">
179
- Cabeçalho, corpo e rodapé.
180
- </p>
181
- </PaneBody>
182
- <PaneFooter>
183
- <Button variant="ghost" size="sm">
184
- Configurações
185
- </Button>
186
- </PaneFooter>
187
- </Pane>
188
- </div>
189
- <div className="h-56 overflow-hidden rounded-lg border border-border">
190
- <Pane layout="continuous" className="h-full">
191
- <PaneHeader>
192
- <PaneMedia>
193
- <ChartNoAxesColumn />
194
- </PaneMedia>
195
- <PaneTitle>Contínuo com mídia</PaneTitle>
196
- <PaneDescription>O espaço separa as regiões.</PaneDescription>
197
- </PaneHeader>
198
- <PaneBody>
199
- <p className="text-sm text-muted-foreground">
200
- Sem rodapé e sem divisores.
201
- </p>
202
- </PaneBody>
203
- </Pane>
204
- </div>
205
- <div className="h-56 overflow-hidden rounded-lg border border-border">
206
- <Pane className="h-full">
207
- <PaneBody>
208
- <p className="text-sm text-muted-foreground">
209
- Só corpo: nenhuma fronteira a marcar.
210
- </p>
211
- </PaneBody>
212
- </Pane>
213
- </div>
214
- <div className="h-56 overflow-hidden rounded-lg border border-border">
215
- <Pane className="h-full">
216
- <PaneHeader>
217
- <PaneMedia context="primary">
218
- <Folder />
219
- </PaneMedia>
220
- <PaneTitle>Sem corpo</PaneTitle>
221
- </PaneHeader>
222
- <PaneFooter>
223
- <Button variant="ghost" size="sm">
224
- Ação persistente
225
- </Button>
226
- </PaneFooter>
227
- </Pane>
228
- </div>
229
- </div>,
230
- );
231
- ```
232
-
233
- ## Onde termina o Pane
234
-
235
- Três componentes dividem a responsabilidade de uma coluna, e trocá-los de papel é a origem mais
236
- comum de layout duplicado:
237
-
238
- | Componente | Responsabilidade |
239
- | ------------------------ | --------------------------------------------------------------------------- |
240
- | [`Split`](/ui/split) | Relação espacial entre as áreas e, com `resizable`, o arraste da fronteira. |
241
- | `Pane` | Tamanho recebido, recuo e as regiões internas: cabeçalho, corpo e rodapé. |
242
- | [`Sidebar`](/ui/sidebar) | Superfície da navegação lateral e o estado de colapso dos destinos. |
243
-
244
- Tamanho inicial, limites e persistência do layout são declarados no `Pane` e operados pelo `Split`
245
- — a [página do Split](/ui/split) trata deles. Uma `Sidebar` é composta dentro de um `Pane` e usa os
246
- mesmos slots para o próprio cabeçalho e rodapé; ela não tem regiões próprias.
247
-
248
- ## Hierarquia do título
249
-
250
- `PaneTitle` é um heading. `level` escolhe a hierarquia do documento, de `1` a `6`, com `2` como
251
- padrão. O tamanho visual vem da família e do `layout`, não do nível, então corrigir a estrutura do
252
- documento não muda a aparência da faixa.
253
-
254
- ## Propriedades de Pane
255
-
256
- | Propriedade | Tipo | Padrão | Descrição |
257
- | --------------------- | -------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------- |
258
- | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
259
- | `inset` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'`, ou `'none'` com slots diretos | Respiro interno do pane sem slots; slots dentro de outro componente exigem declarar. |
260
- | `id` | `string` | | Identidade estável usada pelo layout redimensionável e persistido. |
261
- | `initialSize` | `number \| string` | | Tamanho inicial; número é porcentagem, string aceita `%`, `rem`, `em`, `vh`, `vw` e `px`. |
262
- | `minSize` / `maxSize` | `number \| string` | | Limites aplicados pelo `Split` quando ele é redimensionável. |
263
- | `grow` | `boolean` | `false` | Ocupa o espaço remanescente no layout simples. |
264
- | `className` | `string` | | Ajusta a coluna. |
265
- | `children` | `ReactNode` | | Conteúdo direto ou os slots estruturais. |
266
-
267
- ## Propriedades de PaneHeader
268
-
269
- | Propriedade | Tipo | Padrão | Descrição |
270
- | ----------- | ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
271
- | `children` | `ReactNode` | | `PaneMedia`, `PaneTitle`, `PaneDescription` e `PaneActions`, no máximo um de cada, e conteúdo livre, que aparece depois do título e da descrição. |
272
- | `className` | `string` | | Ajusta a faixa fixa sobre o recuo do layout. |
273
-
274
- ## Propriedades de PaneMedia
275
-
276
- | Propriedade | Tipo | Padrão | Descrição |
277
- | ----------- | ------------------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
278
- | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'xs'` | Tamanho da moldura e do glifo na escala compartilhada. |
279
- | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
280
- | `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
281
- | `className` | `string` | | Ajusta a moldura sem substituir a escala. |
282
- | `asChild` | `boolean` | `false` | Cede o elemento para uma marca com visual próprio — um orbe, um logotipo — que ocupa o slot sem ganhar a moldura por cima. |
283
-
284
- ## Propriedades de PaneTitle
285
-
286
- | Propriedade | Tipo | Padrão | Descrição |
287
- | ----------- | ---------------------------- | ------ | ------------------------------------------------------------------- |
288
- | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
289
- | `className` | `string` | | Ajusta o título, que trunca quando não cabe. |
290
-
291
- ## Propriedades de PaneDescription
292
-
293
- | Propriedade | Tipo | Padrão | Descrição |
294
- | ----------- | ----------- | ------ | ---------------------------------------------------------- |
295
- | `children` | `ReactNode` | | Frase curta de apoio sob o título; trunca quando não cabe. |
296
- | `className` | `string` | | Ajusta a descrição. |
297
-
298
- ## Propriedades de PaneActions
299
-
300
- | Propriedade | Tipo | Padrão | Descrição |
301
- | ----------- | ----------- | ------ | -------------------------------------- |
302
- | `children` | `ReactNode` | | Controles no extremo oposto ao título. |
303
- | `className` | `string` | | Ajusta o agrupamento das ações. |
304
-
305
- ## Propriedades de PaneBody
306
-
307
- | Propriedade | Tipo | Padrão | Descrição |
308
- | ----------- | ----------- | ------ | ----------------------------------------------------- |
309
- | `children` | `ReactNode` | | Conteúdo que ocupa o espaço entre cabeçalho e rodapé. |
310
- | `className` | `string` | | Ajusta a região flexível e rolável. |
311
-
312
- `PaneContent` continua exportado como alias depreciado de `PaneBody` e sai em uma próxima versão
313
- maior. Código novo usa `PaneBody`.
58
+ ## Propriedades
314
59
 
315
- ## Propriedades de PaneFooter
60
+ | Propriedade | Tipo | Padrão | Descrição |
61
+ | ------------- | -------------------------------------------------- | ------- | ------------------------------------------------------------------------ |
62
+ | `id` | `string` | | Identidade estável dentro do grupo, necessária para persistir o layout. |
63
+ | `initialSize` | `number \| \`${number}%\` \| rem, em, vh, vw ou px | | Tamanho inicial. Números representam porcentagens. |
64
+ | `minSize` | mesmo tipo de `initialSize` | | Limite mínimo durante o redimensionamento. |
65
+ | `maxSize` | mesmo tipo de `initialSize` | | Limite máximo durante o redimensionamento. |
66
+ | `grow` | `boolean` | `false` | Faz a região ocupar o espaço remanescente no layout simples. |
67
+ | `className` | `string` | | Ajustes de layout da unidade, sem substituir a superfície do conteúdo. |
68
+ | `children` | `ReactNode` | | Estrutura responsável pela apresentação e organização interna da região. |
316
69
 
317
- | Propriedade | Tipo | Padrão | Descrição |
318
- | ----------- | ----------- | ------ | ---------------------------------------------------------------- |
319
- | `children` | `ReactNode` | | Navegação ou ações que precisam permanecer acessíveis no rodapé. |
320
- | `className` | `string` | | Ajusta a faixa fixa sobre o recuo do layout. |
70
+ `Pane` não possui slots. APIs antigas como `PaneHeader`, `PaneBody` e `PaneFooter` foram removidas;
71
+ use a anatomia de `Surface` quando essas regiões forem necessárias.
@@ -93,8 +93,8 @@ Dentro de [`PageShell`](/ui/page), a superfície `page` usa a anatomia real da a
93
93
  com `PageFooter` quando há ações de rodapé.
94
94
 
95
95
  Uma Presentation de listagem exibida como página muda essa distribuição para manter a criação perto
96
- da coleção. O `PageBody` recebe um [`Content`](/ui/content) com a
97
- [`ActionList`](/ui/action-list), e o cabeçalho desse `Content` recebe o título e os comandos
96
+ da coleção. O `PageBody` recebe um [`Surface`](/ui/surface) com a
97
+ [`ActionList`](/ui/action-list), e o cabeçalho desse `Surface` recebe o título e os comandos
98
98
  declarados com `placement: "header"`, no extremo oposto ao título. Os comandos de cabeçalho usam o
99
99
  tamanho `default` e permanecem textuais, mesmo quando a action declara um ícone: o que abre outra
100
100
  Presentation é um `Button` sólido, e uma action `simple` vira um
@@ -185,7 +185,7 @@ componente exige `children`, e uma com body de action os recusa: nos dois casos,
185
185
  lança um erro que nomeia a Presentation.
186
186
 
187
187
  Com `heading: "shell"`, o padrão, a casca emite o título da definição. Quando o conteúdo React já
188
- declara o heading principal da página, como um `Content level={1}`, use `heading: "content"`: dentro
188
+ declara o heading principal da página, como um `Surface level={1}`, use `heading: "content"`: dentro
189
189
  de `PageShell`, a casca deixa de emitir o `PageHeader` com título e o documento continua com um único `h1`. Em
190
190
  Dialog e Drawer, o título continua no cabeçalho da superfície.
191
191
 
@@ -54,7 +54,6 @@ O par `context` + `variant` vale para componentes que comunicam significado, com
54
54
  | --- | --- | --- |
55
55
  | [`Select`](/ui/select) | `default`, `outline`, `ghost` | `default` é o campo completo; `outline` é compacto com borda, e `ghost`, compacto sem borda nem fundo. |
56
56
  | [`Toggle`](/ui/toggle) | `default`, `outline` | `default` não tem borda nem fundo em repouso; o fundo aparece no hover e quando ativo. `outline` acrescenta a borda. |
57
- | [`TabsList`](/ui/tabs) | `default`, `line` | `default` agrupa as abas em uma superfície preenchida; `line` usa uma linha-base e marca nela a aba ativa. |
58
57
 
59
58
  O mesmo nome pode aparecer nos dois grupos. Num `Badge`, `outline` é um tratamento do significado
60
59
  declarado em `context`; num `Select`, é apenas o formato compacto com borda.
@@ -12,7 +12,7 @@ com regiões. A orientação horizontal fica entre blocos empilhados e ocupa tod
12
12
  <p className="text-sm text-muted-foreground">Próximo horário livre hoje, às 14h.</p>
13
13
  ```
14
14
 
15
- Não use `Separator` entre cabeçalho, corpo e rodapé de [`Card`](/ui/card), [`Dialog`](/ui/dialog) ou
15
+ Não use `Separator` entre cabeçalho, corpo e rodapé de [`Surface`](/ui/surface), [`Dialog`](/ui/dialog) ou
16
16
  [`Drawer`](/ui/drawer). Nessas superfícies, os divisores são derivados das regiões presentes: use
17
17
  `layout="sectioned"` no componente raiz.
18
18
 
@@ -32,8 +32,8 @@ Use a orientação vertical entre itens lado a lado. A linha herda a altura do c
32
32
 
33
33
  ## Propriedades de Separator
34
34
 
35
- | Propriedade | Tipo | Padrão | Descrição |
36
- |---|---|---|---|
37
- | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da linha. A vertical precisa de altura vinda do contêiner. |
38
- | `decorative` | `boolean` | `true` | Uma linha decorativa fica fora da árvore de acessibilidade. Use `false` quando a divisão tiver significado e precisar ser anunciada. |
39
- | `className` | `string` | | Ajusta a linha, como o espaçamento ao redor. |
35
+ | Propriedade | Tipo | Padrão | Descrição |
36
+ | ------------- | ---------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
37
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da linha. A vertical precisa de altura vinda do contêiner. |
38
+ | `decorative` | `boolean` | `true` | Uma linha decorativa fica fora da árvore de acessibilidade. Use `false` quando a divisão tiver significado e precisar ser anunciada. |
39
+ | `className` | `string` | | Ajusta a linha, como o espaçamento ao redor. |