@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.
Files changed (97) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/bin/cli.mjs +2 -0
  3. package/bin/lib/check.mjs +241 -42
  4. package/bin/lib/copy.mjs +16 -34
  5. package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +6 -0
  6. package/docs/adr/0039-filter-presentation-is-independent-from-filter-type.md +3 -3
  7. package/docs/adr/0040-tabs-use-a-single-navigation-presentation.md +5 -6
  8. package/docs/adr/0042-toggle-group-shares-the-grouped-control-grammar.md +79 -0
  9. package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +73 -0
  10. package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +133 -0
  11. package/docs/adr/0045-surface-replaces-content-and-card.md +230 -0
  12. package/docs/adr/0046-structural-body-owns-content-rhythm.md +103 -0
  13. package/docs/adr/0047-pane-is-only-a-split-layout-unit.md +71 -0
  14. package/docs/adr/0048-modal-intro-separates-content-from-chrome.md +34 -0
  15. package/docs/adr/0049-inline-navigation-groups-with-the-heading.md +95 -0
  16. package/package.json +5 -1
  17. package/registry/skills/build-opus-ui/SKILL.md +11 -11
  18. package/registry/skills/build-opus-ui/references/evaluations.md +10 -9
  19. package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -16
  20. package/registry/templates/app/src/App.tsx +24 -12
  21. package/src/ui/appearance.ts +149 -0
  22. package/src/ui/components/patterns/action-form-card.tsx +46 -33
  23. package/src/ui/components/patterns/action-list-dialog.tsx +2 -4
  24. package/src/ui/components/patterns/confirm.tsx +3 -1
  25. package/src/ui/components/patterns/fill-region.ts +8 -7
  26. package/src/ui/components/patterns/form-dialog.tsx +1 -3
  27. package/src/ui/components/patterns/form.tsx +8 -7
  28. package/src/ui/components/patterns/list.tsx +15 -19
  29. package/src/ui/components/patterns/page.tsx +15 -11
  30. package/src/ui/components/patterns/pane.tsx +9 -240
  31. package/src/ui/components/patterns/presentation.tsx +14 -14
  32. package/src/ui/components/patterns/sidebar.tsx +7 -17
  33. package/src/ui/components/patterns/split.tsx +111 -59
  34. package/src/ui/components/patterns/{surface-header.tsx → structural-header.tsx} +90 -27
  35. package/src/ui/components/patterns/structural-media.tsx +26 -0
  36. package/src/ui/components/patterns/surface-anatomy.ts +71 -61
  37. package/src/ui/components/patterns/surface-assistant.tsx +2 -4
  38. package/src/ui/components/patterns/surface.tsx +620 -0
  39. package/src/ui/components/patterns/trigger.tsx +11 -9
  40. package/src/ui/components/primitives/ask.tsx +155 -83
  41. package/src/ui/components/primitives/button.tsx +11 -9
  42. package/src/ui/components/primitives/checkbox.tsx +8 -8
  43. package/src/ui/components/primitives/command.tsx +1 -1
  44. package/src/ui/components/primitives/composer.tsx +47 -45
  45. package/src/ui/components/primitives/detail.tsx +9 -2
  46. package/src/ui/components/primitives/dialog.tsx +60 -26
  47. package/src/ui/components/primitives/drawer.tsx +58 -12
  48. package/src/ui/components/primitives/icon-picker.tsx +90 -73
  49. package/src/ui/components/primitives/input-group.tsx +35 -28
  50. package/src/ui/components/primitives/input-otp.tsx +16 -16
  51. package/src/ui/components/primitives/input.tsx +20 -10
  52. package/src/ui/components/primitives/item.tsx +9 -12
  53. package/src/ui/components/primitives/menu.tsx +44 -65
  54. package/src/ui/components/primitives/metric-card.tsx +75 -59
  55. package/src/ui/components/primitives/radio-group.tsx +9 -9
  56. package/src/ui/components/primitives/select.tsx +344 -209
  57. package/src/ui/components/primitives/switch.tsx +10 -10
  58. package/src/ui/components/primitives/table.tsx +29 -24
  59. package/src/ui/components/primitives/tabs.tsx +4 -2
  60. package/src/ui/components/primitives/textarea.tsx +6 -6
  61. package/src/ui/components/primitives/toggle-group-context.ts +24 -0
  62. package/src/ui/components/primitives/toggle-group.tsx +116 -74
  63. package/src/ui/components/primitives/toggle.tsx +82 -16
  64. package/src/ui/docs/DocBrowser.tsx +77 -69
  65. package/src/ui/docs/content/action-form-card.md +9 -9
  66. package/src/ui/docs/content/action-list.md +76 -70
  67. package/src/ui/docs/content/action-view.md +33 -18
  68. package/src/ui/docs/content/button.md +1 -1
  69. package/src/ui/docs/content/communication.md +1 -1
  70. package/src/ui/docs/content/compositions.md +479 -0
  71. package/src/ui/docs/content/customization.md +64 -11
  72. package/src/ui/docs/content/detail.md +8 -6
  73. package/src/ui/docs/content/dialog.md +105 -60
  74. package/src/ui/docs/content/drawer.md +68 -22
  75. package/src/ui/docs/content/field.md +14 -15
  76. package/src/ui/docs/content/icon-tile.md +14 -13
  77. package/src/ui/docs/content/page.md +44 -34
  78. package/src/ui/docs/content/pane.md +42 -290
  79. package/src/ui/docs/content/presentation.md +3 -3
  80. package/src/ui/docs/content/separator.md +6 -6
  81. package/src/ui/docs/content/sidebar.md +68 -266
  82. package/src/ui/docs/content/skeleton.md +20 -18
  83. package/src/ui/docs/content/split.md +14 -14
  84. package/src/ui/docs/content/surface.md +513 -0
  85. package/src/ui/docs/content/tabs.md +20 -20
  86. package/src/ui/docs/content/toggle.md +117 -65
  87. package/src/ui/docs/content/tokens.md +124 -40
  88. package/src/ui/docs/registry.tsx +10 -6
  89. package/src/ui/index.ts +30 -27
  90. package/src/ui/meta.ts +15 -27
  91. package/src/ui/react.tsx +40 -43
  92. package/src/ui/theme.css +311 -64
  93. package/src/ui/components/patterns/content-header.tsx +0 -528
  94. package/src/ui/components/patterns/surface-media.tsx +0 -69
  95. package/src/ui/components/primitives/card.tsx +0 -191
  96. package/src/ui/docs/content/card.md +0 -292
  97. 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 [`Content`](/ui/content) com a
97
- [`ActionList`](/ui/action-list), e o cabeçalho desse `Content` recebe o título e os comandos
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 `Content level={1}`, use `heading: "content"`: dentro
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 [`Card`](/ui/card), [`Dialog`](/ui/dialog) ou
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 | 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. |
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 dentro de um layout
1
+ ## Navegação lateral
2
2
 
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
- [`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-80 overflow-hidden rounded-lg border border-border">
8
+ <div className="h-72 overflow-hidden rounded-lg border border-border">
13
9
  <Split>
14
- <Pane initialSize="16rem" inset="none">
10
+ <Pane initialSize="16rem">
15
11
  <Sidebar className="w-full">
16
- <PaneHeader>
17
- <PaneTitle>Projeto</PaneTitle>
18
- </PaneHeader>
19
- <PaneBody>
20
- <SidebarNav
21
- groups={[
22
- {
23
- label: 'Workspace',
24
- items: [
25
- { id: 'overview', label: 'Visão geral', icon: <LayoutDashboard /> },
26
- { id: 'sessions', label: 'Sessões', icon: <MessagesSquare /> },
27
- ],
28
- },
29
- ]}
30
- activeId="overview"
31
- onSelect={() => {}}
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 inset="lg">
40
- <p className="text-sm text-muted-foreground">Conteúdo da página.</p>
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
- ## Compor uma árvore
39
+ ## Regiões próprias
93
40
 
94
- Uma árvore não pertence ao contrato de `SidebarNav`: profundidade, carregamento e expansão variam
95
- por produto. Componha cada nó com `SidebarItem`, envolva seus descendentes em `SidebarTreeGroup` e
96
- mantenha o estado no consumidor. O grupo aplica o recuo e desenha a guia vertical; o destino
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 w-64 overflow-hidden rounded-lg border border-border">
104
- <Sidebar className="w-full">
105
- <PaneBody className="p-2">
106
- <SidebarGroupLabel>Documentação</SidebarGroupLabel>
107
- <SidebarItem
108
- label="Componentes"
109
- icon={<Folder />}
110
- expanded={open}
111
- onToggle={() => setOpen((current) => !current)}
112
- onClick={() => setOpen((current) => !current)}
113
- />
114
- {open && (
115
- <SidebarTreeGroup>
116
- <SidebarItem label="Layout" icon={<Folder />} expanded onToggle={() => {}} onClick={() => {}} />
117
- <SidebarTreeGroup>
118
- <SidebarItem label="Sidebar" icon={<PanelLeft />} active onClick={() => {}} />
119
- <SidebarItem label="Page" icon={<PanelsTopLeft />} onClick={() => {}} />
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
- Esse é o padrão usado pelo `DocBrowser`: seções são rótulos, grupos nomeados são nós expansíveis e
130
- páginas são folhas. Um grupo começa aberto e volta a abrir quando contém a página ativa.
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
- `collapsed` pertence à `Sidebar`. Nesse estado, `SidebarItem` e `SidebarNav` mantêm
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
- O slot de ícone do `SidebarItem` ocupa `1rem` nos dois estados e normaliza SVGs para essa medida.
140
- O consumidor escolhe o símbolo e sua cor sem precisar repetir largura ou altura em ícones SVG.
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
- <div className="flex h-64 overflow-hidden rounded-lg border border-border">
148
- <Sidebar collapsed={collapsed}>
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>
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
- O consumidor controla o estado e decide onde colocar o gatilho. A transição de largura pertence à
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
- | Propriedade | Tipo | Padrão | Descrição |
293
- |---|---|---|---|
294
- | `className` | `string` | | Ajusta o grupo sem substituir o recuo, o espaçamento e a guia vertical padrão. |
295
- | `children` | `ReactNode` | | Itens ou grupos que descendem do nó anterior. |
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
- ## Card em carregamento
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
- `CardHeader` só aceita os próprios slots.
25
+ `SurfaceHeader` só aceita os próprios slots.
26
26
 
27
27
  ```tsx preview col
28
- <Card>
29
- <CardHeader>
30
- <CardTitle asChild>
28
+ <Surface framed elevation="raised">
29
+ <SurfaceHeader>
30
+ <SurfaceTitle asChild>
31
31
  <Skeleton className="h-5 w-40" />
32
- </CardTitle>
33
- </CardHeader>
34
- <CardBody className="space-y-2">
35
- <Skeleton className="h-4 w-56" />
36
- <Skeleton className="h-4 w-full" />
37
- <Skeleton className="h-4 w-3/4" />
38
- </CardBody>
39
- <CardFooter className="gap-2">
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
- </CardFooter>
43
- </Card>
44
+ </SurfaceFooter>
45
+ </Surface>
44
46
  ```
45
47
 
46
48
  ## Propriedades de Skeleton
47
49
 
48
- | Propriedade | Tipo | Padrão | Descrição |
49
- |---|---|---|---|
50
- | `className` | `string` | | Dá forma ao placeholder (`h-4 w-40`, `size-10 rounded-full`); o componente só traz o pulso e o fundo. |
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><Content /></Pane>
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 | 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. |
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. |