@softize/opus 29.0.0 → 31.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +137 -0
- package/bin/lib/check.mjs +178 -94
- package/bin/lib/copy.mjs +2970 -1801
- package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +52 -0
- package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +27 -2
- package/docs/adr/0045-surface-replaces-content-and-card.md +3 -0
- package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
- package/docs/adr/0062-listas-contidas-e-texto-flexivel.md +68 -0
- package/docs/adr/0063-metadados-das-superficies.md +44 -0
- package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
- package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
- package/docs/adr/README.md +8 -0
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/SKILL.md +21 -19
- package/registry/skills/build-opus-ui/references/evaluations.md +21 -10
- package/registry/skills/build-opus-ui/references/ui-patterns.md +33 -28
- package/src/core/presentation.ts +938 -32
- package/src/core/types.ts +2 -1
- package/src/ui/components/patterns/form.tsx +2 -0
- package/src/ui/components/patterns/grouped-list.ts +2 -2
- package/src/ui/components/patterns/list.tsx +588 -365
- package/src/ui/components/patterns/page-heading-context.tsx +12 -5
- package/src/ui/components/patterns/page.tsx +238 -181
- package/src/ui/components/patterns/presentation-fields.tsx +246 -0
- package/src/ui/components/patterns/presentation-sections.tsx +494 -0
- package/src/ui/components/patterns/presentation.tsx +1142 -229
- package/src/ui/components/patterns/structural-header.tsx +47 -34
- package/src/ui/components/patterns/surface-anatomy.ts +27 -217
- package/src/ui/components/patterns/surface.tsx +55 -37
- package/src/ui/components/patterns/trigger.tsx +10 -2
- package/src/ui/components/primitives/close-button.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -8
- package/src/ui/components/primitives/detail.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +59 -89
- package/src/ui/components/primitives/drawer.tsx +52 -87
- package/src/ui/components/primitives/field.tsx +1 -1
- package/src/ui/components/primitives/pagination.tsx +3 -2
- package/src/ui/components/primitives/table.tsx +3 -3
- package/src/ui/components/primitives/tabs.tsx +13 -2
- package/src/ui/docs/content/action-form.md +2 -1
- package/src/ui/docs/content/action-list.md +146 -73
- package/src/ui/docs/content/action-trigger.md +5 -0
- package/src/ui/docs/content/button.md +5 -6
- package/src/ui/docs/content/command.md +62 -50
- package/src/ui/docs/content/compositions.md +129 -459
- package/src/ui/docs/content/dialog.md +72 -101
- package/src/ui/docs/content/drawer.md +69 -92
- package/src/ui/docs/content/field.md +2 -1
- package/src/ui/docs/content/page.md +207 -386
- package/src/ui/docs/content/presentation.md +371 -23
- package/src/ui/docs/content/separator.md +1 -1
- package/src/ui/docs/content/surface.md +94 -116
- package/src/ui/docs/content/table.md +7 -0
- package/src/ui/docs/content/tokens.md +18 -4
- package/src/ui/drivers/context.tsx +11 -4
- package/src/ui/drivers/react.tsx +27 -7
- package/src/ui/meta.ts +5 -5
- package/src/ui/react.tsx +38 -8
- package/src/ui/theme.css +44 -33
|
@@ -1,491 +1,161 @@
|
|
|
1
|
-
|
|
2
|
-
title: Composições
|
|
3
|
-
---
|
|
1
|
+
## Uma estrutura para cada superfície
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
Page, Dialog, Drawer e Surface compartilham cabeçalho, corpo e rodapé. Escolha a superfície
|
|
4
|
+
pelo contexto da tarefa: Page ocupa a área principal, Dialog interrompe para uma tarefa,
|
|
5
|
+
Drawer mantém o detalhe lateral e Surface agrupa uma região dentro do conteúdo.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
| Região | Page | Dialog | Drawer | Surface |
|
|
8
|
+
| ------------ | ----------- | ------------- | ------------- | -------------- |
|
|
9
|
+
| Cabeçalho | PageHeader | DialogHeader | DrawerHeader | SurfaceHeader |
|
|
10
|
+
| Título | PageTitle | DialogTitle | DrawerTitle | SurfaceTitle |
|
|
11
|
+
| Metadados | PageMeta | DialogMeta | DrawerMeta | SurfaceMeta |
|
|
12
|
+
| Ações gerais | PageActions | DialogActions | DrawerActions | SurfaceActions |
|
|
13
|
+
| Corpo | PageBody | DialogBody | DrawerBody | SurfaceBody |
|
|
14
|
+
| Rodapé | PageFooter | DialogFooter | DrawerFooter | SurfaceFooter |
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
## As regiões de cada superfície
|
|
19
|
-
|
|
20
|
-
Cada família dá um nome próprio a cada região. A tabela mostra a correspondência entre elas.
|
|
21
|
-
|
|
22
|
-
| Região | Page | Dialog | Drawer | Surface |
|
|
23
|
-
| -------------------- | ------------------------------------------- | ----------------------------- | ----------------------------- | ----------------------------- |
|
|
24
|
-
| Navegação | `PageNavigation` ou `PageBack` | `DialogNavigation` | `DrawerNavigation` | Não existe |
|
|
25
|
-
| Título no cabeçalho | `PageTitle` | `DialogTitle` | `DrawerTitle` | `SurfaceTitle` |
|
|
26
|
-
| Ações do cabeçalho | `PageActions` | `DialogActions` | `DrawerActions` | `SurfaceActions` |
|
|
27
|
-
| Intro | `PageIntro` no início do `PageBody` | `DialogIntro` | `DrawerIntro` | Não existe |
|
|
28
|
-
| Ações da intro | `PageIntroActions` | `DialogIntroActions` | `DrawerIntroActions` | Não existe |
|
|
29
|
-
| Corpo | `PageBody` | `DialogBody` | `DrawerBody` | `SurfaceBody` |
|
|
30
|
-
| Rodapé | `PageFooter` | `DialogFooter` | `DrawerFooter` | `SurfaceFooter` |
|
|
31
|
-
| Divisores | Antes do `PageFooter` | `sectioned` (padrão) | `sectioned` (padrão) | `sectioned` |
|
|
32
|
-
| Sem divisores | Cabeçalho e corpo | `continuous` | `continuous` | `continuous` (padrão) |
|
|
33
|
-
|
|
34
|
-
`layout` escolhe entre as duas anatomias em `DialogContent`, `DrawerContent` e `Surface`. Em
|
|
35
|
-
`sectioned`, uma linha separa as regiões vizinhas; em `continuous`, o espaço faz essa separação. Na
|
|
36
|
-
`Surface`, `sectioned` exige `framed` ou `elevation="raised"`, para que a linha tenha um limite. A
|
|
37
|
-
`Page` não oferece anatomia `sectioned`: cabeçalho e corpo são contínuos, enquanto o `PageFooter`
|
|
38
|
-
é uma faixa própria, separada por sua borda superior. O `layout` da página decide apenas a ocupação
|
|
39
|
-
de altura.
|
|
16
|
+
O título pertence ao cabeçalho. Descrição opcional e metadados têm slots próprios. Cabeçalho
|
|
17
|
+
e rodapé ficam fora da rolagem do corpo em Page e modais; a Surface acompanha o fluxo do conteúdo.
|
|
18
|
+
Os divisores são automáticos, sem escolha de anatomia contínua ou compacta.
|
|
40
19
|
|
|
41
20
|
## Onde cada ação fica
|
|
42
21
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
| Intro | Ações ligadas ao título e ao conteúdo, como ver o histórico do registro. |
|
|
51
|
-
| Rodapé | A decisão da etapa: **Cancelar** em `ghost` e a ação principal sólida, alinhadas à direita. |
|
|
52
|
-
|
|
53
|
-
Em `Dialog` e `Drawer`, a navegação abre a linha do cabeçalho e fica junto do título, a `0.5rem`
|
|
54
|
-
dele. As ações ficam no extremo oposto, antes do botão de fechar, e mantêm a distância maior da
|
|
55
|
-
família até o título. Na `Page`, a navegação fica acima do título; quando o título está na intro,
|
|
56
|
-
ela divide a linha com as ações da página.
|
|
57
|
-
|
|
58
|
-
Em `Dialog` e `Drawer`, cabeçalho e rodapé permanecem visíveis enquanto o corpo rola; a intro rola
|
|
59
|
-
junto com o conteúdo.
|
|
60
|
-
|
|
61
|
-
## Título no cabeçalho ou na intro
|
|
62
|
-
|
|
63
|
-
O título pode ficar em dois lugares, e essa escolha define a composição:
|
|
22
|
+
| Ação | Região |
|
|
23
|
+
| ----------------------------------------------------- | ------------------------- |
|
|
24
|
+
| Retorno, histórico ou configuração do recurso inteiro | Ações do cabeçalho |
|
|
25
|
+
| Criar, importar, exportar ou operar a coleção | ActionList.toolbarActions |
|
|
26
|
+
| Operar os registros selecionados | ActionList.batchActions |
|
|
27
|
+
| Operar um registro da lista | ActionList.rowActions |
|
|
28
|
+
| Salvar ou cancelar uma etapa | Rodapé |
|
|
64
29
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
continuar estáveis e separados do registro aberto.
|
|
68
|
-
- **Compacta:** título, ações do conteúdo e ações da superfície dividem a linha do cabeçalho, e a
|
|
69
|
-
intro é omitida. Use quando uma linha basta para nomear a tarefa e agir sobre ela.
|
|
30
|
+
O botão de criação mostra **Criar**. Seu nome acessível e o título do formulário identificam
|
|
31
|
+
o recurso. Menus com vários tipos de criação mantêm nomes específicos.
|
|
70
32
|
|
|
71
|
-
|
|
72
|
-
ações. Em `Dialog` e `Drawer`, o título no cabeçalho trunca quando não cabe na linha; na intro, ele
|
|
73
|
-
usa uma escala maior e quebra em mais de uma linha.
|
|
33
|
+
## Página
|
|
74
34
|
|
|
75
|
-
|
|
35
|
+
A página usa a largura disponível. Para uma lista preencher a altura restante, declare
|
|
36
|
+
`layout="fill"`; para conteúdo que rola no corpo, mantenha `flow`.
|
|
76
37
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<DialogHeader>
|
|
99
|
-
<DialogActions>
|
|
100
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
101
|
-
<MessageCircle />
|
|
102
|
-
</Button>
|
|
103
|
-
</DialogActions>
|
|
104
|
-
</DialogHeader>
|
|
105
|
-
<DialogBody>
|
|
106
|
-
<DialogIntro>
|
|
107
|
-
<DialogTitle>Editar ordem de serviço</DialogTitle>
|
|
108
|
-
<DialogIntroActions>
|
|
109
|
-
<Button variant="outline" size="sm">
|
|
110
|
-
Ver histórico
|
|
111
|
-
</Button>
|
|
112
|
-
</DialogIntroActions>
|
|
113
|
-
</DialogIntro>
|
|
114
|
-
<OrderField />
|
|
115
|
-
</DialogBody>
|
|
116
|
-
<DialogFooter>
|
|
117
|
-
<ButtonGroup mode="spaced">
|
|
118
|
-
<DialogClose asChild>
|
|
119
|
-
<Button variant="ghost">Cancelar</Button>
|
|
120
|
-
</DialogClose>
|
|
121
|
-
<Button>Salvar</Button>
|
|
122
|
-
</ButtonGroup>
|
|
123
|
-
</DialogFooter>
|
|
124
|
-
</DialogContent>
|
|
125
|
-
</Dialog>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function CompactDialog({ layout, label }) {
|
|
130
|
-
return (
|
|
131
|
-
<Dialog>
|
|
132
|
-
<DialogTrigger asChild>
|
|
133
|
-
<Button variant="outline">{label}</Button>
|
|
134
|
-
</DialogTrigger>
|
|
135
|
-
<DialogContent layout={layout}>
|
|
136
|
-
<DialogHeader>
|
|
137
|
-
<DialogMedia>
|
|
138
|
-
<Wrench />
|
|
139
|
-
</DialogMedia>
|
|
140
|
-
<DialogTitle>Editar ordem de serviço</DialogTitle>
|
|
141
|
-
<DialogActions>
|
|
142
|
-
<Button variant="outline" size="sm">
|
|
143
|
-
Ver histórico
|
|
144
|
-
</Button>
|
|
145
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
146
|
-
<MessageCircle />
|
|
147
|
-
</Button>
|
|
148
|
-
</DialogActions>
|
|
149
|
-
</DialogHeader>
|
|
150
|
-
<DialogBody>
|
|
151
|
-
<OrderField />
|
|
152
|
-
</DialogBody>
|
|
153
|
-
<DialogFooter>
|
|
154
|
-
<ButtonGroup mode="spaced">
|
|
155
|
-
<DialogClose asChild>
|
|
156
|
-
<Button variant="ghost">Cancelar</Button>
|
|
157
|
-
</DialogClose>
|
|
158
|
-
<Button>Salvar</Button>
|
|
159
|
-
</ButtonGroup>
|
|
160
|
-
</DialogFooter>
|
|
161
|
-
</DialogContent>
|
|
162
|
-
</Dialog>
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
render(
|
|
167
|
-
<div className="grid grid-cols-2 gap-3">
|
|
168
|
-
<DialogWithIntro layout="sectioned" label="Seccionado com intro" />
|
|
169
|
-
<CompactDialog layout="sectioned" label="Seccionado compacto" />
|
|
170
|
-
<DialogWithIntro layout="continuous" label="Contínuo com intro" />
|
|
171
|
-
<CompactDialog layout="continuous" label="Contínuo compacto" />
|
|
172
|
-
</div>,
|
|
173
|
-
);
|
|
38
|
+
```tsx preview col
|
|
39
|
+
<Page>
|
|
40
|
+
<PageHeader>
|
|
41
|
+
<PageTitle>Evento</PageTitle>
|
|
42
|
+
<PageActions>
|
|
43
|
+
<PageBack href="/events">Eventos</PageBack>
|
|
44
|
+
<Button variant="ghost" size="icon" aria-label="Histórico">
|
|
45
|
+
<History />
|
|
46
|
+
</Button>
|
|
47
|
+
</PageActions>
|
|
48
|
+
</PageHeader>
|
|
49
|
+
<PageBody>
|
|
50
|
+
<p>Dados do evento.</p>
|
|
51
|
+
</PageBody>
|
|
52
|
+
<PageFooter>
|
|
53
|
+
<ButtonGroup mode="spaced">
|
|
54
|
+
<Button variant="ghost">Cancelar</Button>
|
|
55
|
+
<Button>Salvar</Button>
|
|
56
|
+
</ButtonGroup>
|
|
57
|
+
</PageFooter>
|
|
58
|
+
</Page>
|
|
174
59
|
```
|
|
175
60
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
precisar voltar à anterior.
|
|
61
|
+
`PageShell` fornece ações conhecidas pelo shell sem criar outra barra. Subpáginas usam
|
|
62
|
+
`PageBack` como primeiro ícone das ações, com destino explícito.
|
|
179
63
|
|
|
180
|
-
##
|
|
64
|
+
## Diálogo
|
|
181
65
|
|
|
182
|
-
O
|
|
183
|
-
|
|
184
|
-
dois controles de fechamento.
|
|
66
|
+
O diálogo preserva a mesma ordem das regiões. Fechar, Escape e o clique fora dispensam
|
|
67
|
+
uma tarefa comum; use `closeDisabled` durante uma operação que não possa ser interrompida.
|
|
185
68
|
|
|
186
69
|
```tsx preview
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
<DrawerContent layout={layout} showCloseButton={false}>
|
|
214
|
-
<DrawerHeader>
|
|
215
|
-
<DrawerNavigation>
|
|
216
|
-
<CollapseButton />
|
|
217
|
-
</DrawerNavigation>
|
|
218
|
-
<DrawerActions>
|
|
219
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
220
|
-
<MessageCircle />
|
|
221
|
-
</Button>
|
|
222
|
-
</DrawerActions>
|
|
223
|
-
</DrawerHeader>
|
|
224
|
-
<DrawerBody>
|
|
225
|
-
<DrawerIntro>
|
|
226
|
-
<DrawerTitle>Editar ordem de serviço</DrawerTitle>
|
|
227
|
-
<DrawerIntroActions>
|
|
228
|
-
<Button variant="outline" size="sm">
|
|
229
|
-
Ver histórico
|
|
230
|
-
</Button>
|
|
231
|
-
</DrawerIntroActions>
|
|
232
|
-
</DrawerIntro>
|
|
233
|
-
<OrderField />
|
|
234
|
-
</DrawerBody>
|
|
235
|
-
<DrawerFooter>
|
|
236
|
-
<ButtonGroup mode="spaced">
|
|
237
|
-
<DrawerClose asChild>
|
|
238
|
-
<Button variant="ghost">Cancelar</Button>
|
|
239
|
-
</DrawerClose>
|
|
240
|
-
<Button>Salvar</Button>
|
|
241
|
-
</ButtonGroup>
|
|
242
|
-
</DrawerFooter>
|
|
243
|
-
</DrawerContent>
|
|
244
|
-
</Drawer>
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function CompactDrawer({ layout, label }) {
|
|
249
|
-
return (
|
|
250
|
-
<Drawer>
|
|
251
|
-
<DrawerTrigger asChild>
|
|
252
|
-
<Button variant="outline">{label}</Button>
|
|
253
|
-
</DrawerTrigger>
|
|
254
|
-
<DrawerContent layout={layout} showCloseButton={false}>
|
|
255
|
-
<DrawerHeader>
|
|
256
|
-
<DrawerNavigation>
|
|
257
|
-
<CollapseButton />
|
|
258
|
-
</DrawerNavigation>
|
|
259
|
-
<DrawerTitle>Editar ordem de serviço</DrawerTitle>
|
|
260
|
-
<DrawerActions>
|
|
261
|
-
<Button variant="outline" size="sm">
|
|
262
|
-
Ver histórico
|
|
263
|
-
</Button>
|
|
264
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
265
|
-
<MessageCircle />
|
|
266
|
-
</Button>
|
|
267
|
-
</DrawerActions>
|
|
268
|
-
</DrawerHeader>
|
|
269
|
-
<DrawerBody>
|
|
270
|
-
<OrderField />
|
|
271
|
-
</DrawerBody>
|
|
272
|
-
<DrawerFooter>
|
|
273
|
-
<ButtonGroup mode="spaced">
|
|
274
|
-
<DrawerClose asChild>
|
|
275
|
-
<Button variant="ghost">Cancelar</Button>
|
|
276
|
-
</DrawerClose>
|
|
277
|
-
<Button>Salvar</Button>
|
|
278
|
-
</ButtonGroup>
|
|
279
|
-
</DrawerFooter>
|
|
280
|
-
</DrawerContent>
|
|
281
|
-
</Drawer>
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
render(
|
|
286
|
-
<div className="grid grid-cols-2 gap-3">
|
|
287
|
-
<DrawerWithIntro layout="sectioned" label="Seccionado com intro" />
|
|
288
|
-
<CompactDrawer layout="sectioned" label="Seccionado compacto" />
|
|
289
|
-
<DrawerWithIntro layout="continuous" label="Contínuo com intro" />
|
|
290
|
-
<CompactDrawer layout="continuous" label="Contínuo compacto" />
|
|
291
|
-
</div>,
|
|
292
|
-
);
|
|
70
|
+
<Dialog>
|
|
71
|
+
<DialogTrigger asChild>
|
|
72
|
+
<Button variant="outline">Abrir diálogo</Button>
|
|
73
|
+
</DialogTrigger>
|
|
74
|
+
<DialogContent aria-describedby={undefined}>
|
|
75
|
+
<DialogHeader>
|
|
76
|
+
<DialogTitle>Editar evento</DialogTitle>
|
|
77
|
+
<DialogActions>
|
|
78
|
+
<Button variant="ghost" size="icon" aria-label="Histórico">
|
|
79
|
+
<History />
|
|
80
|
+
</Button>
|
|
81
|
+
</DialogActions>
|
|
82
|
+
</DialogHeader>
|
|
83
|
+
<DialogBody>
|
|
84
|
+
<p>Dados do evento.</p>
|
|
85
|
+
</DialogBody>
|
|
86
|
+
<DialogFooter>
|
|
87
|
+
<ButtonGroup mode="spaced">
|
|
88
|
+
<DialogClose asChild>
|
|
89
|
+
<Button variant="ghost">Cancelar</Button>
|
|
90
|
+
</DialogClose>
|
|
91
|
+
<Button>Salvar</Button>
|
|
92
|
+
</ButtonGroup>
|
|
93
|
+
</DialogFooter>
|
|
94
|
+
</DialogContent>
|
|
95
|
+
</Dialog>
|
|
293
96
|
```
|
|
294
97
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
qualquer outro nó, inclusive um componente local que devolva um slot. Por isso, o exemplo extrai
|
|
298
|
-
apenas o botão de recolher. Sem o botão de fechar, Esc e o clique no overlay continuam fechando o
|
|
299
|
-
painel.
|
|
300
|
-
|
|
301
|
-
## Page
|
|
98
|
+
`Dialog mode="alert"` conserva sua composição de resposta obrigatória. É uma diferença de
|
|
99
|
+
comportamento, não uma opção de densidade do formulário.
|
|
302
100
|
|
|
303
|
-
|
|
304
|
-
página, e uma `PageIntro` abre o `PageBody` com o título e as ações do conteúdo. A página
|
|
305
|
-
precisa de exatamente um heading principal, por isso o `PageHeader` dessa composição não leva
|
|
306
|
-
`PageTitle`.
|
|
307
|
-
|
|
308
|
-
```tsx preview col
|
|
309
|
-
render(
|
|
310
|
-
<div className="w-full overflow-hidden rounded-lg border border-border">
|
|
311
|
-
<Page>
|
|
312
|
-
<PageHeader>
|
|
313
|
-
<PageNavigation>
|
|
314
|
-
<Breadcrumb>
|
|
315
|
-
<BreadcrumbList>
|
|
316
|
-
<BreadcrumbItem>Oficina</BreadcrumbItem>
|
|
317
|
-
<BreadcrumbSeparator />
|
|
318
|
-
<BreadcrumbItem>Ordens de serviço</BreadcrumbItem>
|
|
319
|
-
<BreadcrumbSeparator />
|
|
320
|
-
<BreadcrumbPage>OS-1842</BreadcrumbPage>
|
|
321
|
-
</BreadcrumbList>
|
|
322
|
-
</Breadcrumb>
|
|
323
|
-
</PageNavigation>
|
|
324
|
-
<PageActions>
|
|
325
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
326
|
-
<MessageCircle />
|
|
327
|
-
</Button>
|
|
328
|
-
</PageActions>
|
|
329
|
-
</PageHeader>
|
|
330
|
-
<PageBody>
|
|
331
|
-
<PageIntro>
|
|
332
|
-
<PageTitle>Editar ordem de serviço</PageTitle>
|
|
333
|
-
<PageIntroActions><Button variant="outline" size="sm">Ver histórico</Button></PageIntroActions>
|
|
334
|
-
</PageIntro>
|
|
335
|
-
<div className="space-y-2">
|
|
336
|
-
<Label htmlFor="page-intro-owner">Responsável</Label>
|
|
337
|
-
<Input id="page-intro-owner" defaultValue="Marina Alves" />
|
|
338
|
-
</div>
|
|
339
|
-
</PageBody>
|
|
340
|
-
<PageFooter>
|
|
341
|
-
<ButtonGroup mode="spaced">
|
|
342
|
-
<Button variant="ghost">Cancelar</Button>
|
|
343
|
-
<Button>Salvar</Button>
|
|
344
|
-
</ButtonGroup>
|
|
345
|
-
</PageFooter>
|
|
346
|
-
</Page>
|
|
347
|
-
</div>,
|
|
348
|
-
);
|
|
349
|
-
```
|
|
101
|
+
## Painel lateral
|
|
350
102
|
|
|
351
|
-
|
|
352
|
-
`PageActions`, antes das ações da página. A forma curta, `<Page title actions>`, produz esse mesmo
|
|
353
|
-
cabeçalho; nela, a navegação vem do [`PageShell`](/ui/page).
|
|
103
|
+
O drawer usa o mesmo cabeçalho e mantém seu corpo rolável até a altura disponível.
|
|
354
104
|
|
|
355
|
-
```tsx preview
|
|
356
|
-
|
|
357
|
-
<
|
|
358
|
-
<
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
</Button>
|
|
376
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
377
|
-
<MessageCircle />
|
|
378
|
-
</Button>
|
|
379
|
-
</PageActions>
|
|
380
|
-
</PageHeader>
|
|
381
|
-
<PageBody>
|
|
382
|
-
<div className="space-y-2">
|
|
383
|
-
<Label htmlFor="page-compact-owner">Responsável</Label>
|
|
384
|
-
<Input id="page-compact-owner" defaultValue="Marina Alves" />
|
|
385
|
-
</div>
|
|
386
|
-
</PageBody>
|
|
387
|
-
<PageFooter>
|
|
388
|
-
<ButtonGroup mode="spaced">
|
|
105
|
+
```tsx preview
|
|
106
|
+
<Drawer>
|
|
107
|
+
<DrawerTrigger asChild>
|
|
108
|
+
<Button variant="outline">Abrir painel</Button>
|
|
109
|
+
</DrawerTrigger>
|
|
110
|
+
<DrawerContent aria-describedby={undefined}>
|
|
111
|
+
<DrawerHeader>
|
|
112
|
+
<DrawerTitle>Evento</DrawerTitle>
|
|
113
|
+
<DrawerActions>
|
|
114
|
+
<Button variant="ghost" size="icon" aria-label="Histórico">
|
|
115
|
+
<History />
|
|
116
|
+
</Button>
|
|
117
|
+
</DrawerActions>
|
|
118
|
+
</DrawerHeader>
|
|
119
|
+
<DrawerBody>
|
|
120
|
+
<p>Dados do evento.</p>
|
|
121
|
+
</DrawerBody>
|
|
122
|
+
<DrawerFooter>
|
|
123
|
+
<ButtonGroup mode="spaced">
|
|
124
|
+
<DrawerClose asChild>
|
|
389
125
|
<Button variant="ghost">Cancelar</Button>
|
|
390
|
-
|
|
391
|
-
</
|
|
392
|
-
</
|
|
393
|
-
</
|
|
394
|
-
</
|
|
395
|
-
|
|
126
|
+
</DrawerClose>
|
|
127
|
+
<Button>Salvar</Button>
|
|
128
|
+
</ButtonGroup>
|
|
129
|
+
</DrawerFooter>
|
|
130
|
+
</DrawerContent>
|
|
131
|
+
</Drawer>
|
|
396
132
|
```
|
|
397
133
|
|
|
398
|
-
Use `PageFooter` quando a página for uma etapa com decisão própria, como esta edição.
|
|
399
|
-
|
|
400
134
|
## Pane com Surface
|
|
401
135
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
dentro dela. A `Surface` não tem intro, então o título fica no `SurfaceHeader`, como na composição
|
|
405
|
-
compacta.
|
|
136
|
+
Pane distribui espaço; Surface fornece a apresentação. Moldura e elevação continuam
|
|
137
|
+
independentes da composição do cabeçalho, corpo e rodapé.
|
|
406
138
|
|
|
407
139
|
```tsx preview col
|
|
408
|
-
|
|
409
|
-
<
|
|
410
|
-
<
|
|
411
|
-
<
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
items: [
|
|
419
|
-
{ id: "os-1842", label: "OS-1842" },
|
|
420
|
-
{ id: "os-1839", label: "OS-1839" },
|
|
421
|
-
{ id: "os-1835", label: "OS-1835" },
|
|
422
|
-
],
|
|
423
|
-
},
|
|
424
|
-
]}
|
|
425
|
-
/>
|
|
426
|
-
</Sidebar>
|
|
427
|
-
</Pane>
|
|
428
|
-
<Pane grow>
|
|
429
|
-
<Surface
|
|
430
|
-
as="section"
|
|
431
|
-
framed
|
|
432
|
-
elevation="raised"
|
|
433
|
-
layout="sectioned"
|
|
434
|
-
className="flex h-full flex-col"
|
|
435
|
-
>
|
|
436
|
-
<SurfaceHeader>
|
|
437
|
-
<SurfaceMedia>
|
|
438
|
-
<Wrench />
|
|
439
|
-
</SurfaceMedia>
|
|
440
|
-
<SurfaceTitle>Editar ordem de serviço</SurfaceTitle>
|
|
441
|
-
<SurfaceActions>
|
|
442
|
-
<Button variant="outline" size="sm">
|
|
443
|
-
Ver histórico
|
|
444
|
-
</Button>
|
|
445
|
-
<Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
|
|
446
|
-
<MessageCircle />
|
|
447
|
-
</Button>
|
|
448
|
-
</SurfaceActions>
|
|
449
|
-
</SurfaceHeader>
|
|
450
|
-
<SurfaceBody className="min-h-0 flex-1 overflow-y-auto">
|
|
451
|
-
<div className="space-y-2">
|
|
452
|
-
<Label htmlFor="pane-owner">Responsável</Label>
|
|
453
|
-
<Input id="pane-owner" defaultValue="Marina Alves" />
|
|
454
|
-
</div>
|
|
455
|
-
</SurfaceBody>
|
|
456
|
-
<SurfaceFooter>
|
|
457
|
-
<ButtonGroup mode="spaced">
|
|
458
|
-
<Button variant="ghost">Cancelar</Button>
|
|
459
|
-
<Button>Salvar</Button>
|
|
460
|
-
</ButtonGroup>
|
|
461
|
-
</SurfaceFooter>
|
|
462
|
-
</Surface>
|
|
463
|
-
</Pane>
|
|
464
|
-
</Split>
|
|
465
|
-
</div>,
|
|
466
|
-
);
|
|
140
|
+
<Pane>
|
|
141
|
+
<Surface framed title="Evento">
|
|
142
|
+
<SurfaceBody>
|
|
143
|
+
<p>Dados do evento.</p>
|
|
144
|
+
</SurfaceBody>
|
|
145
|
+
<SurfaceFooter>
|
|
146
|
+
<Button>Salvar</Button>
|
|
147
|
+
</SurfaceFooter>
|
|
148
|
+
</Surface>
|
|
149
|
+
</Pane>
|
|
467
150
|
```
|
|
468
151
|
|
|
469
|
-
|
|
470
|
-
[`Sidebar`](/ui/sidebar), que já tem anatomia própria, e o segundo, uma `Surface` completa. A
|
|
471
|
-
rolagem também pertence ao conteúdo: a `Surface` ocupa a altura do pane com `flex h-full flex-col`,
|
|
472
|
-
e o `SurfaceBody` declara `min-h-0 flex-1 overflow-y-auto` para rolar entre o cabeçalho e o rodapé.
|
|
473
|
-
|
|
474
|
-
## Ritmo entre regiões e blocos
|
|
475
|
-
|
|
476
|
-
Surface (incluindo cards e seções), Page, Dialog, Drawer e Tabs organizam o conteúdo
|
|
477
|
-
com intervalos de `1rem`. Os bodies separam seus blocos diretos; grupos internos podem
|
|
478
|
-
ter densidade própria. DetailGroup e Separator não criam margens externas.
|
|
479
|
-
|
|
480
|
-
Sem delimitação, Surface e Tabs não adicionam padding inferior. Uma Surface com moldura
|
|
481
|
-
ou elevação, assim como Dialog e Drawer, reserva `1rem` até a borda. No layout contínuo,
|
|
482
|
-
o intervalo vem da região anterior. No seccionado, há `1rem` entre cada divisória e o
|
|
483
|
-
conteúdo adjacente. Não some padding e gap para expressar o mesmo intervalo.
|
|
152
|
+
## Abas e espaçamento
|
|
484
153
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
O modo `flush` remove recuos do body para uma lista ou tabela controlar sua própria borda,
|
|
488
|
-
mas mantém o intervalo entre blocos.
|
|
154
|
+
O header de cada família aceita `tabs`, com uma `TabsList` governada por `Tabs` ancestral.
|
|
155
|
+
Os painéis ficam no body. Ações de listagem permanecem dentro do painel correspondente.
|
|
489
156
|
|
|
490
|
-
|
|
491
|
-
|
|
157
|
+
Superfícies delimitadas usam recuo de `1rem` em cada região. A linha de cabeçalho reserva
|
|
158
|
+
`2,25rem`, com ou sem ações, e recebe botões `default` ou `icon`. O corpo separa blocos diretos
|
|
159
|
+
por `1rem`; grupos com ritmo próprio ficam em um wrapper filho. `flush` permite que um conteúdo
|
|
160
|
+
controle seu próprio recuo. Surface sem moldura ou elevação mantém alinhamento lateral com
|
|
161
|
+
o hospedeiro, sem padding inferior extra. Não reescreva essas medidas em cada tela.
|