@softize/opus 18.5.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.
- package/CHANGELOG.md +82 -0
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +293 -0
- package/package.json +1 -1
- package/src/ui/components/patterns/content-header.tsx +1 -9
- package/src/ui/components/patterns/heading-level.ts +16 -0
- package/src/ui/components/patterns/list.tsx +34 -15
- package/src/ui/components/patterns/pane.tsx +294 -0
- package/src/ui/components/patterns/presentation.tsx +29 -17
- package/src/ui/components/patterns/sidebar.tsx +13 -72
- package/src/ui/components/patterns/split.tsx +8 -35
- package/src/ui/components/patterns/surface-anatomy.ts +219 -0
- package/src/ui/components/patterns/surface-header.tsx +51 -6
- package/src/ui/components/patterns/surface-media.tsx +69 -0
- package/src/ui/components/primitives/card.tsx +91 -29
- package/src/ui/components/primitives/command.tsx +12 -4
- package/src/ui/components/primitives/detail.tsx +10 -13
- package/src/ui/components/primitives/dialog.tsx +138 -35
- package/src/ui/components/primitives/drawer.tsx +122 -23
- package/src/ui/components/primitives/metric-card.tsx +98 -39
- package/src/ui/docs/content/card.md +221 -30
- package/src/ui/docs/content/content.md +6 -0
- package/src/ui/docs/content/dialog.md +115 -7
- package/src/ui/docs/content/drawer.md +136 -9
- package/src/ui/docs/content/metric-card.md +57 -18
- package/src/ui/docs/content/page.md +8 -0
- package/src/ui/docs/content/pane.md +250 -0
- package/src/ui/docs/content/sidebar.md +22 -43
- package/src/ui/docs/content/skeleton.md +7 -3
- package/src/ui/docs/content/split.md +16 -21
- package/src/ui/docs/registry.tsx +8 -2
- package/src/ui/meta.ts +8 -2
- package/src/ui/react.tsx +14 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
## Painel lateral de detalhe
|
|
2
2
|
|
|
3
3
|
Use `Drawer` para abrir detalhes ou edição junto a uma borda, preservando a referência visual da
|
|
4
|
-
tela ao fundo. Para conteúdo curto e centralizado, prefira `Dialog
|
|
5
|
-
entra pela direita e pode ser fechado por Esc, pelo overlay ou pelo botão
|
|
4
|
+
tela ao fundo. Para conteúdo curto e centralizado, prefira [`Dialog`](/ui/dialog). Com
|
|
5
|
+
`side="right"`, o painel entra pela direita e pode ser fechado por Esc, pelo overlay ou pelo botão
|
|
6
|
+
de fechamento.
|
|
6
7
|
|
|
7
8
|
```tsx preview
|
|
8
9
|
<Drawer>
|
|
@@ -23,11 +24,10 @@ entra pela direita e pode ser fechado por Esc, pelo overlay ou pelo botão de fe
|
|
|
23
24
|
|
|
24
25
|
## Edição com ações persistentes
|
|
25
26
|
|
|
26
|
-
`side` aceita `top`, `right`, `bottom` e `left`. `DrawerFooter` mantém as ações no
|
|
27
|
-
`DrawerClose` fecha o painel sem exigir controle manual de estado.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
e sutil; `closeSize` escolhe entre `xs` e `sm`, com `sm` como padrão.
|
|
27
|
+
`side` aceita `top`, `right`, `bottom` e `left`. `DrawerFooter` mantém as ações no rodapé e
|
|
28
|
+
`DrawerClose` fecha o painel sem exigir controle manual de estado. O corpo preserva o mesmo
|
|
29
|
+
alinhamento horizontal do cabeçalho e do rodapé. O fechamento do cabeçalho usa uma ação circular
|
|
30
|
+
neutra e sutil; `closeSize` escolhe entre `xs` e `sm`, com `sm` como padrão.
|
|
31
31
|
|
|
32
32
|
```tsx preview
|
|
33
33
|
<Drawer>
|
|
@@ -54,6 +54,86 @@ e sutil; `closeSize` escolhe entre `xs` e `sm`, com `sm` como padrão.
|
|
|
54
54
|
</Drawer>
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
O rodapé usa a mesma faixa sutil do [`Dialog`](/ui/dialog). As duas famílias compartilham a
|
|
58
|
+
anatomia, então um fluxo que começa em um modal e continua em um painel não muda de aparência no
|
|
59
|
+
meio.
|
|
60
|
+
|
|
61
|
+
## Regiões separadas ou contínuas
|
|
62
|
+
|
|
63
|
+
`layout` declara a anatomia da superfície inteira e fica em `DrawerContent`; os slots leem esse
|
|
64
|
+
valor e não o recebem. O padrão é `sectioned`: recuo igual nas três regiões, faixa no rodapé e
|
|
65
|
+
divisor entre as regiões vizinhas. É o painel de trabalho, em que o corpo rola sob um cabeçalho e um
|
|
66
|
+
rodapé fixos.
|
|
67
|
+
|
|
68
|
+
Use `layout="continuous"` quando o painel apresentar um único bloco de leitura e a linha virar
|
|
69
|
+
ruído.
|
|
70
|
+
|
|
71
|
+
```tsx preview
|
|
72
|
+
<Drawer>
|
|
73
|
+
<DrawerTrigger asChild>
|
|
74
|
+
<Button variant="outline">Ver resumo</Button>
|
|
75
|
+
</DrawerTrigger>
|
|
76
|
+
<DrawerContent layout="continuous">
|
|
77
|
+
<DrawerHeader>
|
|
78
|
+
<DrawerTitle>Resumo da execução</DrawerTitle>
|
|
79
|
+
</DrawerHeader>
|
|
80
|
+
<DrawerBody>
|
|
81
|
+
<p className="text-sm text-muted-foreground">
|
|
82
|
+
Concluída em 2 minutos, sem falhas registradas.
|
|
83
|
+
</p>
|
|
84
|
+
</DrawerBody>
|
|
85
|
+
</DrawerContent>
|
|
86
|
+
</Drawer>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Os divisores do modo seccionado são derivados da vizinhança: cada região desenha a linha quando há
|
|
90
|
+
uma região do outro lado. Um cabeçalho sem corpo não fecha nada, e um cabeçalho seguido direto de um
|
|
91
|
+
rodapé produz uma linha só. A tela não escreve `border-b` nem `border-t`.
|
|
92
|
+
|
|
93
|
+
## Mídia, ações e navegação no cabeçalho
|
|
94
|
+
|
|
95
|
+
O cabeçalho reconhece quatro slots — `DrawerNavigation`, `DrawerMedia`, `DrawerTitle` e
|
|
96
|
+
`DrawerActions` — e posiciona cada um: a navegação abre a linha, a mídia vem antes do título, o
|
|
97
|
+
título ocupa a folga, as ações vão para o extremo oposto e o botão de fechar entra depois delas. Um
|
|
98
|
+
nó que não seja um desses slots interrompe a renderização com um erro; contexto e conteúdo
|
|
99
|
+
pertencem ao `DrawerBody`.
|
|
100
|
+
|
|
101
|
+
`DrawerMedia` é a moldura de ícone da casa — o mesmo [`IconTile`](/ui/icon-tile) —, útil para
|
|
102
|
+
identificar o tipo do recurso aberto. `DrawerNavigation` carrega o retorno de um fluxo encadeado,
|
|
103
|
+
em que o painel permanece aberto e troca de etapa.
|
|
104
|
+
|
|
105
|
+
```tsx preview
|
|
106
|
+
<Drawer>
|
|
107
|
+
<DrawerTrigger asChild>
|
|
108
|
+
<Button variant="outline">Abrir veículo</Button>
|
|
109
|
+
</DrawerTrigger>
|
|
110
|
+
<DrawerContent side="right">
|
|
111
|
+
<DrawerHeader>
|
|
112
|
+
<DrawerNavigation>
|
|
113
|
+
<Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
|
|
114
|
+
<ArrowLeft />
|
|
115
|
+
</Button>
|
|
116
|
+
</DrawerNavigation>
|
|
117
|
+
<DrawerMedia context="primary">
|
|
118
|
+
<CarFront />
|
|
119
|
+
</DrawerMedia>
|
|
120
|
+
<DrawerTitle>ABC-1D23</DrawerTitle>
|
|
121
|
+
<DrawerActions>
|
|
122
|
+
<Button variant="ghost" size="icon-sm" aria-label="Mais ações">
|
|
123
|
+
<Ellipsis />
|
|
124
|
+
</Button>
|
|
125
|
+
</DrawerActions>
|
|
126
|
+
</DrawerHeader>
|
|
127
|
+
<DrawerBody>
|
|
128
|
+
<p className="text-sm text-muted-foreground">Histórico de passagens na oficina.</p>
|
|
129
|
+
</DrawerBody>
|
|
130
|
+
</DrawerContent>
|
|
131
|
+
</Drawer>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
O cabeçalho não recebe descrição: o painel já nomeia o recurso, e o contexto que ajuda a decidir
|
|
135
|
+
aparece no começo do corpo, como texto ou `Alert`.
|
|
136
|
+
|
|
57
137
|
## Propriedades de Drawer
|
|
58
138
|
|
|
59
139
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
@@ -66,12 +146,59 @@ e sutil; `closeSize` escolhe entre `xs` e `sm`, com `sm` como padrão.
|
|
|
66
146
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
67
147
|
| ----------------- | ---------------------------------------- | --------- | ------------------------------------------------------------------------------------------ |
|
|
68
148
|
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Borda de onde o painel aparece. |
|
|
69
|
-
| `
|
|
149
|
+
| `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
|
|
150
|
+
| `showCloseButton` | `boolean` | `true` | Inclui a ação de fechamento no cabeçalho. Desative quando o painel exigir uma ação explícita. |
|
|
70
151
|
| `closeDisabled` | `boolean` | `false` | Mantém a ação visível e impede fechar enquanto o painel está bloqueado. |
|
|
71
|
-
| `closeSize` | `"xs" \| "sm"`
|
|
152
|
+
| `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
|
|
153
|
+
|
|
154
|
+
## Propriedades de DrawerHeader
|
|
155
|
+
|
|
156
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
157
|
+
| ----------- | ----------- | ------ | ------------------------------------------------------------------------------------------ |
|
|
158
|
+
| `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
|
|
159
|
+
| `children` | `ReactNode` | | Somente `DrawerNavigation`, `DrawerMedia`, `DrawerTitle` e `DrawerActions`, no máximo um de cada; o fechamento padrão entra depois deles. |
|
|
160
|
+
|
|
161
|
+
## Propriedades de DrawerMedia
|
|
162
|
+
|
|
163
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
164
|
+
| ----------- | ------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------- |
|
|
165
|
+
| `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'sm'` | Tamanho da moldura e do glifo na escala compartilhada. |
|
|
166
|
+
| `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
|
|
167
|
+
| `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
|
|
168
|
+
| `className` | `string` | | Ajusta a moldura sem substituir a escala. |
|
|
169
|
+
| `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. |
|
|
170
|
+
|
|
171
|
+
## Propriedades de DrawerNavigation
|
|
172
|
+
|
|
173
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
174
|
+
| ----------- | ----------- | ------ | ----------------------------------------------------- |
|
|
175
|
+
| `className` | `string` | | Ajusta a região introdutória da linha. |
|
|
176
|
+
| `children` | `ReactNode` | | Retorno de um fluxo encadeado, antes do título. |
|
|
177
|
+
|
|
178
|
+
## Propriedades de DrawerActions
|
|
179
|
+
|
|
180
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
181
|
+
| ----------- | ----------- | ------ | -------------------------------------------------------- |
|
|
182
|
+
| `className` | `string` | | Ajusta o agrupamento das ações. |
|
|
183
|
+
| `children` | `ReactNode` | | Ações da tela no cabeçalho, antes do botão de fechar. |
|
|
184
|
+
|
|
185
|
+
## Propriedades de DrawerTitle
|
|
186
|
+
|
|
187
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
188
|
+
| ----------- | ----------- | ------ | ------------------------------------------------------------------- |
|
|
189
|
+
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
|
|
190
|
+
| `className` | `string` | | Ajusta o título, que trunca quando não cabe na linha. |
|
|
191
|
+
| `children` | `ReactNode` | | Nome do recurso ou da tarefa; nomeia a superfície para leitores de tela. |
|
|
72
192
|
|
|
73
193
|
## Propriedades de DrawerBody
|
|
74
194
|
|
|
75
195
|
`DrawerBody` aceita os atributos de `HTMLDivElement` e ocupa a região flexível e rolável entre
|
|
76
196
|
`DrawerHeader` e `DrawerFooter`. O cabeçalho nomeia o painel; contexto relevante entra no começo
|
|
77
197
|
do corpo como texto ou `Alert`.
|
|
198
|
+
|
|
199
|
+
## Propriedades de DrawerFooter
|
|
200
|
+
|
|
201
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
202
|
+
| ----------- | ----------- | ------ | ---------------------------------------------------------------------- |
|
|
203
|
+
| `className` | `string` | | Ajusta a faixa do rodapé, inclusive a distribuição das ações. |
|
|
204
|
+
| `children` | `ReactNode` | | Ações persistentes, normalmente dentro de um `ButtonGroup`. |
|
|
@@ -45,7 +45,9 @@ apresente dois cards independentes.
|
|
|
45
45
|
labelAction={
|
|
46
46
|
<Tooltip>
|
|
47
47
|
<TooltipTrigger asChild>
|
|
48
|
-
<Button size="icon-xs" variant="ghost" aria-label="Sobre Agendados"
|
|
48
|
+
<Button size="icon-xs" variant="ghost" aria-label="Sobre Agendados">
|
|
49
|
+
<Info />
|
|
50
|
+
</Button>
|
|
49
51
|
</TooltipTrigger>
|
|
50
52
|
<TooltipContent>Eventos atualmente agendados.</TooltipContent>
|
|
51
53
|
</Tooltip>
|
|
@@ -56,7 +58,9 @@ apresente dois cards independentes.
|
|
|
56
58
|
labelAction: (
|
|
57
59
|
<Tooltip>
|
|
58
60
|
<TooltipTrigger asChild>
|
|
59
|
-
<Button size="icon-xs" variant="ghost" aria-label="Sobre o período"
|
|
61
|
+
<Button size="icon-xs" variant="ghost" aria-label="Sobre o período">
|
|
62
|
+
<Info />
|
|
63
|
+
</Button>
|
|
60
64
|
</TooltipTrigger>
|
|
61
65
|
<TooltipContent>Agendamentos registrados dentro do período.</TooltipContent>
|
|
62
66
|
</Tooltip>
|
|
@@ -65,6 +69,38 @@ apresente dois cards independentes.
|
|
|
65
69
|
/>
|
|
66
70
|
```
|
|
67
71
|
|
|
72
|
+
## Como filtro ou seleção
|
|
73
|
+
|
|
74
|
+
Use a ativação controlada quando escolher uma métrica também precisar aplicar um recorte. O card
|
|
75
|
+
expõe o estado por `aria-pressed` e preserva controles complementares, como o tooltip do rótulo,
|
|
76
|
+
sem disparar a ativação.
|
|
77
|
+
|
|
78
|
+
```tsx preview col
|
|
79
|
+
const [metric, setMetric] = useState('scheduled')
|
|
80
|
+
|
|
81
|
+
render(
|
|
82
|
+
<div className="grid grid-cols-2 gap-3">
|
|
83
|
+
<MetricCard
|
|
84
|
+
label="Agendados"
|
|
85
|
+
value="18"
|
|
86
|
+
active={metric === 'scheduled'}
|
|
87
|
+
activationLabel="Filtrar por Agendados"
|
|
88
|
+
onActivate={() => setMetric('scheduled')}
|
|
89
|
+
/>
|
|
90
|
+
<MetricCard
|
|
91
|
+
label="Efetivados"
|
|
92
|
+
value="11"
|
|
93
|
+
active={metric === 'completed'}
|
|
94
|
+
activationLabel="Filtrar por Efetivados"
|
|
95
|
+
onActivate={() => setMetric('completed')}
|
|
96
|
+
/>
|
|
97
|
+
</div>,
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`active`, `activationLabel` e `onActivate` formam uma capacidade única: informe as três propriedades
|
|
102
|
+
para tornar o card ativável. O consumidor continua responsável pelo estado e pelo recorte aplicado.
|
|
103
|
+
|
|
68
104
|
## Carregamento
|
|
69
105
|
|
|
70
106
|
`loading` preserva a geometria do card com placeholders e marca a superfície como ocupada para
|
|
@@ -76,22 +112,25 @@ tecnologias assistivas. O contêiner da coleção continua responsável pela men
|
|
|
76
112
|
|
|
77
113
|
## Propriedades de MetricCard
|
|
78
114
|
|
|
79
|
-
| Propriedade
|
|
80
|
-
|
|
81
|
-
| `label`
|
|
82
|
-
| `value`
|
|
83
|
-
| `loading`
|
|
84
|
-
| `labelAction`
|
|
85
|
-
| `description`
|
|
86
|
-
| `secondaryMetric` | `MetricCardSecondaryMetric`
|
|
87
|
-
| `icon`
|
|
88
|
-
| `context`
|
|
89
|
-
| `action`
|
|
115
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
116
|
+
| ----------------- | ----------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| `label` | `ReactNode` | | O nome da medida. |
|
|
118
|
+
| `value` | `ReactNode` | | O valor já formatado pelo consumidor. |
|
|
119
|
+
| `loading` | `boolean` | `false` | Substitui rótulo e valor por skeletons e marca `aria-busy`. |
|
|
120
|
+
| `labelAction` | `ReactNode` | | Controle ao lado do rótulo, como uma explicação em tooltip. |
|
|
121
|
+
| `description` | `ReactNode` | | Contexto que explica recorte, proporção ou significado do valor. |
|
|
122
|
+
| `secondaryMetric` | `MetricCardSecondaryMetric` | | Medida complementar exibida como uma lâmina posterior sob o card principal. |
|
|
123
|
+
| `icon` | `ReactNode` | | Ícone decorativo que identifica a natureza da medida. |
|
|
124
|
+
| `context` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Contexto semântico do ícone; não altera a superfície do card. |
|
|
125
|
+
| `action` | `ReactNode` | | Ação relacionada diretamente à medida. |
|
|
126
|
+
| `active` | `boolean` | | Indica se a medida controla o recorte atualmente aplicado. Exige `activationLabel` e `onActivate`. |
|
|
127
|
+
| `activationLabel` | `string` | | Nome acessível da ativação. Exige `active` e `onActivate`. |
|
|
128
|
+
| `onActivate` | `() => void` | | Ativa a medida como recorte ou seleção. Exige `active` e `activationLabel`. |
|
|
90
129
|
|
|
91
130
|
## Propriedades de MetricCardSecondaryMetric
|
|
92
131
|
|
|
93
|
-
| Propriedade
|
|
94
|
-
|
|
95
|
-
| `label`
|
|
96
|
-
| `value`
|
|
97
|
-
| `labelAction` | `ReactNode` |
|
|
132
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
133
|
+
| ------------- | ----------- | ------ | ------------------------------------------------------------------- |
|
|
134
|
+
| `label` | `ReactNode` | | O nome da medida complementar. |
|
|
135
|
+
| `value` | `ReactNode` | | O valor complementar já formatado pelo consumidor. |
|
|
136
|
+
| `labelAction` | `ReactNode` | | Controle próprio ao lado do rótulo, como uma explicação em tooltip. |
|
|
@@ -17,6 +17,13 @@ introdução podem ser omitidos quando o próprio conteúdo nomeia a página.
|
|
|
17
17
|
Contadores e outros indicadores pertencem ao
|
|
18
18
|
conteúdo que os explica.
|
|
19
19
|
|
|
20
|
+
A `Page` é contínua por definição: separar o chrome do conteúdo é trabalho do shell, e não há
|
|
21
|
+
divisores entre regiões para declarar. O `layout` da `Page` não é a anatomia de superfície de
|
|
22
|
+
[`Card`](/ui/card), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) e [`Pane`](/ui/pane) — aqui ele
|
|
23
|
+
decide a ocupação de altura. `flow`, o padrão, deixa a página crescer e a rolagem acontecer na
|
|
24
|
+
janela; `fill` limita a página à altura do shell para que uma região interna, como uma tabela longa
|
|
25
|
+
ou um split, assuma a rolagem.
|
|
26
|
+
|
|
20
27
|
`PageShell` não inclui sidebar nem inventa breadcrumb. Ele ocupa o painel principal já delimitado e
|
|
21
28
|
mantém a barra com `3.75rem`, mesmo quando o conteúdo muda de estado. Tabs ficam reservados a recortes
|
|
22
29
|
da mesma superfície. Canvas e outros workspaces espaciais imersivos podem usar um shell próprio.
|
|
@@ -196,6 +203,7 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
|
|
|
196
203
|
| ----------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------- |
|
|
197
204
|
| `title` | `ReactNode` | | O h1 da página. |
|
|
198
205
|
| `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho. |
|
|
206
|
+
| `layout` | `'flow' \| 'fill'` | `'flow'` | Ocupação de altura, não anatomia: `fill` limita a página ao shell para que uma região interna role. |
|
|
199
207
|
| `className` | `string` | `max-w-7xl` | Classes do container para substituir o teto padrão de `80rem`. |
|
|
200
208
|
| `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
|
|
201
209
|
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
## A coluna encaixada em um layout
|
|
2
|
+
|
|
3
|
+
Use `Pane` para a coluna ou faixa que ocupa uma das posições de um [`Split`](/ui/split): a
|
|
4
|
+
navegação à esquerda, o inspetor à direita, a lista que abre o detalhe ao lado. O `Split` decide a
|
|
5
|
+
relação espacial e o redimensionamento; o `Pane` decide o que existe dentro da área recebida.
|
|
6
|
+
|
|
7
|
+
No formato mais simples, o pane é uma caixa com recuo e o conteúdo é seu.
|
|
8
|
+
|
|
9
|
+
```tsx preview
|
|
10
|
+
render(
|
|
11
|
+
<div className="h-56 overflow-hidden rounded-lg border border-border">
|
|
12
|
+
<Split>
|
|
13
|
+
<Pane initialSize="16rem" className="bg-muted/30">
|
|
14
|
+
<p className="text-sm text-muted-foreground">Navegação.</p>
|
|
15
|
+
</Pane>
|
|
16
|
+
<Pane grow>
|
|
17
|
+
<p className="text-sm text-muted-foreground">Conteúdo.</p>
|
|
18
|
+
</Pane>
|
|
19
|
+
</Split>
|
|
20
|
+
</div>,
|
|
21
|
+
);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Cabeçalho, corpo e rodapé
|
|
25
|
+
|
|
26
|
+
Quando a área precisa de regiões fixas e de um corpo que rola, componha os slots. `PaneHeader`
|
|
27
|
+
nomeia a região, `PaneBody` ocupa o espaço restante e concentra a rolagem vertical, e `PaneFooter`
|
|
28
|
+
mantém à vista o que não pode sair da tela.
|
|
29
|
+
|
|
30
|
+
```tsx preview
|
|
31
|
+
render(
|
|
32
|
+
<div className="h-72 overflow-hidden rounded-lg border border-border">
|
|
33
|
+
<Split>
|
|
34
|
+
<Pane initialSize="18rem">
|
|
35
|
+
<PaneHeader>
|
|
36
|
+
<PaneMedia>
|
|
37
|
+
<MessagesSquare />
|
|
38
|
+
</PaneMedia>
|
|
39
|
+
<PaneTitle>Conversas</PaneTitle>
|
|
40
|
+
<PaneActions>
|
|
41
|
+
<Button variant="ghost" size="icon-sm" aria-label="Nova conversa">
|
|
42
|
+
<SquarePen />
|
|
43
|
+
</Button>
|
|
44
|
+
</PaneActions>
|
|
45
|
+
</PaneHeader>
|
|
46
|
+
<PaneBody className="space-y-1">
|
|
47
|
+
<p className="text-sm">Revisão do contrato</p>
|
|
48
|
+
<p className="text-sm text-muted-foreground">Importação de clientes</p>
|
|
49
|
+
<p className="text-sm text-muted-foreground">Fila de execuções</p>
|
|
50
|
+
</PaneBody>
|
|
51
|
+
<PaneFooter>
|
|
52
|
+
<Button variant="ghost" size="sm">Ver arquivadas</Button>
|
|
53
|
+
</PaneFooter>
|
|
54
|
+
</Pane>
|
|
55
|
+
<Pane grow>
|
|
56
|
+
<p className="text-sm text-muted-foreground">Conversa selecionada.</p>
|
|
57
|
+
</Pane>
|
|
58
|
+
</Split>
|
|
59
|
+
</div>,
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
O cabeçalho reconhece quatro slots — `PaneMedia`, `PaneTitle`, `PaneDescription` e `PaneActions` —
|
|
64
|
+
e monta a linha sozinho: mídia, título e descrição de um lado, ações no extremo oposto. A ordem em
|
|
65
|
+
que os slots são escritos não altera a posição, e um nó que não seja um desses slots interrompe a
|
|
66
|
+
renderização com um erro. Conteúdo livre vai para `PaneBody`.
|
|
67
|
+
|
|
68
|
+
Título e descrição truncam quando a coluna encolhe, em vez de quebrar a altura da faixa.
|
|
69
|
+
|
|
70
|
+
## Escolher entre seccionado e contínuo
|
|
71
|
+
|
|
72
|
+
`layout` declara a anatomia da superfície inteira e fica no root; os slots leem esse valor e não o
|
|
73
|
+
recebem. Cada valor é um pacote de recuo, ritmo vertical e divisores.
|
|
74
|
+
|
|
75
|
+
| Aspecto | `sectioned` (padrão) | `continuous` |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| Divisores | entre as regiões vizinhas | nenhum |
|
|
78
|
+
| Faixa do cabeçalho | altura fixa de `3.75rem` | acompanha o conteúdo |
|
|
79
|
+
| Ritmo vertical | regiões simétricas | o cabeçalho se aproxima do corpo |
|
|
80
|
+
|
|
81
|
+
O padrão `sectioned` é o pane de operação: a faixa do cabeçalho tem a mesma altura da barra do
|
|
82
|
+
[`PageShell`](/ui/page), então uma navegação lateral e o chrome da página se alinham na mesma
|
|
83
|
+
linha. Use `continuous` quando o pane for um bloco de leitura contínuo, sem fronteiras a marcar.
|
|
84
|
+
|
|
85
|
+
Os divisores são derivados da vizinhança: cada região desenha a linha quando há uma região do outro
|
|
86
|
+
lado. Um cabeçalho sem corpo não fecha nada, e um cabeçalho seguido direto de um rodapé produz uma
|
|
87
|
+
linha só. A tela não escreve `border-b` nem `border-t`.
|
|
88
|
+
|
|
89
|
+
## Recuo do pane e recuo das regiões
|
|
90
|
+
|
|
91
|
+
`inset` é o respiro interno do pane sem slots: `md` por padrão, com `none`, `sm` e `lg`
|
|
92
|
+
disponíveis. Quando `PaneHeader`, `PaneBody` ou `PaneFooter` são filhos **diretos** do pane, o recuo
|
|
93
|
+
passa a ser de cada região e o `inset` vira `none` sozinho — é o que permite ao divisor alcançar a
|
|
94
|
+
borda da coluna.
|
|
95
|
+
|
|
96
|
+
O ajuste enxerga só o primeiro nível. Se os slots vierem dentro de outro componente — é o caso da
|
|
97
|
+
`Sidebar`, que traz a superfície e o colapso —, o pane não sabe que eles existem: declare
|
|
98
|
+
`inset="none"` você mesmo, ou a coluna ganha um recuo que empurra o divisor para dentro.
|
|
99
|
+
|
|
100
|
+
## A matriz de layouts e slots
|
|
101
|
+
|
|
102
|
+
As regiões são independentes e o recuo se ajusta a cada combinação, nos dois layouts.
|
|
103
|
+
|
|
104
|
+
```tsx preview col
|
|
105
|
+
render(
|
|
106
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
107
|
+
<div className="h-56 overflow-hidden rounded-lg border border-border">
|
|
108
|
+
<Pane className="h-full">
|
|
109
|
+
<PaneHeader>
|
|
110
|
+
<PaneTitle>Seccionado</PaneTitle>
|
|
111
|
+
<PaneActions>
|
|
112
|
+
<Button variant="ghost" size="icon-sm" aria-label="Mais ações">
|
|
113
|
+
<Ellipsis />
|
|
114
|
+
</Button>
|
|
115
|
+
</PaneActions>
|
|
116
|
+
</PaneHeader>
|
|
117
|
+
<PaneBody>
|
|
118
|
+
<p className="text-sm text-muted-foreground">Cabeçalho, corpo e rodapé.</p>
|
|
119
|
+
</PaneBody>
|
|
120
|
+
<PaneFooter>
|
|
121
|
+
<Button variant="ghost" size="sm">Configurações</Button>
|
|
122
|
+
</PaneFooter>
|
|
123
|
+
</Pane>
|
|
124
|
+
</div>
|
|
125
|
+
<div className="h-56 overflow-hidden rounded-lg border border-border">
|
|
126
|
+
<Pane layout="continuous" className="h-full">
|
|
127
|
+
<PaneHeader>
|
|
128
|
+
<PaneMedia>
|
|
129
|
+
<ChartNoAxesColumn />
|
|
130
|
+
</PaneMedia>
|
|
131
|
+
<PaneTitle>Contínuo com mídia</PaneTitle>
|
|
132
|
+
<PaneDescription>O espaço separa as regiões.</PaneDescription>
|
|
133
|
+
</PaneHeader>
|
|
134
|
+
<PaneBody>
|
|
135
|
+
<p className="text-sm text-muted-foreground">Sem rodapé e sem divisores.</p>
|
|
136
|
+
</PaneBody>
|
|
137
|
+
</Pane>
|
|
138
|
+
</div>
|
|
139
|
+
<div className="h-56 overflow-hidden rounded-lg border border-border">
|
|
140
|
+
<Pane className="h-full">
|
|
141
|
+
<PaneBody>
|
|
142
|
+
<p className="text-sm text-muted-foreground">Só corpo: nenhuma fronteira a marcar.</p>
|
|
143
|
+
</PaneBody>
|
|
144
|
+
</Pane>
|
|
145
|
+
</div>
|
|
146
|
+
<div className="h-56 overflow-hidden rounded-lg border border-border">
|
|
147
|
+
<Pane className="h-full">
|
|
148
|
+
<PaneHeader>
|
|
149
|
+
<PaneMedia context="primary">
|
|
150
|
+
<Folder />
|
|
151
|
+
</PaneMedia>
|
|
152
|
+
<PaneTitle>Sem corpo</PaneTitle>
|
|
153
|
+
</PaneHeader>
|
|
154
|
+
<PaneFooter>
|
|
155
|
+
<Button variant="ghost" size="sm">Ação persistente</Button>
|
|
156
|
+
</PaneFooter>
|
|
157
|
+
</Pane>
|
|
158
|
+
</div>
|
|
159
|
+
</div>,
|
|
160
|
+
);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Onde termina o Pane
|
|
164
|
+
|
|
165
|
+
Três componentes dividem a responsabilidade de uma coluna, e trocá-los de papel é a origem mais
|
|
166
|
+
comum de layout duplicado:
|
|
167
|
+
|
|
168
|
+
| Componente | Responsabilidade |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| [`Split`](/ui/split) | Relação espacial entre as áreas e, com `resizable`, o arraste da fronteira. |
|
|
171
|
+
| `Pane` | Tamanho recebido, recuo e as regiões internas: cabeçalho, corpo e rodapé. |
|
|
172
|
+
| [`Sidebar`](/ui/sidebar) | Superfície da navegação lateral e o estado de colapso dos destinos. |
|
|
173
|
+
|
|
174
|
+
Tamanho inicial, limites e persistência do layout são declarados no `Pane` e operados pelo `Split`
|
|
175
|
+
— a [página do Split](/ui/split) trata deles. Uma `Sidebar` é composta dentro de um `Pane` e usa os
|
|
176
|
+
mesmos slots para o próprio cabeçalho e rodapé; ela não tem regiões próprias.
|
|
177
|
+
|
|
178
|
+
## Hierarquia do título
|
|
179
|
+
|
|
180
|
+
`PaneTitle` é um heading. `level` escolhe a hierarquia do documento, de `1` a `6`, com `2` como
|
|
181
|
+
padrão. O tamanho visual vem da família e do `layout`, não do nível, então corrigir a estrutura do
|
|
182
|
+
documento não muda a aparência da faixa.
|
|
183
|
+
|
|
184
|
+
## Propriedades de Pane
|
|
185
|
+
|
|
186
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
187
|
+
|---|---|---|---|
|
|
188
|
+
| `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
|
|
189
|
+
| `inset` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'`, ou `'none'` com slots diretos | Respiro interno do pane sem slots; slots dentro de outro componente exigem declarar. |
|
|
190
|
+
| `id` | `string` | | Identidade estável usada pelo layout redimensionável e persistido. |
|
|
191
|
+
| `initialSize` | `number \| string` | | Tamanho inicial; número é porcentagem, string aceita `%`, `rem`, `em`, `vh`, `vw` e `px`. |
|
|
192
|
+
| `minSize` / `maxSize` | `number \| string` | | Limites aplicados pelo `Split` quando ele é redimensionável. |
|
|
193
|
+
| `grow` | `boolean` | `false` | Ocupa o espaço remanescente no layout simples. |
|
|
194
|
+
| `className` | `string` | | Ajusta a coluna. |
|
|
195
|
+
| `children` | `ReactNode` | | Conteúdo direto ou os slots estruturais. |
|
|
196
|
+
|
|
197
|
+
## Propriedades de PaneHeader
|
|
198
|
+
|
|
199
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
200
|
+
|---|---|---|---|
|
|
201
|
+
| `children` | `ReactNode` | | Somente `PaneMedia`, `PaneTitle`, `PaneDescription` e `PaneActions`, no máximo um de cada. |
|
|
202
|
+
| `className` | `string` | | Ajusta a faixa fixa sobre o recuo do layout. |
|
|
203
|
+
|
|
204
|
+
## Propriedades de PaneMedia
|
|
205
|
+
|
|
206
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
207
|
+
|---|---|---|---|
|
|
208
|
+
| `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'xs'` | Tamanho da moldura e do glifo na escala compartilhada. |
|
|
209
|
+
| `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
|
|
210
|
+
| `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
|
|
211
|
+
| `className` | `string` | | Ajusta a moldura sem substituir a escala. |
|
|
212
|
+
| `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. |
|
|
213
|
+
|
|
214
|
+
## Propriedades de PaneTitle
|
|
215
|
+
|
|
216
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
217
|
+
|---|---|---|---|
|
|
218
|
+
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
|
|
219
|
+
| `className` | `string` | | Ajusta o título, que trunca quando não cabe. |
|
|
220
|
+
|
|
221
|
+
## Propriedades de PaneDescription
|
|
222
|
+
|
|
223
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
224
|
+
|---|---|---|---|
|
|
225
|
+
| `children` | `ReactNode` | | Frase curta de apoio sob o título; trunca quando não cabe. |
|
|
226
|
+
| `className` | `string` | | Ajusta a descrição. |
|
|
227
|
+
|
|
228
|
+
## Propriedades de PaneActions
|
|
229
|
+
|
|
230
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
231
|
+
|---|---|---|---|
|
|
232
|
+
| `children` | `ReactNode` | | Controles no extremo oposto ao título. |
|
|
233
|
+
| `className` | `string` | | Ajusta o agrupamento das ações. |
|
|
234
|
+
|
|
235
|
+
## Propriedades de PaneBody
|
|
236
|
+
|
|
237
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
238
|
+
|---|---|---|---|
|
|
239
|
+
| `children` | `ReactNode` | | Conteúdo que ocupa o espaço entre cabeçalho e rodapé. |
|
|
240
|
+
| `className` | `string` | | Ajusta a região flexível e rolável. |
|
|
241
|
+
|
|
242
|
+
`PaneContent` continua exportado como alias depreciado de `PaneBody` e sai em uma próxima versão
|
|
243
|
+
maior. Código novo usa `PaneBody`.
|
|
244
|
+
|
|
245
|
+
## Propriedades de PaneFooter
|
|
246
|
+
|
|
247
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
248
|
+
|---|---|---|---|
|
|
249
|
+
| `children` | `ReactNode` | | Navegação ou ações que precisam permanecer acessíveis no rodapé. |
|
|
250
|
+
| `className` | `string` | | Ajusta a faixa fixa sobre o recuo do layout. |
|