@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
|
@@ -93,8 +93,8 @@ Dentro de [`PageShell`](/ui/page), a superfície `page` usa a anatomia real da a
|
|
|
93
93
|
com `PageFooter` quando há ações de rodapé.
|
|
94
94
|
|
|
95
95
|
Uma Presentation de listagem exibida como página muda essa distribuição para manter a criação perto
|
|
96
|
-
da coleção. O `PageBody` recebe um [`
|
|
97
|
-
[`ActionList`](/ui/action-list), e o cabeçalho desse `
|
|
96
|
+
da coleção. O `PageBody` recebe um [`Surface`](/ui/surface) com a
|
|
97
|
+
[`ActionList`](/ui/action-list), e o cabeçalho desse `Surface` recebe o título e os comandos
|
|
98
98
|
declarados com `placement: "header"`, no extremo oposto ao título. Os comandos de cabeçalho usam o
|
|
99
99
|
tamanho `default` e permanecem textuais, mesmo quando a action declara um ícone: o que abre outra
|
|
100
100
|
Presentation é um `Button` sólido, e uma action `simple` vira um
|
|
@@ -185,7 +185,7 @@ componente exige `children`, e uma com body de action os recusa: nos dois casos,
|
|
|
185
185
|
lança um erro que nomeia a Presentation.
|
|
186
186
|
|
|
187
187
|
Com `heading: "shell"`, o padrão, a casca emite o título da definição. Quando o conteúdo React já
|
|
188
|
-
declara o heading principal da página, como um `
|
|
188
|
+
declara o heading principal da página, como um `Surface level={1}`, use `heading: "content"`: dentro
|
|
189
189
|
de `PageShell`, a casca deixa de emitir o `PageHeader` com título e o documento continua com um único `h1`. Em
|
|
190
190
|
Dialog e Drawer, o título continua no cabeçalho da superfície.
|
|
191
191
|
|
|
@@ -12,7 +12,7 @@ com regiões. A orientação horizontal fica entre blocos empilhados e ocupa tod
|
|
|
12
12
|
<p className="text-sm text-muted-foreground">Próximo horário livre hoje, às 14h.</p>
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Não use `Separator` entre cabeçalho, corpo e rodapé de [`
|
|
15
|
+
Não use `Separator` entre cabeçalho, corpo e rodapé de [`Surface`](/ui/surface), [`Dialog`](/ui/dialog) ou
|
|
16
16
|
[`Drawer`](/ui/drawer). Nessas superfícies, os divisores são derivados das regiões presentes: use
|
|
17
17
|
`layout="sectioned"` no componente raiz.
|
|
18
18
|
|
|
@@ -32,8 +32,8 @@ Use a orientação vertical entre itens lado a lado. A linha herda a altura do c
|
|
|
32
32
|
|
|
33
33
|
## Propriedades de Separator
|
|
34
34
|
|
|
35
|
-
| Propriedade
|
|
36
|
-
|
|
37
|
-
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da linha. A vertical precisa de altura vinda do contêiner.
|
|
38
|
-
| `decorative`
|
|
39
|
-
| `className`
|
|
35
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
36
|
+
| ------------- | ---------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
37
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da linha. A vertical precisa de altura vinda do contêiner. |
|
|
38
|
+
| `decorative` | `boolean` | `true` | Uma linha decorativa fica fora da árvore de acessibilidade. Use `false` quando a divisão tiver significado e precisar ser anunciada. |
|
|
39
|
+
| `className` | `string` | | Ajusta a linha, como o espaçamento ao redor. |
|
|
@@ -1,295 +1,97 @@
|
|
|
1
|
-
## Navegação
|
|
1
|
+
## Navegação lateral
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[`Pane`](/ui/pane) dentro de [`Split`](/ui/split).
|
|
6
|
-
|
|
7
|
-
O exemplo canônico mantém a largura inicial em `rem`, deixa a navegação rolar e preserva o
|
|
8
|
-
cabeçalho e o rodapé nas extremidades.
|
|
3
|
+
`Sidebar` é a estrutura vertical de navegação. Ela pode ocupar um `Pane`, mas não depende dele:
|
|
4
|
+
`Pane` define somente a medida no `Split`; a própria sidebar e seus filhos organizam o conteúdo.
|
|
9
5
|
|
|
10
6
|
```tsx preview
|
|
11
7
|
render(
|
|
12
|
-
<div className="h-
|
|
8
|
+
<div className="h-72 overflow-hidden rounded-lg border border-border">
|
|
13
9
|
<Split>
|
|
14
|
-
<Pane initialSize="16rem"
|
|
10
|
+
<Pane initialSize="16rem">
|
|
15
11
|
<Sidebar className="w-full">
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
</PaneBody>
|
|
34
|
-
<PaneFooter>
|
|
35
|
-
<SidebarItem label="Configurações" icon={<Settings />} onClick={() => {}} />
|
|
36
|
-
</PaneFooter>
|
|
12
|
+
<SidebarNav
|
|
13
|
+
navLabel="Projeto"
|
|
14
|
+
activeId="overview"
|
|
15
|
+
groups={[
|
|
16
|
+
{
|
|
17
|
+
label: "Workspace",
|
|
18
|
+
items: [
|
|
19
|
+
{
|
|
20
|
+
id: "overview",
|
|
21
|
+
label: "Visão geral",
|
|
22
|
+
icon: <LayoutDashboard />,
|
|
23
|
+
},
|
|
24
|
+
{ id: "members", label: "Pessoas", icon: <Users /> },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
]}
|
|
28
|
+
/>
|
|
37
29
|
</Sidebar>
|
|
38
30
|
</Pane>
|
|
39
|
-
<Pane grow
|
|
40
|
-
<
|
|
31
|
+
<Pane grow>
|
|
32
|
+
<main className="h-full overflow-y-auto p-6">Conteúdo.</main>
|
|
41
33
|
</Pane>
|
|
42
34
|
</Split>
|
|
43
35
|
</div>,
|
|
44
|
-
)
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Use `resizable` no `Split` somente quando ajustar a largura fizer parte da tarefa. Nesse caso, o
|
|
48
|
-
`Pane` também declara `minSize`, e `divider={false}` evita que `Sidebar` desenhe uma segunda
|
|
49
|
-
divisória ao lado do handle.
|
|
50
|
-
|
|
51
|
-
## Anatomia e responsabilidades
|
|
52
|
-
|
|
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).
|
|
56
|
-
|
|
57
|
-
| Parte | Responsabilidade |
|
|
58
|
-
|---|---|
|
|
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. |
|
|
61
|
-
| `Sidebar` | Desenha a superfície lateral e fornece o estado de colapso. |
|
|
62
|
-
| `SidebarNav` | Apresenta e controla os destinos de navegação. |
|
|
63
|
-
|
|
64
|
-
## Escolher a navegação
|
|
65
|
-
|
|
66
|
-
Use `SidebarNav` para grupos planos de destinos. Ele recebe dados e produz `SidebarItem` com a mesma
|
|
67
|
-
semântica usada na composição manual.
|
|
68
|
-
|
|
69
|
-
```tsx preview
|
|
70
|
-
<div className="h-72 w-64 overflow-hidden rounded-lg border border-border">
|
|
71
|
-
<Sidebar className="w-full">
|
|
72
|
-
<PaneBody>
|
|
73
|
-
<SidebarNav
|
|
74
|
-
groups={[
|
|
75
|
-
{
|
|
76
|
-
label: 'Configurações',
|
|
77
|
-
items: [
|
|
78
|
-
{ id: 'users', label: 'Usuários', icon: <Users /> },
|
|
79
|
-
{ id: 'roles', label: 'Papéis', icon: <ShieldCheck /> },
|
|
80
|
-
{ id: 'imports', label: 'Importações', icon: <Database /> },
|
|
81
|
-
],
|
|
82
|
-
},
|
|
83
|
-
]}
|
|
84
|
-
activeId="users"
|
|
85
|
-
onSelect={() => {}}
|
|
86
|
-
/>
|
|
87
|
-
</PaneBody>
|
|
88
|
-
</Sidebar>
|
|
89
|
-
</div>
|
|
36
|
+
);
|
|
90
37
|
```
|
|
91
38
|
|
|
92
|
-
##
|
|
39
|
+
## Regiões próprias
|
|
93
40
|
|
|
94
|
-
Uma
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
principal e o controle de expansão permanecem irmãos acessíveis.
|
|
41
|
+
Uma sidebar especializada pode declarar cabeçalho, região rolável e rodapé com HTML semântico. O
|
|
42
|
+
conteúdo central recebe `min-h-0 flex-1 overflow-y-auto`; borda, fundo e raio pertencem à própria
|
|
43
|
+
`Sidebar` ou a uma `Surface` que a envolva.
|
|
98
44
|
|
|
99
45
|
```tsx preview
|
|
100
|
-
const [open, setOpen] = useState(true)
|
|
101
|
-
|
|
102
46
|
render(
|
|
103
|
-
<div className="h-72
|
|
104
|
-
<Sidebar className="w-
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
/>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
</SidebarTreeGroup>
|
|
121
|
-
</SidebarTreeGroup>
|
|
122
|
-
)}
|
|
123
|
-
</PaneBody>
|
|
47
|
+
<div className="h-72 overflow-hidden rounded-lg border border-border">
|
|
48
|
+
<Sidebar className="w-64">
|
|
49
|
+
<header className="flex h-14 shrink-0 items-center px-3 font-semibold">
|
|
50
|
+
Projeto
|
|
51
|
+
</header>
|
|
52
|
+
<nav
|
|
53
|
+
className="min-h-0 flex-1 space-y-1 overflow-y-auto p-3"
|
|
54
|
+
aria-label="Projeto"
|
|
55
|
+
>
|
|
56
|
+
<SidebarItem label="Visão geral" icon={<LayoutDashboard />} active />
|
|
57
|
+
<SidebarItem label="Pessoas" icon={<Users />} />
|
|
58
|
+
</nav>
|
|
59
|
+
<footer className="shrink-0 border-t p-3">
|
|
60
|
+
<Button variant="ghost" className="w-full justify-start">
|
|
61
|
+
Configurações
|
|
62
|
+
</Button>
|
|
63
|
+
</footer>
|
|
124
64
|
</Sidebar>
|
|
125
65
|
</div>,
|
|
126
|
-
)
|
|
66
|
+
);
|
|
127
67
|
```
|
|
128
68
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
## Recolher a coluna
|
|
69
|
+
Use `SidebarNav` quando grupos e itens já puderem ser descritos como dados. Use `SidebarItem`
|
|
70
|
+
diretamente quando a composição precisar de controles, badges ou hierarquia particular.
|
|
133
71
|
|
|
134
|
-
|
|
135
|
-
somente os ícones e expõem os rótulos em tooltips. Por isso, todo destino que aparece no modo
|
|
136
|
-
recolhido precisa de um ícone reconhecível e de um `label` completo. `SidebarNav` já monta o
|
|
137
|
-
`TooltipProvider`; um `SidebarItem` recolhido fora dele depende do provider na raiz do aplicativo.
|
|
72
|
+
## Colapso
|
|
138
73
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
Outros tipos de `ReactNode` continuam responsáveis pelas próprias dimensões.
|
|
74
|
+
`collapsed` informa o estado compacto aos itens. Forneça labels acessíveis mesmo quando somente os
|
|
75
|
+
ícones estiverem visíveis.
|
|
142
76
|
|
|
143
77
|
```tsx preview
|
|
144
|
-
const [collapsed, setCollapsed] = useState(false)
|
|
145
|
-
|
|
146
78
|
render(
|
|
147
|
-
<
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
<PanelLeftClose className={collapsed ? 'rotate-180' : ''} />
|
|
158
|
-
</Button>
|
|
159
|
-
</PaneActions>
|
|
160
|
-
</PaneHeader>
|
|
161
|
-
<PaneBody>
|
|
162
|
-
<SidebarNav
|
|
163
|
-
groups={[
|
|
164
|
-
{
|
|
165
|
-
items: [
|
|
166
|
-
{ id: 'home', label: 'Início', icon: <House /> },
|
|
167
|
-
{ id: 'reports', label: 'Relatórios', icon: <ChartNoAxesColumn /> },
|
|
168
|
-
],
|
|
169
|
-
},
|
|
170
|
-
]}
|
|
171
|
-
activeId="home"
|
|
172
|
-
onSelect={() => {}}
|
|
173
|
-
/>
|
|
174
|
-
</PaneBody>
|
|
175
|
-
</Sidebar>
|
|
176
|
-
<div className="flex-1 p-4 text-sm text-muted-foreground">
|
|
177
|
-
O conteúdo ocupa o espaço liberado pela sidebar.
|
|
178
|
-
</div>
|
|
179
|
-
</div>,
|
|
180
|
-
)
|
|
79
|
+
<Sidebar collapsed className="w-16">
|
|
80
|
+
<nav
|
|
81
|
+
className="flex flex-col items-center gap-1 p-3"
|
|
82
|
+
aria-label="Principal"
|
|
83
|
+
>
|
|
84
|
+
<SidebarItem label="Início" icon={<House />} active />
|
|
85
|
+
<SidebarItem label="Pessoas" icon={<Users />} />
|
|
86
|
+
</nav>
|
|
87
|
+
</Sidebar>,
|
|
88
|
+
);
|
|
181
89
|
```
|
|
182
90
|
|
|
183
|
-
|
|
184
|
-
`Sidebar`; a aplicação não precisa trocar a árvore de componentes.
|
|
185
|
-
|
|
186
|
-
## Itens com expansão e ações
|
|
187
|
-
|
|
188
|
-
`SidebarItem` mantém o destino principal, a expansão e as ações como controles irmãos. Essa
|
|
189
|
-
estrutura evita botões aninhados e permite que cada controle receba foco de forma independente.
|
|
190
|
-
|
|
191
|
-
```tsx preview
|
|
192
|
-
<div className="w-72 rounded-lg border border-border p-2">
|
|
193
|
-
<SidebarItem
|
|
194
|
-
label="Contratos"
|
|
195
|
-
icon={<Folder />}
|
|
196
|
-
expanded
|
|
197
|
-
onToggle={() => {}}
|
|
198
|
-
actions={
|
|
199
|
-
<Button variant="ghost" size="icon-xs" aria-label="Mais ações">
|
|
200
|
-
<Ellipsis />
|
|
201
|
-
</Button>
|
|
202
|
-
}
|
|
203
|
-
onClick={() => {}}
|
|
204
|
-
/>
|
|
205
|
-
<SidebarTreeGroup>
|
|
206
|
-
<SidebarItem
|
|
207
|
-
label="Criar workspace"
|
|
208
|
-
icon={<FilePlus2 />}
|
|
209
|
-
onClick={() => {}}
|
|
210
|
-
/>
|
|
211
|
-
</SidebarTreeGroup>
|
|
212
|
-
</div>
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
Quando o rótulo não cabe, ele termina em um gradiente. As ações aparecem ao passar o ponteiro, ao
|
|
216
|
-
receber foco visível ou enquanto um menu permanece aberto; como são sobrepostas, não reduzem o
|
|
217
|
-
espaço disponível para o texto.
|
|
218
|
-
|
|
219
|
-
Para árvores arrastáveis, `dropPosition` comunica o destino visual sem reservar espaço:
|
|
220
|
-
`before` e `after` desenham uma linha na fronteira, enquanto `inside` realça a superfície do item.
|
|
221
|
-
O driver de drag-and-drop continua externo e fornece seus atributos por `dragProps`.
|
|
222
|
-
|
|
223
|
-
## Acessibilidade
|
|
224
|
-
|
|
225
|
-
- `activeId` resulta em `aria-current="page"` no destino atual.
|
|
226
|
-
- `navLabel` nomeia a landmark de navegação.
|
|
227
|
-
- O controle de expansão informa `aria-expanded` e recebe um rótulo baseado no item.
|
|
228
|
-
- Itens desabilitados continuam visíveis, mas não respondem à interação.
|
|
229
|
-
- O foco visível usa o anel semântico do tema no destino, nas ações e no controle de expansão.
|
|
230
|
-
- No modo recolhido, o tooltip preserva o nome que deixou de aparecer visualmente.
|
|
231
|
-
|
|
232
|
-
## Propriedades de Sidebar
|
|
233
|
-
|
|
234
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
235
|
-
|---|---|---|---|
|
|
236
|
-
| `collapsed` | `boolean` | `false` | Recolhe a coluna e publica esse estado para as navegações descendentes. |
|
|
237
|
-
| `divider` | `boolean` | `true` | Desenha a borda na lateral. Desative quando o `Split` já fornecer o handle. |
|
|
238
|
-
| `className` | `string` | | Ajusta a raiz. A largura externa deve continuar pertencendo ao `Pane`. |
|
|
239
|
-
| `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou uma navegação que gerencie a própria estrutura. |
|
|
240
|
-
|
|
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).
|
|
243
|
-
|
|
244
|
-
## Propriedades de SidebarNav
|
|
245
|
-
|
|
246
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
247
|
-
|---|---|---|---|
|
|
248
|
-
| `groups` | `SidebarNavGroup[]` | | Grupos e itens apresentados na ordem recebida. Grupos vazios são omitidos. |
|
|
249
|
-
| `activeId` | `string` | | Identificador do destino atual. |
|
|
250
|
-
| `onSelect` | `(id: string) => void` | | Recebe o identificador selecionado; roteamento permanece com o consumidor. |
|
|
251
|
-
| `navLabel` | `string` | `'Navegação'` | Nome acessível da landmark `nav`. |
|
|
252
|
-
| `className` | `string` | | Ajusta a raiz da navegação. |
|
|
253
|
-
|
|
254
|
-
### Estrutura de SidebarNavGroup
|
|
255
|
-
|
|
256
|
-
| Campo | Tipo | Descrição |
|
|
257
|
-
|---|---|---|
|
|
258
|
-
| `label` | `string` | Rótulo opcional do grupo. Rótulos vazios não reservam espaço. |
|
|
259
|
-
| `items` | `SidebarNavItem[]` | Itens diretos do grupo. |
|
|
260
|
-
|
|
261
|
-
`SidebarNavItem` recebe as propriedades de `SidebarItem`, exceto `active` e `onClick`, e acrescenta
|
|
262
|
-
`id`. O destaque vem de `activeId` e a seleção chega por `onSelect`, ambos no `SidebarNav`. Para mais
|
|
263
|
-
níveis, componha `SidebarItem` e `SidebarTreeGroup` diretamente.
|
|
264
|
-
|
|
265
|
-
## Propriedades de SidebarItem
|
|
266
|
-
|
|
267
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
268
|
-
|---|---|---|---|
|
|
269
|
-
| `label` | `string` | | Nome visível do destino e conteúdo do tooltip no modo recolhido. |
|
|
270
|
-
| `icon` | `ReactNode` | | Ícone apresentado antes do rótulo e preservado no modo recolhido. |
|
|
271
|
-
| `badge` | `ReactNode` | | Informação curta no fim da linha, como contagem ou estado. |
|
|
272
|
-
| `active` | `boolean` | `false` | Destaca o destino e aplica `aria-current="page"`. |
|
|
273
|
-
| `disabled` | `boolean` | `false` | Mantém o item visível sem permitir interação. |
|
|
274
|
-
| `actions` | `ReactNode` | | Controles relacionados exibidos no fim da linha. |
|
|
275
|
-
| `onToggle` | `() => void` | | Adiciona o controle independente de expansão. |
|
|
276
|
-
| `expanded` | `boolean` | `false` | Define o estado acessível e a rotação do controle de expansão. |
|
|
277
|
-
| `dropPosition` | `'before' \| 'inside' \| 'after'` | | Indica visualmente onde um item arrastado será solto. |
|
|
278
|
-
| `dragProps` | `HTMLAttributes<HTMLDivElement>` | | Encaminha atributos fornecidos pelo driver de drag-and-drop para a linha. |
|
|
279
|
-
| `tooltipHint` | `ReactNode` | | Acrescenta contexto ao tooltip do modo recolhido. |
|
|
280
|
-
| `className` | `string` | | Ajusta a linha nos estados aberto e recolhido. |
|
|
281
|
-
| `onClick` | `() => void` | | Executa a navegação principal do item. |
|
|
282
|
-
|
|
283
|
-
## Propriedades de SidebarGroupLabel
|
|
284
|
-
|
|
285
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
286
|
-
|---|---|---|---|
|
|
287
|
-
| `className` | `string` | | Ajusta o rótulo discreto do grupo. |
|
|
288
|
-
| `children` | `ReactNode` | | Nome do conjunto de destinos. |
|
|
289
|
-
|
|
290
|
-
## Propriedades de SidebarTreeGroup
|
|
91
|
+
## Responsabilidades
|
|
291
92
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
93
|
+
- `Split` organiza as regiões e o redimensionamento.
|
|
94
|
+
- `Pane` declara identidade e tamanho.
|
|
95
|
+
- `Sidebar` oferece a coluna de navegação.
|
|
96
|
+
- `SidebarNav`, `SidebarItem` e elementos nativos organizam o conteúdo interno.
|
|
97
|
+
- `Surface` oferece anatomia e tratamento visual quando a região não é uma sidebar.
|
|
@@ -18,33 +18,35 @@ o contêiner com `role="status"` e um nome, como `aria-label="Carregando sessõe
|
|
|
18
18
|
</div>
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Surface em carregamento
|
|
22
22
|
|
|
23
23
|
O esqueleto reproduz o layout final do card — título, conteúdo e ações — para a tela não pular
|
|
24
24
|
quando os dados chegarem. O título entra pelo slot do cabeçalho com `asChild`, porque o
|
|
25
|
-
`
|
|
25
|
+
`SurfaceHeader` só aceita os próprios slots.
|
|
26
26
|
|
|
27
27
|
```tsx preview col
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
<
|
|
28
|
+
<Surface framed elevation="raised">
|
|
29
|
+
<SurfaceHeader>
|
|
30
|
+
<SurfaceTitle asChild>
|
|
31
31
|
<Skeleton className="h-5 w-40" />
|
|
32
|
-
</
|
|
33
|
-
</
|
|
34
|
-
<
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
</SurfaceTitle>
|
|
33
|
+
</SurfaceHeader>
|
|
34
|
+
<SurfaceBody>
|
|
35
|
+
<div className="space-y-2">
|
|
36
|
+
<Skeleton className="h-4 w-56" />
|
|
37
|
+
<Skeleton className="h-4 w-full" />
|
|
38
|
+
<Skeleton className="h-4 w-3/4" />
|
|
39
|
+
</div>
|
|
40
|
+
</SurfaceBody>
|
|
41
|
+
<SurfaceFooter className="gap-2">
|
|
40
42
|
<Skeleton className="h-8 w-28" />
|
|
41
43
|
<Skeleton className="h-8 w-24" />
|
|
42
|
-
</
|
|
43
|
-
</
|
|
44
|
+
</SurfaceFooter>
|
|
45
|
+
</Surface>
|
|
44
46
|
```
|
|
45
47
|
|
|
46
48
|
## Propriedades de Skeleton
|
|
47
49
|
|
|
48
|
-
| Propriedade | Tipo
|
|
49
|
-
|
|
50
|
-
| `className` | `string` |
|
|
50
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
51
|
+
| ----------- | -------- | ------ | ----------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| `className` | `string` | | Dá forma ao placeholder (`h-4 w-40`, `size-10 rounded-full`); o componente só traz o pulso e o fundo. |
|
|
@@ -93,7 +93,7 @@ const defaultLayout = readLayout('workspace-layout')
|
|
|
93
93
|
}}
|
|
94
94
|
>
|
|
95
95
|
<Pane id="navigation" initialSize="28rem" minSize="28rem"><Navigation /></Pane>
|
|
96
|
-
<Pane id="content" grow><
|
|
96
|
+
<Pane id="content" grow><Surface as="section" /></Pane>
|
|
97
97
|
</Split>
|
|
98
98
|
```
|
|
99
99
|
|
|
@@ -153,20 +153,20 @@ render(<Example />);
|
|
|
153
153
|
| `defaultLayout` | `Record<string, number>` | | Layout percentual restaurado, indexado pelos ids dos panes. |
|
|
154
154
|
| `onLayoutChanged` | `(layout, { isUserInteraction }) => void` | | Chamado ao concluir uma mudança de layout; persista onde fizer sentido. |
|
|
155
155
|
| `className` | `string` | | Ajusta o contêiner do grupo. |
|
|
156
|
-
| `data-slot` | `string` | `'split'` | Identificador semântico para testes e composição de patterns.
|
|
156
|
+
| `data-slot` | `string` | `'split'` | Identificador semântico para testes e composição de patterns. |
|
|
157
157
|
| `children` | `ReactNode` | | Os `Pane`, diretos ou agrupados em fragment; outro filho gera erro. |
|
|
158
158
|
|
|
159
159
|
## Propriedades de SurfaceAssistant
|
|
160
160
|
|
|
161
|
-
| Propriedade
|
|
162
|
-
|
|
|
163
|
-
| `open`
|
|
164
|
-
| `assistantLabel`
|
|
165
|
-
| `children`
|
|
166
|
-
| `assistant`
|
|
167
|
-
| `initialSize`
|
|
168
|
-
| `minSize`
|
|
169
|
-
| `maxSize`
|
|
170
|
-
| `className`
|
|
171
|
-
| `contentClassName`
|
|
172
|
-
| `assistantClassName` | `string`
|
|
161
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
162
|
+
| -------------------- | ----------- | ------- | ------------------------------------------------------- |
|
|
163
|
+
| `open` | `boolean` | | Exibe o painel complementar à direita. |
|
|
164
|
+
| `assistantLabel` | `string` | | Nome acessível da região complementar. |
|
|
165
|
+
| `children` | `ReactNode` | | Conteúdo principal que permanece montado. |
|
|
166
|
+
| `assistant` | `ReactNode` | | Painel fornecido pela superfície que conhece o recurso. |
|
|
167
|
+
| `initialSize` | `PaneSize` | `28rem` | Largura inicial do painel. |
|
|
168
|
+
| `minSize` | `PaneSize` | `20rem` | Largura mínima durante o redimensionamento. |
|
|
169
|
+
| `maxSize` | `PaneSize` | `40rem` | Largura máxima durante o redimensionamento. |
|
|
170
|
+
| `className` | `string` | | Ajusta o contêiner do split. |
|
|
171
|
+
| `contentClassName` | `string` | | Ajusta a coluna do conteúdo principal. |
|
|
172
|
+
| `assistantClassName` | `string` | | Ajusta a coluna do painel de assistência. |
|