@softize/opus 23.0.0 → 24.0.1
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 +99 -0
- package/bin/cli.mjs +2 -0
- package/bin/lib/check.mjs +241 -42
- package/bin/lib/copy.mjs +16 -34
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +6 -0
- package/docs/adr/0039-filter-presentation-is-independent-from-filter-type.md +3 -3
- package/docs/adr/0040-tabs-use-a-single-navigation-presentation.md +5 -6
- package/docs/adr/0042-toggle-group-shares-the-grouped-control-grammar.md +79 -0
- package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +73 -0
- package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +133 -0
- package/docs/adr/0045-surface-replaces-content-and-card.md +230 -0
- package/docs/adr/0046-structural-body-owns-content-rhythm.md +103 -0
- package/docs/adr/0047-pane-is-only-a-split-layout-unit.md +71 -0
- package/docs/adr/0048-modal-intro-separates-content-from-chrome.md +34 -0
- package/docs/adr/0049-inline-navigation-groups-with-the-heading.md +95 -0
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/SKILL.md +11 -11
- package/registry/skills/build-opus-ui/references/evaluations.md +10 -9
- package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -16
- package/registry/templates/app/src/App.tsx +24 -12
- package/src/ui/appearance.ts +149 -0
- package/src/ui/components/patterns/action-form-card.tsx +46 -33
- package/src/ui/components/patterns/action-list-dialog.tsx +2 -4
- package/src/ui/components/patterns/confirm.tsx +3 -1
- package/src/ui/components/patterns/fill-region.ts +8 -7
- package/src/ui/components/patterns/form-dialog.tsx +1 -3
- package/src/ui/components/patterns/form.tsx +8 -7
- package/src/ui/components/patterns/list.tsx +15 -19
- package/src/ui/components/patterns/page.tsx +15 -11
- package/src/ui/components/patterns/pane.tsx +9 -240
- package/src/ui/components/patterns/presentation.tsx +14 -14
- package/src/ui/components/patterns/sidebar.tsx +7 -17
- package/src/ui/components/patterns/split.tsx +111 -59
- package/src/ui/components/patterns/{surface-header.tsx → structural-header.tsx} +90 -27
- package/src/ui/components/patterns/structural-media.tsx +26 -0
- package/src/ui/components/patterns/surface-anatomy.ts +71 -61
- package/src/ui/components/patterns/surface-assistant.tsx +2 -4
- package/src/ui/components/patterns/surface.tsx +620 -0
- package/src/ui/components/patterns/trigger.tsx +11 -9
- package/src/ui/components/primitives/ask.tsx +155 -83
- package/src/ui/components/primitives/button.tsx +11 -9
- package/src/ui/components/primitives/checkbox.tsx +8 -8
- package/src/ui/components/primitives/command.tsx +1 -1
- package/src/ui/components/primitives/composer.tsx +47 -45
- package/src/ui/components/primitives/detail.tsx +9 -2
- package/src/ui/components/primitives/dialog.tsx +60 -26
- package/src/ui/components/primitives/drawer.tsx +58 -12
- package/src/ui/components/primitives/icon-picker.tsx +90 -73
- package/src/ui/components/primitives/input-group.tsx +35 -28
- package/src/ui/components/primitives/input-otp.tsx +16 -16
- package/src/ui/components/primitives/input.tsx +20 -10
- package/src/ui/components/primitives/item.tsx +9 -12
- package/src/ui/components/primitives/menu.tsx +44 -65
- package/src/ui/components/primitives/metric-card.tsx +75 -59
- package/src/ui/components/primitives/radio-group.tsx +9 -9
- package/src/ui/components/primitives/select.tsx +344 -209
- package/src/ui/components/primitives/switch.tsx +10 -10
- package/src/ui/components/primitives/table.tsx +29 -24
- package/src/ui/components/primitives/tabs.tsx +4 -2
- package/src/ui/components/primitives/textarea.tsx +6 -6
- package/src/ui/components/primitives/toggle-group-context.ts +24 -0
- package/src/ui/components/primitives/toggle-group.tsx +116 -74
- package/src/ui/components/primitives/toggle.tsx +82 -16
- package/src/ui/docs/DocBrowser.tsx +77 -69
- package/src/ui/docs/content/action-form-card.md +9 -9
- package/src/ui/docs/content/action-list.md +76 -70
- package/src/ui/docs/content/action-view.md +33 -18
- package/src/ui/docs/content/button.md +1 -1
- package/src/ui/docs/content/communication.md +1 -1
- package/src/ui/docs/content/compositions.md +479 -0
- package/src/ui/docs/content/customization.md +64 -11
- package/src/ui/docs/content/detail.md +8 -6
- package/src/ui/docs/content/dialog.md +105 -60
- package/src/ui/docs/content/drawer.md +68 -22
- package/src/ui/docs/content/field.md +14 -15
- package/src/ui/docs/content/icon-tile.md +14 -13
- package/src/ui/docs/content/page.md +44 -34
- package/src/ui/docs/content/pane.md +42 -290
- package/src/ui/docs/content/presentation.md +3 -3
- package/src/ui/docs/content/separator.md +6 -6
- package/src/ui/docs/content/sidebar.md +68 -266
- package/src/ui/docs/content/skeleton.md +20 -18
- package/src/ui/docs/content/split.md +14 -14
- package/src/ui/docs/content/surface.md +513 -0
- package/src/ui/docs/content/tabs.md +20 -20
- package/src/ui/docs/content/toggle.md +117 -65
- package/src/ui/docs/content/tokens.md +124 -40
- package/src/ui/docs/registry.tsx +10 -6
- package/src/ui/index.ts +30 -27
- package/src/ui/meta.ts +15 -27
- package/src/ui/react.tsx +40 -43
- package/src/ui/theme.css +311 -64
- package/src/ui/components/patterns/content-header.tsx +0 -528
- package/src/ui/components/patterns/surface-media.tsx +0 -69
- package/src/ui/components/primitives/card.tsx +0 -191
- package/src/ui/docs/content/card.md +0 -292
- package/src/ui/docs/content/content.md +0 -275
|
@@ -37,14 +37,14 @@ vincula ao controle, ligue-o ao controle por `aria-labelledby` para manter o nom
|
|
|
37
37
|
|
|
38
38
|
## Conjunto com legenda e erro
|
|
39
39
|
|
|
40
|
-
Use [`
|
|
40
|
+
Use [`Surface`](/ui/surface) com `as="fieldset"` para nomear um conjunto de campos relacionados. O título vira a legenda
|
|
41
41
|
nativa, enquanto `FieldGroup` define o espaçamento e `FieldSeparator` marca uma divisão.
|
|
42
42
|
`FieldError` aparece somente quando existe mensagem de erro. Declare `data-invalid="true"` no
|
|
43
43
|
`Field` para que o rótulo acompanhe o contexto de erro; `aria-invalid` marca apenas o controle. O
|
|
44
44
|
`ActionForm` define os dois atributos sozinho.
|
|
45
45
|
|
|
46
46
|
```tsx preview col md
|
|
47
|
-
<
|
|
47
|
+
<Surface as="fieldset" title="Novo agente">
|
|
48
48
|
<FieldGroup>
|
|
49
49
|
<Field data-invalid="true">
|
|
50
50
|
<FieldLabel htmlFor="agent-name">Nome</FieldLabel>
|
|
@@ -69,7 +69,7 @@ nativa, enquanto `FieldGroup` define o espaçamento e `FieldSeparator` marca uma
|
|
|
69
69
|
/>
|
|
70
70
|
</Field>
|
|
71
71
|
</FieldGroup>
|
|
72
|
-
</
|
|
72
|
+
</Surface>
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
## Campo desabilitado
|
|
@@ -86,15 +86,14 @@ declare também `data-disabled="true"` no `Field`: `FieldLabel` e `FieldTitle` e
|
|
|
86
86
|
|
|
87
87
|
## Conjunto com moldura
|
|
88
88
|
|
|
89
|
-
Use a moldura para distinguir grupos vizinhos que continuem pertencendo ao mesmo formulário.
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
Use a moldura para distinguir grupos vizinhos que continuem pertencendo ao mesmo formulário.
|
|
90
|
+
Declare `as="fieldset"`: a `Surface` transforma o header em `legend` nativa e preserva o título
|
|
91
|
+
como legenda semântica.
|
|
92
92
|
|
|
93
93
|
```tsx preview col md
|
|
94
|
-
<
|
|
94
|
+
<Surface
|
|
95
95
|
as="fieldset"
|
|
96
96
|
framed
|
|
97
|
-
frameVariant="legend"
|
|
98
97
|
title={
|
|
99
98
|
<span className="flex items-center gap-2">
|
|
100
99
|
<IconTile size="xs">
|
|
@@ -110,13 +109,13 @@ o acabamento compacto com a legenda integrada à borda, declare `frameVariant="l
|
|
|
110
109
|
<Input id="vehicle-plate" defaultValue="GBR1A03" />
|
|
111
110
|
</Field>
|
|
112
111
|
</FieldGroup>
|
|
113
|
-
</
|
|
112
|
+
</Surface>
|
|
114
113
|
```
|
|
115
114
|
|
|
116
115
|
## Compatibilidade de FieldSet
|
|
117
116
|
|
|
118
117
|
`FieldSet` e `FieldLegend` continuam disponíveis para composições existentes. Em código novo,
|
|
119
|
-
prefira `
|
|
118
|
+
prefira `Surface as="fieldset"`: ele reúne legenda, corpo e moldura na mesma anatomia usada pelas
|
|
120
119
|
demais regiões nomeadas. A migração pode ser gradual porque os controles e o `FieldGroup` não mudam.
|
|
121
120
|
|
|
122
121
|
## Propriedades de FieldSet
|
|
@@ -127,11 +126,11 @@ demais regiões nomeadas. A migração pode ser gradual porque os controles e o
|
|
|
127
126
|
|
|
128
127
|
## Propriedades de Field
|
|
129
128
|
|
|
130
|
-
| Propriedade
|
|
131
|
-
|
|
|
132
|
-
| `orientation`
|
|
133
|
-
| `data-invalid`
|
|
134
|
-
| `data-disabled` | `'true' \| 'false'`
|
|
129
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
130
|
+
| --------------- | -------------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------- |
|
|
131
|
+
| `orientation` | `'vertical' \| 'horizontal' \| 'responsive'` | `'vertical'` | Direção fixa do campo. `responsive` permanece como alias compatível de `horizontal`. |
|
|
132
|
+
| `data-invalid` | `boolean \| 'true' \| 'false'` | | Com `true`, aplica o contexto de erro ao campo e ao rótulo. O `ActionForm` define o atributo sozinho. |
|
|
133
|
+
| `data-disabled` | `'true' \| 'false'` | | Com `true`, esmaece `FieldLabel` e `FieldTitle`. Declare `disabled` também no controle. |
|
|
135
134
|
|
|
136
135
|
## Propriedades de FieldLegend
|
|
137
136
|
|
|
@@ -18,19 +18,20 @@ uma classe `size-*` preserva a própria medida.
|
|
|
18
18
|
Slots genéricos de ícone, como `FieldLegend.icon`, não criam a moldura: passe o glifo quando quiser
|
|
19
19
|
só o ícone e componha `IconTile` quando a moldura reforçar a hierarquia.
|
|
20
20
|
|
|
21
|
-
Os slots de mídia
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
`media` é adotado pelo slot, que herda o que ele declara, em vez de desenhar uma moldura dentro da
|
|
25
|
-
outra.
|
|
21
|
+
Os slots de mídia estruturais não criam decoração. `SurfaceMedia`, `DialogMedia` e `DrawerMedia`
|
|
22
|
+
reservam posição e alinhamento, mas preservam o nó recebido. Passe o glifo diretamente
|
|
23
|
+
quando ele deve ficar solto; componha `IconTile` de forma explícita quando quiser moldura.
|
|
26
24
|
|
|
27
25
|
```tsx preview col md
|
|
28
|
-
<
|
|
26
|
+
<Surface
|
|
29
27
|
as="fieldset"
|
|
30
28
|
framed
|
|
31
|
-
frameVariant="legend"
|
|
32
29
|
title="Veículo"
|
|
33
|
-
media={
|
|
30
|
+
media={
|
|
31
|
+
<IconTile size="xs">
|
|
32
|
+
<CarFront aria-hidden="true" />
|
|
33
|
+
</IconTile>
|
|
34
|
+
}
|
|
34
35
|
>
|
|
35
36
|
<FieldGroup>
|
|
36
37
|
<Field>
|
|
@@ -38,7 +39,7 @@ outra.
|
|
|
38
39
|
<Input id="icon-tile-plate" />
|
|
39
40
|
</Field>
|
|
40
41
|
</FieldGroup>
|
|
41
|
-
</
|
|
42
|
+
</Surface>
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
## Propriedades de IconTile
|
|
@@ -59,10 +60,10 @@ não é renderizado pelo `IconTile`. Os padrões são os mesmos do componente: `
|
|
|
59
60
|
|
|
60
61
|
```ts
|
|
61
62
|
function iconTileVariants(options?: {
|
|
62
|
-
context?: IconTileContext | null
|
|
63
|
-
variant?: IconTileVariant | null
|
|
64
|
-
size?: IconTileSize | null
|
|
65
|
-
}): string
|
|
63
|
+
context?: IconTileContext | null;
|
|
64
|
+
variant?: IconTileVariant | null;
|
|
65
|
+
size?: IconTileSize | null;
|
|
66
|
+
}): string;
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
`resolveIconTileStyle` continua exportado, mas está depreciado e sai em uma próxima versão maior. Ele
|
|
@@ -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
|
|
10
|
-
deixe um `PageState` ativo assumir esse papel. O
|
|
11
|
-
nomeia a página. Contadores e outros indicadores pertencem ao conteúdo que os explica.
|
|
9
|
+
exige exatamente um heading principal. Use `PageTitle` no cabeçalho, `Surface level={1}` no body,
|
|
10
|
+
ou deixe um `PageState` ativo assumir esse papel. O cabeçalho pode ser omitido quando o próprio
|
|
11
|
+
conteúdo nomeia a página. Contadores e outros indicadores pertencem ao conteúdo que os explica.
|
|
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
|
-
[`
|
|
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
|
|
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
|
|
@@ -109,7 +109,7 @@ navegação e as ações do shell no `PageHeader` rolável da página ativa.
|
|
|
109
109
|
Durante `PageState`, o cabeçalho inteiro desaparece e o título do estado assume o heading principal.
|
|
110
110
|
Se uma ação não puder ser executada sem o conteúdo, a própria rota deve omiti-la naquele estado.
|
|
111
111
|
|
|
112
|
-
Na composição explícita, combine navegação, título e ações no mesmo
|
|
112
|
+
Na composição explícita, combine navegação, título e ações no mesmo cabeçalho:
|
|
113
113
|
|
|
114
114
|
```tsx preview col
|
|
115
115
|
<PageShell
|
|
@@ -137,7 +137,7 @@ Na composição explícita, combine navegação, título e ações no mesmo head
|
|
|
137
137
|
|
|
138
138
|
## Composição explícita
|
|
139
139
|
|
|
140
|
-
Use os slots quando a página precisar compor o
|
|
140
|
+
Use os slots quando a página precisar compor o cabeçalho diretamente. Não misture propriedades da
|
|
141
141
|
forma curta com `PageHeader` ou `PageBody`.
|
|
142
142
|
|
|
143
143
|
```tsx preview col
|
|
@@ -158,9 +158,11 @@ render(
|
|
|
158
158
|
);
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
Em uma página de listagem, [`
|
|
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 `
|
|
163
|
+
materializa somente o `PageHeader` necessário para recebê-las, sem duplicar o heading de `Surface`.
|
|
164
|
+
[Composições](/ui/compositions) compara essa forma, com o título no corpo, à forma compacta, com o
|
|
165
|
+
título no cabeçalho.
|
|
164
166
|
|
|
165
167
|
## Ações de etapa no rodapé
|
|
166
168
|
|
|
@@ -197,20 +199,25 @@ render(
|
|
|
197
199
|
<PageHeader>
|
|
198
200
|
<PageTitle>Ordens de serviço</PageTitle>
|
|
199
201
|
</PageHeader>
|
|
200
|
-
<PageBody className="min-h-0 flex-1
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
202
|
+
<PageBody className="min-h-0 flex-1 overflow-y-auto">
|
|
203
|
+
<div className="space-y-2">
|
|
204
|
+
{[
|
|
205
|
+
"OS-1842",
|
|
206
|
+
"OS-1839",
|
|
207
|
+
"OS-1835",
|
|
208
|
+
"OS-1830",
|
|
209
|
+
"OS-1827",
|
|
210
|
+
"OS-1821",
|
|
211
|
+
"OS-1818",
|
|
212
|
+
].map((id) => (
|
|
213
|
+
<div
|
|
214
|
+
key={id}
|
|
215
|
+
className="rounded-md border border-border p-3 text-sm"
|
|
216
|
+
>
|
|
217
|
+
{id}
|
|
218
|
+
</div>
|
|
219
|
+
))}
|
|
220
|
+
</div>
|
|
214
221
|
</PageBody>
|
|
215
222
|
</Page>
|
|
216
223
|
</div>,
|
|
@@ -218,8 +225,8 @@ render(
|
|
|
218
225
|
```
|
|
219
226
|
|
|
220
227
|
Uma [`ActionList`](/ui/action-list) não precisa dessas classes. Filha de `PageBody`, ou de um
|
|
221
|
-
[`
|
|
222
|
-
sozinha: `PageBody`, `
|
|
228
|
+
[`Surface`](/ui/surface) dentro dele, ela recebe a altura da página e assume `layout="fill"`
|
|
229
|
+
sozinha: `PageBody`, `Surface` e `SurfaceBody` passam a repassar a altura até ela, o cabeçalho da
|
|
223
230
|
tabela fica fixo e só os resultados rolam. As demais seções do `PageBody` mantêm a altura do
|
|
224
231
|
próprio conteúdo, e uma página `fill` sem lista não muda.
|
|
225
232
|
|
|
@@ -373,21 +380,24 @@ estado na própria seção com [`DataState`](/ui/data-state), [`ActionView`](/ui
|
|
|
373
380
|
|
|
374
381
|
## Propriedades de PageBody
|
|
375
382
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
|
380
|
-
|
|
|
383
|
+
`PageBody` separa seus blocos diretos por `1.5rem`; o inset da página continua pertencendo a
|
|
384
|
+
`Page`. Uma grade, lista compacta ou linha horizontal fica dentro de um wrapper próprio.
|
|
385
|
+
|
|
386
|
+
| Propriedade | Tipo | Descrição |
|
|
387
|
+
| ----------- | ----------------------------- | --------------------------------------------------------- |
|
|
388
|
+
| `children` | `ReactNode` | Blocos principais, separados pelo ritmo estrutural. |
|
|
389
|
+
| `className` | `string` | Classes de ocupação, overflow, alinhamento ou tipografia. |
|
|
390
|
+
| demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
|
|
381
391
|
|
|
382
392
|
Em uma `Page` com `layout="fill"`, o `PageBody` vira coluna flexível sozinho quando contém uma `ActionList` que
|
|
383
393
|
ocupa a altura.
|
|
384
394
|
|
|
385
395
|
## Propriedades de PageActionsTarget
|
|
386
396
|
|
|
387
|
-
| Propriedade | Tipo | Descrição
|
|
388
|
-
| ----------- | --------------------- |
|
|
389
|
-
| `target` | `HTMLElement \| null` | Destino externo das ações; `null` mantém as ações no
|
|
390
|
-
| `children` | `ReactNode` | Árvore de página que poderá declarar `PageActions`.
|
|
397
|
+
| Propriedade | Tipo | Descrição |
|
|
398
|
+
| ----------- | --------------------- | --------------------------------------------------------------- |
|
|
399
|
+
| `target` | `HTMLElement \| null` | Destino externo das ações; `null` mantém as ações no cabeçalho. |
|
|
400
|
+
| `children` | `ReactNode` | Árvore de página que poderá declarar `PageActions`. |
|
|
391
401
|
|
|
392
402
|
## Propriedades de PageState
|
|
393
403
|
|
|
@@ -1,320 +1,72 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Uma unidade de layout do Split
|
|
2
2
|
|
|
3
|
-
Use `Pane` para
|
|
4
|
-
|
|
5
|
-
|
|
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"
|
|
14
|
-
<
|
|
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
|
-
<
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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. [Composições](/ui/compositions) mostra um pane com
|
|
31
|
+
`Surface` completa, com cabeçalho, corpo rolável e rodapé.
|
|
73
32
|
|
|
74
|
-
|
|
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.
|
|
33
|
+
## Redimensionamento
|
|
79
34
|
|
|
80
|
-
|
|
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.
|
|
35
|
+
Em um `Split` redimensionável, use `id` estável em cada pane. Números representam porcentagens;
|
|
36
|
+
strings preservam unidades explícitas.
|
|
86
37
|
|
|
87
38
|
```tsx preview
|
|
88
39
|
render(
|
|
89
40
|
<div className="h-56 overflow-hidden rounded-lg border border-border">
|
|
90
|
-
<Split>
|
|
91
|
-
<Pane initialSize="18rem">
|
|
92
|
-
<
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
41
|
+
<Split id="workspace" resizable>
|
|
42
|
+
<Pane id="navigation" initialSize="18rem" minSize="14rem" maxSize="28rem">
|
|
43
|
+
<Sidebar className="w-full">
|
|
44
|
+
<SidebarNav
|
|
45
|
+
navLabel="Projeto"
|
|
46
|
+
activeId="overview"
|
|
47
|
+
groups={[{ items: [{ id: "overview", label: "Visão geral" }] }]}
|
|
97
48
|
/>
|
|
98
|
-
|
|
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>
|
|
49
|
+
</Sidebar>
|
|
110
50
|
</Pane>
|
|
111
|
-
<Pane grow>
|
|
112
|
-
<
|
|
51
|
+
<Pane id="content" grow minSize="20rem">
|
|
52
|
+
<main className="h-full overflow-y-auto p-6">Conteúdo principal.</main>
|
|
113
53
|
</Pane>
|
|
114
54
|
</Split>
|
|
115
55
|
</div>,
|
|
116
56
|
);
|
|
117
57
|
```
|
|
118
58
|
|
|
119
|
-
|
|
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`.
|
|
59
|
+
## Propriedades
|
|
314
60
|
|
|
315
|
-
|
|
61
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
62
|
+
| ------------- | -------------------------------------------------- | ------- | ------------------------------------------------------------------------ |
|
|
63
|
+
| `id` | `string` | | Identidade estável dentro do grupo, necessária para persistir o layout. |
|
|
64
|
+
| `initialSize` | `number \| \`${number}%\` \| rem, em, vh, vw ou px | | Tamanho inicial. Números representam porcentagens. |
|
|
65
|
+
| `minSize` | mesmo tipo de `initialSize` | | Limite mínimo durante o redimensionamento. |
|
|
66
|
+
| `maxSize` | mesmo tipo de `initialSize` | | Limite máximo durante o redimensionamento. |
|
|
67
|
+
| `grow` | `boolean` | `false` | Faz a região ocupar o espaço remanescente no layout simples. |
|
|
68
|
+
| `className` | `string` | | Ajustes de layout da unidade, sem substituir a superfície do conteúdo. |
|
|
69
|
+
| `children` | `ReactNode` | | Estrutura responsável pela apresentação e organização interna da região. |
|
|
316
70
|
|
|
317
|
-
|
|
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. |
|
|
71
|
+
`Pane` não possui slots. APIs antigas como `PaneHeader`, `PaneBody` e `PaneFooter` foram removidas;
|
|
72
|
+
use a anatomia de `Surface` quando essas regiões forem necessárias.
|