@softize/opus 18.4.0 → 19.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 (42) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/docs/adr/0020-icon-tiles-are-explicitly-composed.md +46 -0
  3. package/docs/adr/0021-content-carries-structure-and-semantic-element.md +65 -0
  4. package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +293 -0
  5. package/package.json +1 -1
  6. package/src/ui/components/patterns/content-header.tsx +169 -50
  7. package/src/ui/components/patterns/heading-level.ts +16 -0
  8. package/src/ui/components/patterns/list.tsx +76 -27
  9. package/src/ui/components/patterns/pane.tsx +294 -0
  10. package/src/ui/components/patterns/presentation.tsx +29 -17
  11. package/src/ui/components/patterns/sidebar.tsx +13 -72
  12. package/src/ui/components/patterns/split.tsx +8 -35
  13. package/src/ui/components/patterns/surface-anatomy.ts +219 -0
  14. package/src/ui/components/patterns/surface-header.tsx +51 -6
  15. package/src/ui/components/patterns/surface-media.tsx +69 -0
  16. package/src/ui/components/primitives/card.tsx +91 -29
  17. package/src/ui/components/primitives/command.tsx +12 -4
  18. package/src/ui/components/primitives/detail.tsx +10 -13
  19. package/src/ui/components/primitives/dialog.tsx +138 -35
  20. package/src/ui/components/primitives/drawer.tsx +122 -23
  21. package/src/ui/components/primitives/empty.tsx +2 -1
  22. package/src/ui/components/primitives/field.tsx +38 -16
  23. package/src/ui/components/primitives/icon-tile.tsx +91 -0
  24. package/src/ui/components/primitives/item.tsx +2 -1
  25. package/src/ui/components/primitives/metric-card.tsx +98 -39
  26. package/src/ui/components/primitives/table.tsx +1 -1
  27. package/src/ui/docs/content/action-list.md +61 -52
  28. package/src/ui/docs/content/card.md +221 -30
  29. package/src/ui/docs/content/content.md +90 -8
  30. package/src/ui/docs/content/dialog.md +115 -7
  31. package/src/ui/docs/content/drawer.md +136 -9
  32. package/src/ui/docs/content/field.md +78 -30
  33. package/src/ui/docs/content/icon-tile.md +47 -0
  34. package/src/ui/docs/content/metric-card.md +57 -18
  35. package/src/ui/docs/content/page.md +8 -0
  36. package/src/ui/docs/content/pane.md +250 -0
  37. package/src/ui/docs/content/sidebar.md +22 -43
  38. package/src/ui/docs/content/skeleton.md +7 -3
  39. package/src/ui/docs/content/split.md +16 -21
  40. package/src/ui/docs/registry.tsx +14 -2
  41. package/src/ui/meta.ts +17 -5
  42. package/src/ui/react.tsx +31 -0
@@ -1,6 +1,8 @@
1
- ## Box simples
1
+ ## Caixa simples
2
2
 
3
- O uso mais comum: a superfície de conteúdo em repouso (`rounded-xl` + `border`), flat por padrão, com o padding pelo `className`. O Card não força flex/gap/padding — você compõe o miolo (sem brigar com `space-y`/`flex` seu). Quando a hierarquia realmente pedir elevação, declare a intensidade explicitamente, por exemplo `className="shadow-sm"`.
3
+ O uso mais comum é a superfície em repouso: raio, borda e fundo, sem sombra. O `Card` não impõe
4
+ flex, gap nem padding, então o miolo continua seu — inclusive o `space-y` ou o grid que a tela já
5
+ usa. Nesse formato o recuo vem do `className`.
4
6
 
5
7
  ```tsx preview col
6
8
  <Card className="p-4">
@@ -8,9 +10,15 @@ O uso mais comum: a superfície de conteúdo em repouso (`rounded-xl` + `border`
8
10
  </Card>
9
11
  ```
10
12
 
11
- ## Estruturado (header / conteúdo / rodapé)
13
+ Quando a hierarquia realmente pedir elevação, declare a intensidade, por exemplo
14
+ `className="shadow-sm"`.
12
15
 
13
- Para painel com estrutura: cada slot é dono do próprio padding (como o Dialog). CardTitle/CardDescription no header; CardFooter alinha as ações.
16
+ ## Cabeçalho, corpo e rodapé
17
+
18
+ Quando o card tem estrutura, cada região vira um slot e traz o próprio recuo. `CardHeader`
19
+ reconhece quatro slots — `CardMedia`, `CardTitle`, `CardDescription` e `CardAction` — e monta a
20
+ linha sozinho: mídia, título e descrição de um lado, ações no extremo oposto. A ordem em que os
21
+ slots são escritos não altera a posição.
14
22
 
15
23
  ```tsx preview col
16
24
  <Card>
@@ -21,55 +29,238 @@ Para painel com estrutura: cada slot é dono do próprio padding (como o Dialog)
21
29
  <CardBody>
22
30
  <p className="text-sm text-muted-foreground">Última sessão concluída há 2 horas.</p>
23
31
  </CardBody>
24
- <CardFooter className="gap-2">
25
- <Button size="sm">Abrir sessão</Button>
32
+ <CardFooter>
26
33
  <Button size="sm" variant="outline">Ver repositórios</Button>
34
+ <Button size="sm">Abrir sessão</Button>
27
35
  </CardFooter>
28
36
  </Card>
29
37
  ```
30
38
 
31
- ## Com divisor
39
+ O rodapé alinha as ações no fim da linha. Um nó que não seja um desses quatro slots dentro do
40
+ `CardHeader` interrompe a renderização com um erro: a linha do cabeçalho pertence à família, e um
41
+ `div` solto ali devolveria à tela a decisão de posicionamento. Conteúdo livre vai para `CardBody`.
42
+
43
+ ## Escolher entre contínuo e seccionado
32
44
 
33
- `border-b` no header / `border-t` no footer dão o divisor quando a estrutura pede separação visível. A aresta externa e os divisores internos usam o mesmo vocabulário de `border`.
45
+ `layout` declara a anatomia da superfície inteira e fica no root. Não é uma borda ligada ou
46
+ desligada: cada valor é um pacote de recuo, ritmo vertical, escala do título e divisores.
47
+
48
+ | Aspecto | `continuous` (padrão) | `sectioned` |
49
+ | --- | --- | --- |
50
+ | Divisores | nenhum | entre as regiões vizinhas |
51
+ | Ritmo vertical | o cabeçalho se aproxima do corpo; o espaço separa | regiões simétricas; o divisor separa |
52
+ | Recuo lateral | mais folgado, para leitura | o mesmo das demais superfícies de operação |
53
+ | Escala do título | um degrau acima | um degrau mais contida |
54
+
55
+ Use `continuous` no card de leitura, que apresenta um assunto e termina. Use `sectioned` quando o
56
+ card for uma superfície de operação — regiões com pesos diferentes, lista dentro do corpo, rodapé
57
+ com ações — ou quando ele precisar conviver com um [`Dialog`](/ui/dialog), um
58
+ [`Drawer`](/ui/drawer) ou um [`Pane`](/ui/pane) sem degrau visível entre eles.
34
59
 
35
60
  ```tsx preview col
36
- <Card>
37
- <CardHeader className="border-b">
38
- <CardTitle>Skill code-style</CardTitle>
39
- <CardDescription>Padrão softize de código e microcopy.</CardDescription>
61
+ render(
62
+ <div className="grid gap-4 md:grid-cols-2">
63
+ <Card>
64
+ <CardHeader>
65
+ <CardTitle>Contínuo</CardTitle>
66
+ <CardDescription>O espaço separa as regiões.</CardDescription>
67
+ </CardHeader>
68
+ <CardBody>
69
+ <p className="text-sm text-muted-foreground">Um assunto, lido de cima a baixo.</p>
70
+ </CardBody>
71
+ <CardFooter>
72
+ <Button size="sm" variant="outline">Abrir</Button>
73
+ </CardFooter>
74
+ </Card>
75
+ <Card layout="sectioned">
76
+ <CardHeader>
77
+ <CardTitle>Seccionado</CardTitle>
78
+ <CardDescription>O divisor separa as regiões.</CardDescription>
79
+ </CardHeader>
80
+ <CardBody>
81
+ <p className="text-sm text-muted-foreground">Regiões com pesos diferentes.</p>
82
+ </CardBody>
83
+ <CardFooter>
84
+ <Button size="sm" variant="outline">Abrir</Button>
85
+ </CardFooter>
86
+ </Card>
87
+ </div>,
88
+ );
89
+ ```
90
+
91
+ ### Os divisores são derivados
92
+
93
+ Em `sectioned`, cada região desenha a própria linha quando existe uma região vizinha do outro lado.
94
+ Um cabeçalho sozinho não fecha nada, um rodapé que é a única região também não, e um cabeçalho
95
+ seguido direto de um rodapé produz uma linha só, em vez de duas encostadas.
96
+
97
+ A tela não escreve mais `border-b` no cabeçalho nem `border-t` no rodapé. A regra depende da
98
+ presença das regiões irmãs, que o componente conhece e a tela não.
99
+
100
+ ## Mídia e ações no cabeçalho
101
+
102
+ `CardMedia` abre a linha com a moldura de ícone da casa — o mesmo [`IconTile`](/ui/icon-tile), na
103
+ escala `sm`, com `context` e `variant` para declarar o significado da cor. `CardAction` fica no
104
+ extremo oposto ao título, sem precisar de classe de alinhamento.
105
+
106
+ ```tsx preview col
107
+ <Card layout="sectioned">
108
+ <CardHeader>
109
+ <CardMedia context="primary">
110
+ <CarFront />
111
+ </CardMedia>
112
+ <CardTitle>Revisão dos 20.000 km</CardTitle>
113
+ <CardDescription>Agendada para 12 de maio, às 9h.</CardDescription>
114
+ <CardAction>
115
+ <Button size="sm" variant="outline">Reagendar</Button>
116
+ </CardAction>
40
117
  </CardHeader>
41
118
  <CardBody>
42
- <p className="text-sm text-muted-foreground">Vinculada a 4 agentes neste workspace.</p>
119
+ <p className="text-sm text-muted-foreground">Consultor responsável: Marina Alves.</p>
43
120
  </CardBody>
44
- <CardFooter className="justify-between border-t">
45
- <Badge context="success">Publicada</Badge>
46
- <Button size="sm" variant="outline">Editar skill</Button>
47
- </CardFooter>
48
121
  </Card>
49
122
  ```
50
123
 
51
- ## Ação no cabeçalho
124
+ ## Hierarquia do título
52
125
 
53
- `CardAction` é o slot de ação do header (um botão ou menu). Quem compõe posiciona — em geral um
54
- `CardHeader` em `flex-row` com o título de um lado e a ação do outro.
126
+ `CardTitle` é um heading. `level` escolhe a hierarquia do documento, de `1` a `6`, com `3` como
127
+ padrão — um card costuma ser uma seção dentro de uma página que já tem o `h1`. O tamanho visual não
128
+ vem daí: ele é decidido pela família e pelo `layout`, então corrigir o nível para acertar a
129
+ estrutura do documento não muda a aparência.
55
130
 
56
131
  ```tsx preview col
57
132
  <Card>
58
- <CardHeader className="flex-row items-start justify-between">
59
- <div>
60
- <CardTitle>Empresa X</CardTitle>
61
- <CardDescription>3 agentes vinculados.</CardDescription>
62
- </div>
63
- <CardAction>
64
- <Button size="sm" variant="outline">Editar</Button>
65
- </CardAction>
133
+ <CardHeader>
134
+ <CardTitle level={2}>Qualidade da base</CardTitle>
135
+ <CardDescription>O nível muda a semântica; a escala continua a do layout.</CardDescription>
66
136
  </CardHeader>
67
137
  </Card>
68
138
  ```
69
139
 
140
+ Use `asChild` quando o heading precisar vir de outro componente, como um link.
141
+
142
+ ## A matriz de slots
143
+
144
+ As regiões são independentes: o cabeçalho existe sem corpo, o corpo existe sem cabeçalho e o rodapé
145
+ entra apenas quando há ações persistentes. O recuo e os divisores se ajustam a cada combinação, nos
146
+ dois layouts.
147
+
148
+ ```tsx preview col
149
+ render(
150
+ <div className="grid gap-4 md:grid-cols-2">
151
+ <Card>
152
+ <CardHeader>
153
+ <CardMedia>
154
+ <UserRound />
155
+ </CardMedia>
156
+ <CardTitle>Contínuo com mídia</CardTitle>
157
+ </CardHeader>
158
+ <CardBody>
159
+ <p className="text-sm text-muted-foreground">
160
+ Sem rodapé, o corpo reassume o respiro de baixo.
161
+ </p>
162
+ </CardBody>
163
+ </Card>
164
+ <Card>
165
+ <CardBody>
166
+ <p className="text-sm text-muted-foreground">
167
+ Só corpo: o card vira uma caixa com o recuo da família.
168
+ </p>
169
+ </CardBody>
170
+ </Card>
171
+ <Card layout="sectioned">
172
+ <CardHeader>
173
+ <CardTitle>Seccionado sem corpo</CardTitle>
174
+ <CardAction>
175
+ <Button size="sm" variant="ghost">Editar</Button>
176
+ </CardAction>
177
+ </CardHeader>
178
+ <CardFooter>
179
+ <Button size="sm">Salvar</Button>
180
+ </CardFooter>
181
+ </Card>
182
+ <Card layout="sectioned">
183
+ <CardHeader>
184
+ <CardMedia context="success">
185
+ <ShieldCheck />
186
+ </CardMedia>
187
+ <CardTitle>Seccionado completo</CardTitle>
188
+ <CardDescription>Cabeçalho, corpo e rodapé.</CardDescription>
189
+ </CardHeader>
190
+ <CardBody>
191
+ <p className="text-sm text-muted-foreground">Cada fronteira ganha uma linha.</p>
192
+ </CardBody>
193
+ <CardFooter>
194
+ <Button size="sm" variant="outline">Descartar</Button>
195
+ <Button size="sm">Publicar</Button>
196
+ </CardFooter>
197
+ </Card>
198
+ </div>,
199
+ );
200
+ ```
201
+
70
202
  ## Propriedades de Card
71
203
 
72
204
  | Propriedade | Tipo | Padrão | Descrição |
73
205
  |---|---|---|---|
74
- | `asChild` | `boolean` | `false` | Renderiza o filho com a superfície do Card (ex.: um `<button>` clicável inteiro). |
75
- | `className` | `string` | | Compõe sobre a superfície; os slots (`CardHeader`, `CardBody`, `CardFooter`, `CardAction`) são donos do próprio padding. `CardContent` é alias depreciado de `CardBody`. |
206
+ | `layout` | `'continuous' \| 'sectioned'` | `'continuous'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
207
+ | `asChild` | `boolean` | `false` | Renderiza o filho com a superfície do Card, por exemplo um `<button>` clicável inteiro. |
208
+ | `className` | `string` | | Compõe sobre a superfície. Sem slots, é aqui que entra o recuo da caixa. |
209
+
210
+ As demais propriedades são as propriedades nativas de `div`.
211
+
212
+ ## Propriedades de CardHeader
213
+
214
+ | Propriedade | Tipo | Padrão | Descrição |
215
+ |---|---|---|---|
216
+ | `children` | `ReactNode` | | Somente `CardMedia`, `CardTitle`, `CardDescription` e `CardAction`, no máximo um de cada. |
217
+ | `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
218
+
219
+ ## Propriedades de CardMedia
220
+
221
+ | Propriedade | Tipo | Padrão | Descrição |
222
+ |---|---|---|---|
223
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'sm'` | Tamanho da moldura e do glifo na escala compartilhada dos controles. |
224
+ | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
225
+ | `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
226
+ | `className` | `string` | | Ajusta a moldura sem substituir a escala. |
227
+ | `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. |
228
+
229
+ ## Propriedades de CardTitle
230
+
231
+ | Propriedade | Tipo | Padrão | Descrição |
232
+ |---|---|---|---|
233
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `3` | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
234
+ | `asChild` | `boolean` | `false` | Usa o filho como heading, preservando a escala do título. |
235
+ | `className` | `string` | | Ajusta o título. |
236
+
237
+ ## Propriedades de CardDescription
238
+
239
+ | Propriedade | Tipo | Padrão | Descrição |
240
+ |---|---|---|---|
241
+ | `children` | `ReactNode` | | Frase de apoio sob o título, dentro do cabeçalho. |
242
+ | `className` | `string` | | Ajusta a descrição. |
243
+
244
+ ## Propriedades de CardAction
245
+
246
+ | Propriedade | Tipo | Padrão | Descrição |
247
+ |---|---|---|---|
248
+ | `children` | `ReactNode` | | Controles no extremo oposto ao título, como um botão ou um menu. |
249
+ | `className` | `string` | | Ajusta o agrupamento das ações. |
250
+
251
+ ## Propriedades de CardBody
252
+
253
+ | Propriedade | Tipo | Padrão | Descrição |
254
+ |---|---|---|---|
255
+ | `children` | `ReactNode` | | Conteúdo principal do card. |
256
+ | `className` | `string` | | Ajusta a região sobre o recuo do layout. |
257
+
258
+ `CardContent` continua exportado como alias depreciado de `CardBody` e sai em uma próxima versão
259
+ maior. Código novo usa `CardBody`.
260
+
261
+ ## Propriedades de CardFooter
262
+
263
+ | Propriedade | Tipo | Padrão | Descrição |
264
+ |---|---|---|---|
265
+ | `children` | `ReactNode` | | Ações persistentes, alinhadas no fim da linha. |
266
+ | `className` | `string` | | Ajusta o rodapé, inclusive a distribuição das ações. |
@@ -4,6 +4,12 @@ Use `Content` para dar título e estrutura a uma região dentro de `PageBody`, `
4
4
  `DialogBody` ou outra superfície. Ele renderiza uma `section` ligada ao próprio título e mantém o
5
5
  espaçamento entre header e body. `ContentHeader` pertence sempre a essa estrutura; não o use solto.
6
6
 
7
+ O `Content` é contínuo por definição e não expõe `layout`: ele é uma região nomeada dentro de outra
8
+ superfície, e a escolha entre regiões seccionadas e contínuas pertence a quem a hospeda — o
9
+ [`Card`](/ui/card), o [`Dialog`](/ui/dialog), o [`Drawer`](/ui/drawer) ou o [`Pane`](/ui/pane).
10
+ Quando a própria região precisar de uma fronteira visível, use `framed`, descrito adiante. Pelo
11
+ mesmo motivo o `Content` não tem rodapé: um rodapé pertence à superfície que a hospeda.
12
+
7
13
  No caso comum, prefira o shorthand:
8
14
 
9
15
  ```tsx preview col
@@ -20,6 +26,79 @@ render(
20
26
  );
21
27
  ```
22
28
 
29
+ ## Região com moldura
30
+
31
+ Use `framed` quando título e corpo precisarem formar uma única região delimitada. A moldura pertence
32
+ ao `Content`; componentes internos, como `DetailGroup`, continuam responsáveis somente pelo layout
33
+ e pela semântica dos próprios dados.
34
+
35
+ ```tsx preview col
36
+ render(
37
+ <Content
38
+ framed
39
+ title={
40
+ <span className="flex items-center gap-2">
41
+ <UserRound
42
+ className="size-4 text-muted-foreground"
43
+ aria-hidden="true"
44
+ />
45
+ Cliente
46
+ </span>
47
+ }
48
+ >
49
+ <DetailGroup columns={2}>
50
+ <DetailField label="Nome" value="Carla Souza" />
51
+ <DetailField label="Telefone" value="+55 11 97333-4455" />
52
+ </DetailGroup>
53
+ </Content>,
54
+ );
55
+ ```
56
+
57
+ ## Grupo de campos
58
+
59
+ Quando a região nomear um conjunto de campos relacionados, use `as="fieldset"`. O `Content`
60
+ renderiza o título como `legend`, preserva as props nativas do `fieldset` e mantém o mesmo contrato
61
+ de título e corpo. Essa escolha altera somente a semântica e o comportamento nativo; com `framed`,
62
+ a moldura permanece contínua. Nesse modo, contador, descrição e ações não entram na legenda.
63
+
64
+ ```tsx preview col
65
+ render(
66
+ <Content as="fieldset" framed title="Proprietário">
67
+ <FieldGroup>
68
+ <Field>
69
+ <FieldLabel htmlFor="owner-name">Nome</FieldLabel>
70
+ <Input id="owner-name" />
71
+ </Field>
72
+ <Field>
73
+ <FieldLabel htmlFor="owner-document">CPF/CNPJ</FieldLabel>
74
+ <Input id="owner-document" />
75
+ </Field>
76
+ </FieldGroup>
77
+ </Content>,
78
+ );
79
+ ```
80
+
81
+ Quando a legenda precisar integrar visualmente a borda, declare essa escolha separadamente. Use
82
+ `frameVariant="legend"` em agrupamentos compactos, como as seções de filtros avançados.
83
+
84
+ ```tsx preview col
85
+ render(
86
+ <Content
87
+ as="fieldset"
88
+ framed
89
+ frameVariant="legend"
90
+ title="Dados do veículo"
91
+ >
92
+ <FieldGroup>
93
+ <Field>
94
+ <FieldLabel htmlFor="vehicle-plate">Placa</FieldLabel>
95
+ <Input id="vehicle-plate" />
96
+ </Field>
97
+ </FieldGroup>
98
+ </Content>,
99
+ );
100
+ ```
101
+
23
102
  ## Composição explícita
24
103
 
25
104
  Use os slots quando o header precisar de composição própria. A árvore aceita exatamente um
@@ -63,14 +142,17 @@ gatilho repete esse título e a edição usa `Editar recurso`.
63
142
 
64
143
  ## Propriedades de Content
65
144
 
66
- | Propriedade | Tipo | Padrão | Descrição |
67
- | ------------- | ---------------------------- | ----------- | -------------------------------------------------------------------------------------------------------- |
68
- | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
69
- | `count` | `number` | | Forma curta: total de itens ao lado do título da região. |
70
- | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
71
- | `actions` | `ReactNode` | | Forma curta: ações sobre a região inteira; em `page`, ficam no extremo oposto ao título. |
72
- | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Nível semântico do heading, independente do destaque visual. |
73
- | `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual: `page` reproduz o cabeçalho de `Page`; `section` é a região dentro de uma superfície. |
145
+ | Propriedade | Tipo | Padrão | Descrição |
146
+ | -------------- | ---------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------- |
147
+ | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
148
+ | `count` | `number` | | Forma curta: total de itens ao lado do título da região. |
149
+ | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
150
+ | `actions` | `ReactNode` | | Forma curta: ações sobre a região inteira; em `page`, ficam no extremo oposto ao título. |
151
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Nível semântico do heading, independente do destaque visual. |
152
+ | `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual: `page` reproduz o cabeçalho de `Page`; `section` é a região dentro de uma superfície. |
153
+ | `as` | `'section' \| 'fieldset'` | `'section'` | Usa uma região com heading ou um grupo de campos cujo título é a legenda nativa. |
154
+ | `framed` | `boolean` | `false` | Envolve o header e o body com a moldura estrutural da região. |
155
+ | `frameVariant` | `'default' \| 'legend'` | `'default'` | Em `fieldset` com moldura, mantém a borda contínua ou integra visualmente a legenda à borda. Não altera a semântica. |
74
156
 
75
157
  Na composição explícita, `ContentHeader` recebe `ContentTitle`, `ContentMeta`, `ContentDescription` e
76
158
  `ContentActions`, e `ContentBody` recebe o conteúdo; nenhum desses slots aceita `title` ou `level`
@@ -54,6 +54,91 @@ decide a distribuição nem a aparência dos botões.
54
54
  `DialogClose` encerra o modal sem exigir estado controlado. Use `open` e `onOpenChange` quando outra
55
55
  parte da interface também precisar controlar a abertura.
56
56
 
57
+ ## Regiões separadas ou contínuas
58
+
59
+ `layout` declara a anatomia da superfície inteira e fica em `DialogContent`; os slots leem esse
60
+ valor e não o recebem. O padrão é `sectioned`: as regiões têm o mesmo recuo, o rodapé ganha uma
61
+ faixa sutil e as fronteiras entre regiões vizinhas ganham um divisor. É o modal de tarefa, com
62
+ cabeçalho, conteúdo e ações claramente separados.
63
+
64
+ Use `layout="continuous"` para uma superfície curta, em que o espaço basta para separar as regiões
65
+ e a linha seria um ruído — um aviso de uma frase, uma escolha rápida.
66
+
67
+ ```tsx preview
68
+ <Dialog>
69
+ <DialogTrigger asChild>
70
+ <Button variant="outline">Publicar contrato</Button>
71
+ </DialogTrigger>
72
+ <DialogContent layout="continuous">
73
+ <DialogHeader>
74
+ <DialogTitle>Publicar contrato</DialogTitle>
75
+ </DialogHeader>
76
+ <DialogBody>
77
+ <p className="text-sm text-muted-foreground">
78
+ A versão publicada passa a valer para todos os consumidores.
79
+ </p>
80
+ </DialogBody>
81
+ <DialogFooter>
82
+ <ButtonGroup mode="spaced">
83
+ <DialogClose asChild>
84
+ <Button variant="ghost">Cancelar</Button>
85
+ </DialogClose>
86
+ <Button>Publicar</Button>
87
+ </ButtonGroup>
88
+ </DialogFooter>
89
+ </DialogContent>
90
+ </Dialog>
91
+ ```
92
+
93
+ Os divisores do modo seccionado são derivados da vizinhança: cada região desenha a linha quando há
94
+ uma região do outro lado. Um cabeçalho sem corpo não fecha nada, e um cabeçalho seguido direto de um
95
+ rodapé produz uma linha só. A tela não escreve `border-b` nem `border-t`.
96
+
97
+ A faixa sutil do rodapé é a mesma no `Dialog` e no [`Drawer`](/ui/drawer): as duas famílias
98
+ compartilham a anatomia, e um fluxo que troca de superfície não muda de aparência no meio.
99
+
100
+ `mode="alert"` mantém a composição centrada da resposta obrigatória e não usa `layout`.
101
+
102
+ ## Ações e navegação no cabeçalho
103
+
104
+ O cabeçalho reconhece quatro slots — `DialogNavigation`, `DialogMedia`, `DialogTitle` e
105
+ `DialogActions` — e posiciona cada um: a navegação abre a linha, o título ocupa a folga, as ações
106
+ vão para o extremo oposto e o botão de fechar entra depois delas. Um nó que não seja um desses
107
+ slots interrompe a renderização com um erro; contexto e conteúdo pertencem ao `DialogBody`.
108
+
109
+ Use `DialogActions` para uma ação da tela que precisa ficar à vista sem competir com o rodapé, como
110
+ abrir um assistente ou alternar um modo de visualização. Use `DialogNavigation` para o retorno de um
111
+ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
112
+
113
+ ```tsx preview
114
+ <Dialog>
115
+ <DialogTrigger asChild>
116
+ <Button variant="outline">Revisar evento</Button>
117
+ </DialogTrigger>
118
+ <DialogContent>
119
+ <DialogHeader>
120
+ <DialogNavigation>
121
+ <Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
122
+ <ArrowLeft />
123
+ </Button>
124
+ </DialogNavigation>
125
+ <DialogTitle>Evento 4821</DialogTitle>
126
+ <DialogActions>
127
+ <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
128
+ <Ellipsis />
129
+ </Button>
130
+ </DialogActions>
131
+ </DialogHeader>
132
+ <DialogBody>
133
+ <p className="text-sm text-muted-foreground">Detalhe do evento selecionado.</p>
134
+ </DialogBody>
135
+ </DialogContent>
136
+ </Dialog>
137
+ ```
138
+
139
+ O cabeçalho não recebe descrição: um modal já é a superfície de uma tarefa, e o contexto que ajuda a
140
+ decidir aparece no começo do corpo, como texto ou `Alert`.
141
+
57
142
  ## Pedir uma resposta pela API imperativa
58
143
 
59
144
  Use `dialog.alert`, `dialog.confirm`, `dialog.prompt` e `dialog.choose` quando a resposta couber em
@@ -280,6 +365,7 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Ence
280
365
  | `showCloseButton` | `boolean` | `true` | No modo padrão, inclui a ação de fechamento no header; o modo de alerta exige uma resposta identificável. |
281
366
  | `closeDisabled` | `boolean` | `false` | Mantém a ação visível e impede o fechamento enquanto a tarefa está bloqueada. |
282
367
  | `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
368
+ | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. Ignorado em `mode="alert"`. |
283
369
  | `className` | `string` | | Ajusta a superfície. |
284
370
  | `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou conteúdo próprio. |
285
371
 
@@ -287,8 +373,22 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Ence
287
373
 
288
374
  | Propriedade | Tipo | Padrão | Descrição |
289
375
  | ----------- | ----------- | ------ | ---------------------------------------------------------- |
290
- | `className` | `string` | | Ajusta a faixa superior. |
291
- | `children` | `ReactNode` | | Título e ações opcionais; o close padrão entra por último. |
376
+ | `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
377
+ | `children` | `ReactNode` | | Somente `DialogNavigation`, `DialogMedia`, `DialogTitle` e `DialogActions`, no máximo um de cada; o fechamento padrão entra depois deles. |
378
+
379
+ ## Propriedades de DialogNavigation
380
+
381
+ | Propriedade | Tipo | Padrão | Descrição |
382
+ | ----------- | ----------- | ------ | -------------------------------------------------------------- |
383
+ | `className` | `string` | | Ajusta a região introdutória da linha. |
384
+ | `children` | `ReactNode` | | Retorno de um fluxo modal encadeado, antes do título. |
385
+
386
+ ## Propriedades de DialogActions
387
+
388
+ | Propriedade | Tipo | Padrão | Descrição |
389
+ | ----------- | ----------- | ------ | ------------------------------------------------------------------ |
390
+ | `className` | `string` | | Ajusta o agrupamento das ações. |
391
+ | `children` | `ReactNode` | | Ações da tela no cabeçalho, antes do botão de fechar. |
292
392
 
293
393
  ## Propriedades de DialogBody
294
394
 
@@ -308,15 +408,23 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Ence
308
408
 
309
409
  | Propriedade | Tipo | Padrão | Descrição |
310
410
  | ----------- | ----------- | ------ | ------------------------------------ |
311
- | `className` | `string` | | Ajusta o título. |
411
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
412
+ | `className` | `string` | | Ajusta o título, que trunca quando não cabe na linha. |
312
413
  | `children` | `ReactNode` | | Nome da tarefa ou do conteúdo modal. |
313
414
 
314
415
  ## Propriedades de DialogMedia
315
416
 
316
- | Propriedade | Tipo | Padrão | Descrição |
317
- | ----------- | ----------- | ------ | ----------------------------------------- |
318
- | `className` | `string` | | Ajusta a moldura quadrada da mídia. |
319
- | `children` | `ReactNode` | | Ícone que reforça o contexto da resposta. |
417
+ A moldura vem do `IconTile`, como nas demais famílias. No `mode="alert"` ela cresce e centraliza:
418
+ ali a mídia não acompanha uma linha de título, ela é o que faz a pessoa reconhecer a resposta.
419
+
420
+ | Propriedade | Tipo | Padrão | Descrição |
421
+ | ----------- | ----------------------------------------------------------- | --------- | -------------------------------------------------- |
422
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `sm` | Escala da moldura; no alerta vale a moldura maior. |
423
+ | `context` | `UiContext` | `neutral` | Cor semântica da moldura. |
424
+ | `variant` | `'subtle' \| 'outline'` | `subtle` | Tratamento visual da moldura. |
425
+ | `className` | `string` | | Ajustes pontuais da moldura. |
426
+ | `children` | `ReactNode` | | Ícone que reforça o contexto da resposta. |
427
+ | `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. |
320
428
 
321
429
  ## Propriedades de DialogClose
322
430