@softize/opus 18.4.0 → 19.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/docs/adr/0020-icon-tiles-are-explicitly-composed.md +46 -0
- package/docs/adr/0021-content-carries-structure-and-semantic-element.md +65 -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 +169 -50
- package/src/ui/components/patterns/heading-level.ts +16 -0
- package/src/ui/components/patterns/list.tsx +76 -27
- 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/empty.tsx +2 -1
- package/src/ui/components/primitives/field.tsx +38 -16
- package/src/ui/components/primitives/icon-tile.tsx +91 -0
- package/src/ui/components/primitives/item.tsx +2 -1
- package/src/ui/components/primitives/metric-card.tsx +98 -39
- package/src/ui/components/primitives/table.tsx +1 -1
- package/src/ui/docs/content/action-list.md +61 -52
- package/src/ui/docs/content/card.md +221 -30
- package/src/ui/docs/content/content.md +90 -8
- package/src/ui/docs/content/dialog.md +115 -7
- package/src/ui/docs/content/drawer.md +136 -9
- package/src/ui/docs/content/field.md +78 -30
- package/src/ui/docs/content/icon-tile.md +47 -0
- 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 +14 -2
- package/src/ui/meta.ts +17 -5
- package/src/ui/react.tsx +31 -0
|
@@ -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. |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
## Navegação dentro de um layout
|
|
2
2
|
|
|
3
3
|
Use `Sidebar` para apresentar navegação global ou contextual em uma coluna lateral. O componente
|
|
4
|
-
organiza a superfície e compartilha o estado de colapso; posição e largura pertencem a um
|
|
5
|
-
dentro de `Split
|
|
4
|
+
organiza a superfície e compartilha o estado de colapso; posição e largura pertencem a um
|
|
5
|
+
[`Pane`](/ui/pane) dentro de [`Split`](/ui/split).
|
|
6
6
|
|
|
7
7
|
O exemplo canônico mantém a largura inicial em `rem`, deixa a navegação rolar e preserva o
|
|
8
8
|
cabeçalho e o rodapé nas extremidades.
|
|
@@ -13,8 +13,8 @@ render(
|
|
|
13
13
|
<Split>
|
|
14
14
|
<Pane initialSize="16rem" inset="none">
|
|
15
15
|
<Sidebar className="w-full">
|
|
16
|
-
<PaneHeader
|
|
17
|
-
Projeto
|
|
16
|
+
<PaneHeader>
|
|
17
|
+
<PaneTitle>Projeto</PaneTitle>
|
|
18
18
|
</PaneHeader>
|
|
19
19
|
<PaneBody>
|
|
20
20
|
<SidebarNav
|
|
@@ -50,22 +50,17 @@ divisória ao lado do handle.
|
|
|
50
50
|
|
|
51
51
|
## Anatomia e responsabilidades
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
A `Sidebar` não tem regiões próprias: o cabeçalho, o corpo rolável e o rodapé são os slots do
|
|
54
|
+
`Pane` que a hospeda, com a anatomia e as propriedades descritas na
|
|
55
|
+
[página da família](/ui/pane).
|
|
55
56
|
|
|
56
57
|
| Parte | Responsabilidade |
|
|
57
58
|
|---|---|
|
|
58
|
-
| `Split` | Define a relação espacial e, opcionalmente, o redimensionamento. |
|
|
59
|
-
| `Pane` | Define largura
|
|
59
|
+
| [`Split`](/ui/split) | Define a relação espacial e, opcionalmente, o redimensionamento. |
|
|
60
|
+
| [`Pane`](/ui/pane) | Define largura e limites da coluna e estrutura suas regiões. |
|
|
60
61
|
| `Sidebar` | Desenha a superfície lateral e fornece o estado de colapso. |
|
|
61
|
-
| `PaneHeader` | Mantém identidade, contexto ou ações no topo. |
|
|
62
|
-
| `PaneBody` | Ocupa o espaço restante e concentra a rolagem vertical. |
|
|
63
|
-
| `PaneFooter` | Mantém ações persistentes no rodapé. |
|
|
64
62
|
| `SidebarNav` | Apresenta e controla os destinos de navegação. |
|
|
65
63
|
|
|
66
|
-
`PaneContent` continua exportado como alias depreciado de `PaneBody`. Código novo usa
|
|
67
|
-
`PaneBody`.
|
|
68
|
-
|
|
69
64
|
## Escolher a navegação
|
|
70
65
|
|
|
71
66
|
Use `SidebarNav` para grupos planos de destinos. Ele recebe dados e produz `SidebarItem` com a mesma
|
|
@@ -151,15 +146,17 @@ const [collapsed, setCollapsed] = useState(false)
|
|
|
151
146
|
render(
|
|
152
147
|
<div className="flex h-64 overflow-hidden rounded-lg border border-border">
|
|
153
148
|
<Sidebar collapsed={collapsed}>
|
|
154
|
-
<PaneHeader
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
149
|
+
<PaneHeader>
|
|
150
|
+
<PaneActions>
|
|
151
|
+
<Button
|
|
152
|
+
variant="ghost"
|
|
153
|
+
size="icon-sm"
|
|
154
|
+
aria-label={collapsed ? 'Expandir navegação' : 'Recolher navegação'}
|
|
155
|
+
onClick={() => setCollapsed((current) => !current)}
|
|
156
|
+
>
|
|
157
|
+
<PanelLeftClose className={collapsed ? 'rotate-180' : ''} />
|
|
158
|
+
</Button>
|
|
159
|
+
</PaneActions>
|
|
163
160
|
</PaneHeader>
|
|
164
161
|
<PaneBody>
|
|
165
162
|
<SidebarNav
|
|
@@ -241,26 +238,8 @@ O driver de drag-and-drop continua externo e fornece seus atributos por `dragPro
|
|
|
241
238
|
| `className` | `string` | | Ajusta a raiz. A largura externa deve continuar pertencendo ao `Pane`. |
|
|
242
239
|
| `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou uma navegação que gerencie a própria estrutura. |
|
|
243
240
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
247
|
-
|---|---|---|---|
|
|
248
|
-
| `className` | `string` | | Ajusta a faixa fixa e seu espaçamento. |
|
|
249
|
-
| `children` | `ReactNode` | | Identidade, contexto ou ações apresentadas no topo. |
|
|
250
|
-
|
|
251
|
-
## Propriedades de PaneBody
|
|
252
|
-
|
|
253
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
254
|
-
|---|---|---|---|
|
|
255
|
-
| `className` | `string` | | Ajusta a região flexível e rolável. |
|
|
256
|
-
| `children` | `ReactNode` | | Conteúdo que ocupa o espaço entre cabeçalho e rodapé. |
|
|
257
|
-
|
|
258
|
-
## Propriedades de PaneFooter
|
|
259
|
-
|
|
260
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
261
|
-
|---|---|---|---|
|
|
262
|
-
| `className` | `string` | | Ajusta a faixa fixa e seu espaçamento. |
|
|
263
|
-
| `children` | `ReactNode` | | Navegação ou ações que precisam permanecer acessíveis no rodapé. |
|
|
241
|
+
`PaneHeader`, `PaneBody` e `PaneFooter` são os slots da família `Pane`; a referência deles está na
|
|
242
|
+
[página do Pane](/ui/pane).
|
|
264
243
|
|
|
265
244
|
## Propriedades de SidebarNav
|
|
266
245
|
|
|
@@ -15,15 +15,19 @@ avatares e barras com dimensões próximas às linhas de texto esperadas.
|
|
|
15
15
|
|
|
16
16
|
## Card em carregamento
|
|
17
17
|
|
|
18
|
-
O esqueleto reproduz o layout final do card — título,
|
|
18
|
+
O esqueleto reproduz o layout final do card — título, conteúdo e ações — para a tela não pular
|
|
19
|
+
quando os dados chegarem. O título entra pelo slot do cabeçalho com `asChild`, porque o
|
|
20
|
+
`CardHeader` só aceita os próprios slots.
|
|
19
21
|
|
|
20
22
|
```tsx preview col
|
|
21
23
|
<Card>
|
|
22
24
|
<CardHeader>
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
+
<CardTitle asChild>
|
|
26
|
+
<Skeleton className="h-5 w-40" />
|
|
27
|
+
</CardTitle>
|
|
25
28
|
</CardHeader>
|
|
26
29
|
<CardBody className="space-y-2">
|
|
30
|
+
<Skeleton className="h-4 w-56" />
|
|
27
31
|
<Skeleton className="h-4 w-full" />
|
|
28
32
|
<Skeleton className="h-4 w-3/4" />
|
|
29
33
|
</CardBody>
|
|
@@ -8,10 +8,10 @@ layout permanece estático.
|
|
|
8
8
|
render(
|
|
9
9
|
<div className="h-72 overflow-hidden rounded-lg border border-border">
|
|
10
10
|
<Split resizable>
|
|
11
|
-
<Pane initialSize={30} minSize={20}
|
|
12
|
-
<
|
|
11
|
+
<Pane initialSize={30} minSize={20} className="bg-muted/30">
|
|
12
|
+
<p className="text-sm">Navegação</p>
|
|
13
13
|
</Pane>
|
|
14
|
-
<Pane grow
|
|
14
|
+
<Pane grow>
|
|
15
15
|
<p className="text-sm text-muted-foreground">
|
|
16
16
|
Conteúdo. Arraste a divisória.
|
|
17
17
|
</p>
|
|
@@ -21,26 +21,31 @@ render(
|
|
|
21
21
|
);
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
O `Split` responde pela relação espacial e pelo arraste. O que existe dentro de cada área — o
|
|
25
|
+
cabeçalho, o corpo rolável, o rodapé, o recuo e a escolha entre regiões seccionadas e contínuas —
|
|
26
|
+
pertence ao [`Pane`](/ui/pane) e está documentado na página da família.
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
espaçamento; `sm` e `lg` atendem outras densidades.
|
|
28
|
+
## Tamanho de cada pane
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
Cada `Pane` declara o próprio tamanho e o `Split` o aplica. Números representam porcentagens;
|
|
31
|
+
strings aceitam `%`, `rem`, `em`, `vh`, `vw` e `px`. Quando uma área precisa continuar legível em
|
|
32
|
+
telas largas, use uma unidade absoluta no tamanho inicial ou mínimo, de preferência `rem`, para
|
|
33
|
+
acompanhar a escala tipográfica configurada pela aplicação. `grow` entrega o espaço remanescente.
|
|
32
34
|
|
|
33
35
|
```tsx
|
|
34
36
|
<Split resizable>
|
|
35
|
-
<Pane grow
|
|
37
|
+
<Pane grow>
|
|
36
38
|
<Main />
|
|
37
39
|
</Pane>
|
|
38
|
-
<Pane initialSize="28rem" minSize="20rem"
|
|
40
|
+
<Pane initialSize="28rem" minSize="20rem">
|
|
39
41
|
<Inspector />
|
|
40
42
|
</Pane>
|
|
41
43
|
</Split>
|
|
42
44
|
```
|
|
43
45
|
|
|
46
|
+
`minSize` e `maxSize` valem enquanto o `Split` é redimensionável; sem `resizable` eles não limitam
|
|
47
|
+
nada.
|
|
48
|
+
|
|
44
49
|
## Persistência
|
|
45
50
|
|
|
46
51
|
Um layout pode ser restaurado sem acoplar `Split` a um mecanismo específico de armazenamento. Dê um `id` estável a cada `Pane`, leia o valor salvo para formar `defaultLayout` e persista apenas mudanças concluídas pela pessoa.
|
|
@@ -135,16 +140,6 @@ render(<Example />);
|
|
|
135
140
|
| `defaultLayout` | `Record<string, number>` | | Layout percentual restaurado, indexado pelos ids dos panes. |
|
|
136
141
|
| `onLayoutChanged` | `(layout, { isUserInteraction }) => void` | | Chamado ao concluir uma mudança de layout; persista onde fizer sentido. |
|
|
137
142
|
|
|
138
|
-
## Propriedades de Pane
|
|
139
|
-
|
|
140
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
141
|
-
| --------------------- | -------------------------------- | ------- | ----------------------------------------------------------------------------------------- |
|
|
142
|
-
| `id` | `string` | | Identidade estável usada pelo layout redimensionável e persistido. |
|
|
143
|
-
| `initialSize` | `number \| string` | | Tamanho inicial; número é porcentagem, string aceita `%`, `rem`, `em`, `vh`, `vw` e `px`. |
|
|
144
|
-
| `minSize` / `maxSize` | `number \| string` | | Limites quando o split é redimensionável. |
|
|
145
|
-
| `grow` | `boolean` | `false` | Ocupa o espaço remanescente no layout simples. |
|
|
146
|
-
| `inset` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Respiro interno; `none` para chrome, navegação ou conteúdo com inset próprio. |
|
|
147
|
-
|
|
148
143
|
## Propriedades de SurfaceAssistant
|
|
149
144
|
|
|
150
145
|
| Propriedade | Tipo | Padrão | Descrição |
|
package/src/ui/docs/registry.tsx
CHANGED
|
@@ -68,6 +68,7 @@ import chatMd from "./content/chat.md?raw";
|
|
|
68
68
|
import checkboxMd from "./content/checkbox.md?raw";
|
|
69
69
|
import collapsibleMd from "./content/collapsible.md?raw";
|
|
70
70
|
import iconPickerMd from "./content/icon-picker.md?raw";
|
|
71
|
+
import iconTileMd from "./content/icon-tile.md?raw";
|
|
71
72
|
import commandMd from "./content/command.md?raw";
|
|
72
73
|
import composerMd from "./content/composer.md?raw";
|
|
73
74
|
import copyableMd from "./content/copyable.md?raw";
|
|
@@ -124,6 +125,7 @@ import actionSearchDialogMd from "./content/action-list-dialog.md?raw";
|
|
|
124
125
|
import pageMd from "./content/page.md?raw";
|
|
125
126
|
import presentationMd from "./content/presentation.md?raw";
|
|
126
127
|
import contentMd from "./content/content.md?raw";
|
|
128
|
+
import paneMd from "./content/pane.md?raw";
|
|
127
129
|
import sidebarMd from "./content/sidebar.md?raw";
|
|
128
130
|
import splitMd from "./content/split.md?raw";
|
|
129
131
|
import routerMd from "./content/router.md?raw";
|
|
@@ -417,8 +419,13 @@ export const UI_SECTIONS: DocSection[] = [
|
|
|
417
419
|
pages: [
|
|
418
420
|
{
|
|
419
421
|
slug: "split",
|
|
420
|
-
title: "Split
|
|
421
|
-
render: pattern("Split
|
|
422
|
+
title: "Split",
|
|
423
|
+
render: pattern("Split", "split", splitMd),
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
slug: "pane",
|
|
427
|
+
title: "Pane",
|
|
428
|
+
render: pattern("Pane", "pane", paneMd),
|
|
422
429
|
},
|
|
423
430
|
{
|
|
424
431
|
slug: "sidebar",
|
|
@@ -697,6 +704,11 @@ export const UI_SECTIONS: DocSection[] = [
|
|
|
697
704
|
title: "Empty Value",
|
|
698
705
|
render: comp("Empty Value", "empty-value", emptyValueMd),
|
|
699
706
|
},
|
|
707
|
+
{
|
|
708
|
+
slug: "icon-tile",
|
|
709
|
+
title: "Icon Tile",
|
|
710
|
+
render: comp("Icon Tile", "icon-tile", iconTileMd),
|
|
711
|
+
},
|
|
700
712
|
{ slug: "item", title: "Item", render: comp("Item", "item", itemMd) },
|
|
701
713
|
{ slug: "kbd", title: "Kbd", render: comp("Kbd", "kbd", kbdMd) },
|
|
702
714
|
{
|
package/src/ui/meta.ts
CHANGED
|
@@ -53,6 +53,12 @@ export const componentMeta = {
|
|
|
53
53
|
whenToUse:
|
|
54
54
|
"Sinal compacto de estado. `context` declara neutral/primary/info/success/warning/danger e `variant` escolhe solid/outline. Passe `label` quando a cor reforçar informação; sem label, o ponto é decorativo. Para texto visível, use Badge.",
|
|
55
55
|
},
|
|
56
|
+
"icon-tile": {
|
|
57
|
+
name: "icon-tile",
|
|
58
|
+
ancestry: "opus",
|
|
59
|
+
whenToUse:
|
|
60
|
+
"Dê suporte visual não interativo a um ícone com tamanho, contexto, preenchimento e arredondamento consistentes. Componha-o nos slots que pedem a moldura; passe o ícone diretamente quando ela não for necessária. Para uma ação, use Button com tamanho de ícone.",
|
|
61
|
+
},
|
|
56
62
|
detail: {
|
|
57
63
|
name: "detail",
|
|
58
64
|
ancestry: "opus",
|
|
@@ -117,7 +123,7 @@ export const componentMeta = {
|
|
|
117
123
|
name: "content-header",
|
|
118
124
|
ancestry: "opus",
|
|
119
125
|
whenToUse:
|
|
120
|
-
|
|
126
|
+
'Estruture uma região com título e corpo. No caso comum, declare título, descrição, contador e ações diretamente em Content; use `framed` quando a região precisar de limite próprio, `as="fieldset"` para agrupar campos sob uma legenda nativa e `frameVariant="legend"` somente quando essa legenda precisar integrar visualmente a borda. Componha ContentHeader apenas quando precisar controlar a anatomia.',
|
|
121
127
|
},
|
|
122
128
|
copyable: {
|
|
123
129
|
name: "copyable",
|
|
@@ -279,7 +285,7 @@ export const componentMeta = {
|
|
|
279
285
|
name: "field",
|
|
280
286
|
ancestry: "shadcn",
|
|
281
287
|
whenToUse:
|
|
282
|
-
|
|
288
|
+
'Componha rótulo, controle, ajuda e erro com espaçamento consistente. Use a orientação vertical no caso comum e a horizontal quando controle e texto precisarem ficar lado a lado. FieldGroup organiza vários campos; quando o conjunto precisar de título, componha-o dentro de Content com `as="fieldset"`.',
|
|
283
289
|
},
|
|
284
290
|
"input-otp": {
|
|
285
291
|
name: "input-otp",
|
|
@@ -321,13 +327,19 @@ export const componentMeta = {
|
|
|
321
327
|
name: "split",
|
|
322
328
|
ancestry: "opus",
|
|
323
329
|
whenToUse:
|
|
324
|
-
"Divide uma área em panes em sequência horizontal ou vertical. Use `resizable` quando a pessoa deve ajustar a fronteira; o mesmo `<Split>` vira flex simples sem ele. Cada `<Pane>` declara tamanho inicial
|
|
330
|
+
"Divide uma área em panes em sequência horizontal ou vertical. Use `resizable` quando a pessoa deve ajustar a fronteira; o mesmo `<Split>` vira flex simples sem ele. Cada `<Pane>` declara tamanho inicial e mínimo; a anatomia do pane tem página própria. SurfaceAssistant especializa esse layout para assistência contextual dentro de Page, Dialog ou Drawer.",
|
|
325
331
|
},
|
|
326
332
|
sidebar: {
|
|
327
333
|
name: "sidebar",
|
|
328
334
|
ancestry: "opus",
|
|
329
335
|
whenToUse:
|
|
330
|
-
"Organize navegação global ou contextual em uma coluna lateral. Split e Pane definem posição e largura; Sidebar fornece a superfície e o colapso
|
|
336
|
+
"Organize navegação global ou contextual em uma coluna lateral. Split e Pane definem posição e largura; Sidebar fornece a superfície e o colapso. Use SidebarNav para grupos planos e componha árvores com SidebarItem e SidebarTreeGroup; cabeçalho e rodapé próprios são do Pane que a hospeda.",
|
|
337
|
+
},
|
|
338
|
+
pane: {
|
|
339
|
+
name: "pane",
|
|
340
|
+
ancestry: "opus",
|
|
341
|
+
whenToUse:
|
|
342
|
+
"Estruture a coluna ou faixa encaixada num Split: PaneHeader nomeia a região e leva mídia e ações, PaneBody rola e PaneFooter fixa o que precisa ficar à vista. `layout` escolhe entre regiões seccionadas, com divisores derivados da vizinhança, e o fluxo contínuo. O `inset` vale para o pane sem slots; com eles, o recuo é de cada região.",
|
|
331
343
|
},
|
|
332
344
|
"scroll-area": {
|
|
333
345
|
name: "scroll-area",
|
|
@@ -382,7 +394,7 @@ export const componentMeta = {
|
|
|
382
394
|
name: "action-list",
|
|
383
395
|
ancestry: "opus",
|
|
384
396
|
whenToUse:
|
|
385
|
-
"Apresente uma coleção pesquisável a partir de uma ListAction. O contrato declara colunas, filtros, período e busca; ActionList coordena visualizações, paginação, seleção em lote e sincronização com a URL. Em uma página, envolva a lista com Content para manter título e criação junto da coleção. Para um único recurso, use ActionView.",
|
|
397
|
+
"Apresente uma coleção pesquisável a partir de uma ListAction. O contrato declara colunas, filtros, período e busca; ActionList coordena visualizações, paginação, seleção em lote e sincronização com a URL. A tabela derivada não cria moldura própria. Em uma página, envolva a lista com Content para manter título e criação junto da coleção. Para um único recurso, use ActionView.",
|
|
386
398
|
},
|
|
387
399
|
"action-trigger": {
|
|
388
400
|
name: "action-trigger",
|
package/src/ui/react.tsx
CHANGED
|
@@ -93,6 +93,7 @@ export type {
|
|
|
93
93
|
export {
|
|
94
94
|
Card,
|
|
95
95
|
CardHeader,
|
|
96
|
+
CardMedia,
|
|
96
97
|
CardTitle,
|
|
97
98
|
CardDescription,
|
|
98
99
|
CardAction,
|
|
@@ -132,7 +133,9 @@ export {
|
|
|
132
133
|
DialogOverlay,
|
|
133
134
|
DialogContent,
|
|
134
135
|
DialogHeader,
|
|
136
|
+
DialogNavigation,
|
|
135
137
|
DialogMedia,
|
|
138
|
+
DialogActions,
|
|
136
139
|
DialogBody,
|
|
137
140
|
DialogFooter,
|
|
138
141
|
DialogTitle,
|
|
@@ -143,6 +146,10 @@ export type {
|
|
|
143
146
|
DialogMode,
|
|
144
147
|
} from "./components/primitives/dialog.tsx";
|
|
145
148
|
|
|
149
|
+
// O pacote de anatomia que Card, Dialog, Drawer e Pane declaram no root (ADR 0023). As
|
|
150
|
+
// tabelas e o contexto continuam internos; o consumidor escolhe entre os dois nomes.
|
|
151
|
+
export type { SurfaceLayout } from "./components/patterns/surface-anatomy.ts";
|
|
152
|
+
|
|
146
153
|
export {
|
|
147
154
|
Menu,
|
|
148
155
|
MenuTrigger,
|
|
@@ -270,10 +277,13 @@ export {
|
|
|
270
277
|
} from "./components/primitives/collapsible.tsx";
|
|
271
278
|
export {
|
|
272
279
|
Drawer,
|
|
280
|
+
DrawerActions,
|
|
273
281
|
DrawerClose,
|
|
274
282
|
DrawerContent,
|
|
275
283
|
DrawerFooter,
|
|
276
284
|
DrawerHeader,
|
|
285
|
+
DrawerMedia,
|
|
286
|
+
DrawerNavigation,
|
|
277
287
|
DrawerBody,
|
|
278
288
|
DrawerTitle,
|
|
279
289
|
DrawerTrigger,
|
|
@@ -298,6 +308,21 @@ export {
|
|
|
298
308
|
FieldSet,
|
|
299
309
|
FieldTitle,
|
|
300
310
|
} from "./components/primitives/field.tsx";
|
|
311
|
+
export type {
|
|
312
|
+
FieldSetProps,
|
|
313
|
+
FieldSetVariant,
|
|
314
|
+
} from "./components/primitives/field.tsx";
|
|
315
|
+
export {
|
|
316
|
+
IconTile,
|
|
317
|
+
iconTileVariants,
|
|
318
|
+
resolveIconTileStyle,
|
|
319
|
+
} from "./components/primitives/icon-tile.tsx";
|
|
320
|
+
export type {
|
|
321
|
+
IconTileContext,
|
|
322
|
+
IconTileProps,
|
|
323
|
+
IconTileSize,
|
|
324
|
+
IconTileVariant,
|
|
325
|
+
} from "./components/primitives/icon-tile.tsx";
|
|
301
326
|
export {
|
|
302
327
|
InputGroup,
|
|
303
328
|
InputGroupAddon,
|
|
@@ -471,6 +496,8 @@ export {
|
|
|
471
496
|
export type {
|
|
472
497
|
ContentProps,
|
|
473
498
|
ContentHeaderProps,
|
|
499
|
+
ContentElement,
|
|
500
|
+
ContentFrameVariant,
|
|
474
501
|
ContentHeaderLevel,
|
|
475
502
|
ContentHeaderVariant,
|
|
476
503
|
} from "./components/patterns/content-header.tsx";
|
|
@@ -505,7 +532,11 @@ export type {
|
|
|
505
532
|
|
|
506
533
|
// Barra lateral composicional: header/conteúdo/footer e navegação, sem possuir o layout.
|
|
507
534
|
export {
|
|
535
|
+
PaneActions,
|
|
536
|
+
PaneDescription,
|
|
508
537
|
PaneHeader,
|
|
538
|
+
PaneMedia,
|
|
539
|
+
PaneTitle,
|
|
509
540
|
PaneBody,
|
|
510
541
|
PaneContent,
|
|
511
542
|
PaneFooter,
|