@softize/opus 29.0.0 → 31.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/bin/lib/check.mjs +178 -94
  3. package/bin/lib/copy.mjs +2970 -1801
  4. package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +52 -0
  5. package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +27 -2
  6. package/docs/adr/0045-surface-replaces-content-and-card.md +3 -0
  7. package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
  8. package/docs/adr/0062-listas-contidas-e-texto-flexivel.md +68 -0
  9. package/docs/adr/0063-metadados-das-superficies.md +44 -0
  10. package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
  11. package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
  12. package/docs/adr/README.md +8 -0
  13. package/package.json +1 -1
  14. package/registry/skills/build-opus-ui/SKILL.md +21 -19
  15. package/registry/skills/build-opus-ui/references/evaluations.md +21 -10
  16. package/registry/skills/build-opus-ui/references/ui-patterns.md +33 -28
  17. package/src/core/presentation.ts +938 -32
  18. package/src/core/types.ts +2 -1
  19. package/src/ui/components/patterns/form.tsx +2 -0
  20. package/src/ui/components/patterns/grouped-list.ts +2 -2
  21. package/src/ui/components/patterns/list.tsx +588 -365
  22. package/src/ui/components/patterns/page-heading-context.tsx +12 -5
  23. package/src/ui/components/patterns/page.tsx +238 -181
  24. package/src/ui/components/patterns/presentation-fields.tsx +246 -0
  25. package/src/ui/components/patterns/presentation-sections.tsx +494 -0
  26. package/src/ui/components/patterns/presentation.tsx +1142 -229
  27. package/src/ui/components/patterns/structural-header.tsx +47 -34
  28. package/src/ui/components/patterns/surface-anatomy.ts +27 -217
  29. package/src/ui/components/patterns/surface.tsx +55 -37
  30. package/src/ui/components/patterns/trigger.tsx +10 -2
  31. package/src/ui/components/primitives/close-button.tsx +11 -3
  32. package/src/ui/components/primitives/command.tsx +2 -8
  33. package/src/ui/components/primitives/detail.tsx +1 -1
  34. package/src/ui/components/primitives/dialog.tsx +59 -89
  35. package/src/ui/components/primitives/drawer.tsx +52 -87
  36. package/src/ui/components/primitives/field.tsx +1 -1
  37. package/src/ui/components/primitives/pagination.tsx +3 -2
  38. package/src/ui/components/primitives/table.tsx +3 -3
  39. package/src/ui/components/primitives/tabs.tsx +13 -2
  40. package/src/ui/docs/content/action-form.md +2 -1
  41. package/src/ui/docs/content/action-list.md +146 -73
  42. package/src/ui/docs/content/action-trigger.md +5 -0
  43. package/src/ui/docs/content/button.md +5 -6
  44. package/src/ui/docs/content/command.md +62 -50
  45. package/src/ui/docs/content/compositions.md +129 -459
  46. package/src/ui/docs/content/dialog.md +72 -101
  47. package/src/ui/docs/content/drawer.md +69 -92
  48. package/src/ui/docs/content/field.md +2 -1
  49. package/src/ui/docs/content/page.md +207 -386
  50. package/src/ui/docs/content/presentation.md +371 -23
  51. package/src/ui/docs/content/separator.md +1 -1
  52. package/src/ui/docs/content/surface.md +94 -116
  53. package/src/ui/docs/content/table.md +7 -0
  54. package/src/ui/docs/content/tokens.md +18 -4
  55. package/src/ui/drivers/context.tsx +11 -4
  56. package/src/ui/drivers/react.tsx +27 -7
  57. package/src/ui/meta.ts +5 -5
  58. package/src/ui/react.tsx +38 -8
  59. package/src/ui/theme.css +44 -33
@@ -71,3 +71,55 @@ distinguíveis e voltariam a depender de modifiers locais.
71
71
  - primitives neutras usam os mesmos tokens em light e dark, sem receitas locais equivalentes;
72
72
  - testes cobrem a projeção dos tokens e os estados de tabela, toggle, menu e navegação lateral;
73
73
  - a aplicação consumidora é compilada e verificada em páginas com canvas, card, formulário e grid.
74
+
75
+ ## Calibração da navegação — 2026-10-20
76
+
77
+ O fundo `muted` opaco distingue a sidebar no claro, mas dá peso excessivo a essa área extensa
78
+ no escuro. `sidebar` passa a representar a superfície de navegação, com `foreground` para o
79
+ texto: usa `muted` no claro e `control` no escuro, acompanhando os eixos de aparência existentes.
80
+ Os consumidores usam `bg-sidebar`, sem transparência nem ramificações locais por tema.
81
+
82
+ Recalibrar `muted` globalmente alteraria também botões e fundos discretos já aprovados. Manter
83
+ receitas `dark:` nos consumidores duplicaria a decisão. O alias semântico permite ajustar a
84
+ navegação independentemente, sem introduzir outro controle de aparência ou mudar o fundo padrão
85
+ da primitive Sidebar. Os testes de aparência incluem o novo papel nas verificações de contraste
86
+ do texto, e a aplicação verifica as sidebars de Configurações e dos recursos nos dois temas.
87
+
88
+ ## Canvas branco no claro — 2026-10-20
89
+
90
+ O preset claro passa a usar branco puro em canvas, controles, cards e popovers. A calibração
91
+ quase branca anterior separava pouco as superfícies e ainda deixava o fundo geral acinzentado.
92
+ Bordas, espaçamento e elevação continuam distinguindo as regiões; a sidebar mantém seu tom
93
+ próprio. Esta decisão substitui a exigência de diferença de luminosidade entre essas superfícies
94
+ no preset claro. Estados de interação, bordas e tema escuro preservam os valores calibrados.
95
+
96
+ Com o canvas branco, a sidebar clara é recalibrada para luminosidade de 95% no preset,
97
+ 1,5 ponto abaixo de `muted`. Isso reforça a separação da navegação sem alterar os estados
98
+ neutros globais. O token escuro continua no degrau de `control`.
99
+
100
+ ## Navegação interna — referência visual de 19/10/2026
101
+
102
+ A referência fornecida distingue barra global, navegação interna e conteúdo. A calibração
103
+ adotada cobre a navegação interna, quase branca (`#fcfcfc`), sobre conteúdo branco. O fundo da
104
+ sidebar geral permanece como estava, por decisão explícita do produto. `sidebar` fica um ponto
105
+ abaixo do canvas no claro e no degrau de `control` no escuro. Isso substitui a calibração clara
106
+ de 95% acima.
107
+
108
+ No preset claro, a seleção usa `#f0f0f0`. Hover usa um degrau intermediário (`#f4f4f4`) e pressão
109
+ um degrau mais definido (`#e8e8e8`), pois esses estados não estão demonstrados na referência.
110
+ Os tokens de interação continuam compartilhados entre os componentes. O escuro não muda.
111
+ Os testes verificam as superfícies e os estados em conjunto, inclusive a leitura do texto.
112
+
113
+ ## Calibração escura — referência visual de 19/10/2026
114
+
115
+ A referência escura usa conteúdo `#181818`, navegação interna `#1d1d1d`, seleção `#2f2f2f`
116
+ e borda `#363636`. O canvas sobe para 9,4% de luminosidade no preset; a camada elevada fica
117
+ em 11,4% e o controle em 10,4%. A sidebar interna acompanha a camada elevada. Muted, hover,
118
+ seleção e pressão preservam os valores do preset escuro já calibrados.
119
+
120
+ A primeira calibração preservou a base anterior da navegação global. Na validação seguinte,
121
+ o produto definiu que a sidebar geral deve parecer contínua com o fundo, como no light.
122
+ `sidebar-global` passa a acompanhar `background` nos dois temas. O fundo permanece opaco:
123
+ a continuidade vem da igualdade de cor, sem depender de composição alpha. A navegação interna
124
+ mantém seu papel distinto. A primitive Sidebar não impõe fundo; o hospedeiro escolhe o token.
125
+ Os testes cobrem os valores, contraste do texto e a aplicação dos papéis nas duas regiões.
@@ -35,8 +35,11 @@ declara os presets dos dois modos e usa as entradas claras; `.dark` troca para a
35
35
  aplicação pode gravar os dois conjuntos no mesmo elemento, e alternar o tema não exige reaplicar
36
36
  nada.
37
37
 
38
- Com os eixos no preset, a derivação reproduz exatamente os valores calibrados pela ADR 0043. Quem
39
- não personaliza não percebe diferença.
38
+ Na adoção inicial, os presets reproduziam os valores calibrados pela ADR 0043. A calibração de
39
+ 19/10/2026 reforça fundos discretos, estados e bordas no claro, separa `muted` de hover no escuro
40
+ e reforça as bordas escuras. A escala continua opaca e o zero continua sendo o piso: os valores
41
+ salvos dos quatro eixos são preservados, mas passam a atuar sobre a nova calibração. Os valores
42
+ de referência atuais estão em `tests/ui/appearance-tuning.test.ts`.
40
43
 
41
44
  ### Limites
42
45
 
@@ -131,3 +134,25 @@ com os primitives existentes.
131
134
  opacos nos dois temas;
132
135
  - a aplicação consumidora verifica visualmente os extremos de cada eixo em páginas com canvas,
133
136
  card, formulário e grid, nos dois modos.
137
+
138
+ ## Ajuste do preset claro — 2026-10-20
139
+
140
+ Canvas e controle passam a branco puro, acompanhando cards e popovers (emenda da ADR 0043).
141
+ A separação inicial entre essas superfícies é zero no claro; o eixo de camadas continua podendo
142
+ ampliá-la. A base dos estados neutros permanece um ponto abaixo do canvas para preservar a
143
+ calibração de sidebar, muted, interação, borda e texto. O preset escuro permanece igual.
144
+
145
+ ## Calibração escura por referência — 19/10/2026
146
+
147
+ O preset escuro passa a canvas de 9,4%, camada elevada de 11,4% e controle de 10,4%. A base
148
+ mínima do canvas é 5,5%, em vez de preto puro; os eixos ainda só ampliam as separações a partir
149
+ do preset. Os offsets de estado são compensados para manter muted, hover, seleção e pressão.
150
+ Borda fica em 21%. `sidebar-global` acompanha o canvas nos dois temas, conforme a atualização da ADR 0043.
151
+
152
+ ## Redução proporcional do dark — 19/10/2026
153
+
154
+ Após a calibração pela referência, as superfícies, linhas e estados neutros do dark recebem
155
+ um fator final de 0,95 na luminosidade HSL. O fator é aplicado uma única vez na cor resultante,
156
+ sem acumular redução entre canvas, controle e camada. A proporção entre esses valores é
157
+ preservada; texto, primary, contextos semânticos e tema claro ficam inalterados. A calibração
158
+ permanece interna ao tema, sem uma nova preferência pessoal.
@@ -17,6 +17,9 @@
17
17
  `Surface`.
18
18
  - **Não altera:** `Page`, `Dialog`, `Drawer` e `Pane`, que mantêm famílias, slots e mídia próprios.
19
19
 
20
+ A ADR 0063 substitui parcialmente esta decisão: `SurfaceMeta` passa a representar a faixa
21
+ de metadados; o contador na linha do título passa a usar `SurfaceCount`.
22
+
20
23
  ## Contexto
21
24
 
22
25
  Quem monta uma tela precisa delimitar e nomear um trecho dela: uma seção da página, um grupo de
@@ -159,3 +159,145 @@ o título em uma composição inline com quebra, sem criar um novo slot estrutur
159
159
 
160
160
  `contentClassName` em Page e PageBody configura largura e alinhamento internos; `className`
161
161
  controla a moldura e o viewport, respectivamente. Presentation fora do shell preserva largura total.
162
+
163
+ ## Revisão de 16/10/2026 — Page com cabeçalho único
164
+
165
+ A validação no consumidor Grand Brasil substitui o formato com intro de Page: título, ações
166
+ e retorno pertencem ao header fixo; metadados vêm abaixo da linha principal. A Page ocupa
167
+ a largura disponível, usa recuo de 2rem, título de 1,5rem, linha mínima de 2,25rem e ações
168
+ `default`/`icon`. Regiões são sempre seccionadas. Drawer, Dialog e Surface mantêm as opções
169
+ existentes e controles compactos. A separação entre `flow` e `fill` continua governando
170
+ rolagem, sem alterar a anatomia.
171
+
172
+ `PageBack` é uma ação de ícone com destino explícito e tooltip, primeira na região de ações.
173
+ Breadcrumb não compõe a Page. A composição antiga de intro/navegação não é o caminho
174
+ canônico e os consumidores devem migrar para PageHeader; Presentation gera a mesma estrutura.
175
+ A alternativa de classes por consumidor foi descartada por repetir o contrato visual.
176
+ Testes de Page, Presentation e anatomia cobrem medidas, heading único, retorno, estados
177
+ integrais e preservação dos modais.
178
+
179
+ Experimento local após a revisão: Page usa recuo de 1rem nas regiões, igual aos modais
180
+ seccionados. O título também usa 1,125rem, como nos headers de Drawer e Dialog. As ações
181
+ mantêm o tamanho normal de Page.
182
+
183
+ Ajuste local seguinte: os cabeçalhos de Page, Drawer, Dialog e Surface compartilham
184
+ ações `default`/`icon` e linha mínima de 2,25rem. O fechamento nativo dos modais usa
185
+ a mesma escala; `closeSize` mantém as opções menores para composições explícitas.
186
+
187
+ ### Experimento de abas no cabeçalho
188
+
189
+ Para manter a navegação entre painéis visível enquanto o corpo rola, os headers de
190
+ Page, Drawer, Dialog e Surface aceitam `tabs`, contendo um `TabsList` do Tabs existente.
191
+ A região entra abaixo da linha de título e ações, com o mesmo alinhamento lateral.
192
+ O divisor inferior pertence ao header; a lista de abas não acrescenta outra linha.
193
+ O estado, as relações ARIA e o teclado continuam no Tabs que envolve a superfície.
194
+
195
+ Manter as abas no body exigiria repetir posicionamento e recuos em cada consumidor.
196
+ Criar outro controlador duplicaria o contrato de Tabs. A região opcional no header
197
+ é reversível e mantém a composição sem abas inalterada. Alertas e legendas de fieldset
198
+ não aceitam essa navegação. O piloto é E-mails; testes verificam troca de painel,
199
+ semântica, ausência de divisor duplicado e preservação da composição sem abas.
200
+
201
+ O piloto separa ações gerais de ações da aba: `tabsActions` ocupa o extremo oposto
202
+ a `tabs` na mesma faixa, sem participar do tablist. A região exige `tabs` e mantém
203
+ os botões no fluxo normal de foco, com a mesma escala dos demais headers.
204
+
205
+ ### Ações das coleções
206
+
207
+ Ações que afetam a coleção pertencem à toolbar do ActionList, inclusive criação,
208
+ mesmo quando não dependem do recorte atual. Cabeçalhos preservam as ações gerais
209
+ da superfície. Presentation ganha o placement explícito `toolbar`, válido apenas
210
+ quando seu body declara uma action list; `header` continua significando o header.
211
+ O comando pode declarar `label` para a apresentação contextual, sem renomear o
212
+ contrato nem o formulário de destino. A criação pode assim exibir “Criar”. A validação
213
+ rejeita toolbar em bodies sem lista, e o renderer deve manter header e toolbar distintos.
214
+
215
+ ## Consolidação de 18/10/2026 — anatomia única
216
+
217
+ A validação da aplicação substitui a escolha entre composição compacta e intro por um
218
+ cabeçalho único em Page, Dialog, Drawer e Surface. Título, descrição opcional, metadados e
219
+ operações gerais pertencem ao Header; o Body contém o conteúdo. As exportações Intro e
220
+ IntroActions dos modais são removidas, assim como `SurfaceLayout`, `surfaceLayout` da Page
221
+ e `layout` visual de Surface, DialogContent e DrawerContent. Não há alias de compatibilidade.
222
+ `Page.layout="flow" | "fill"` permanece: governa rolagem, não aparência.
223
+
224
+ As regiões derivam seus divisores da vizinhança. Superfícies delimitadas usam recuo de 1rem
225
+ em header, body e footer; a Surface sem moldura mantém alinhamento com o hospedeiro e ritmo
226
+ de 1rem entre as regiões. A linha de cabeçalho reserva 2,25rem e ações usam tamanho normal.
227
+ A semântica de alerta do Dialog continua própria: exige uma resposta e não é uma opção de
228
+ densidade visual. Fieldset mantém legend nativa, em faixa quando delimitado.
229
+
230
+ As abas pertencem ao header e os comandos de coleção à barra da lista. `tabsActions`, criado
231
+ no experimento, é removido. Comandos de linha e seleção preservam seus slots. Exemplos,
232
+ metadata, regras do checker e consumidores migram juntos; testes verificam API removida,
233
+ regiões, foco, rolagem e criação contextual. Manter modos antigos foi descartado porque
234
+ permitiria reintroduzir a divergência que motivou a revisão.
235
+
236
+ A Surface sem moldura não acrescenta padding nem divisor entre regiões: o intervalo é
237
+ 1rem, alinhado ao hospedeiro. Fieldset sem moldura mantém legend sem sublinhado. Abas
238
+ integradas conservam sua própria linha de seleção, encostada na base do Header.
239
+ Surface nível 1 continua disponível fora da Page; dentro dela, seções são subordinadas
240
+ e o título principal pertence ao PageHeader, ou ao PageState integral ativo.
241
+
242
+
243
+ ## Piloto: composição de documento
244
+
245
+ A avaliação visual em Segurança reabre a escolha de composição sem reintroduzir Intro.
246
+ `Page composition="document"` reúne Header, Body e Footer em uma coluna central de até
247
+ 56rem, com recuo externo de 1rem nas laterais e 2,5rem na vertical. A Page inteira rola
248
+ na borda disponível; título e conteúdo seguem juntos, sem divisor entre as regiões.
249
+ `composition="standard"` preserva o cabeçalho fixo e o corpo em toda a largura.
250
+ A opção visual é independente de `layout`, que continua indicando ocupação; documento
251
+ aceita somente `flow`, pois não delega rolagem a uma lista ou canvas interno.
252
+
253
+ A Presentation encaminha `pageComposition` à Page que possui ou à Page do conteúdo.
254
+ O piloto na aplicação fica restrito a Segurança, sem publicação nem propagação antes da
255
+ avaliação visual. A escolha geral de divisores (`sectioned`) permanece em reavaliação;
256
+ este piloto não restaura essa API nem altera Drawer e Dialog.
257
+
258
+ ## Experimento: largura independente da composição — 2026-10-18
259
+
260
+ Preferências curtas precisam de uma coluna menor, enquanto tabelas precisam aproveitar a área
261
+ central. A Page aceita `width="narrow" | "default" | "wide"`: limites de 42rem, 58rem ou toda a
262
+ largura disponível. O limite envolve header, body e footer juntos, preservando seu alinhamento e
263
+ padding. Sem largura explícita, documento conserva default e a composição standard conserva wide.
264
+ A declaração serializável usa `page.width`; a prop width externa da Presentation continua exclusiva
265
+ do dimensionamento de diálogos. A contribuição do shell repassa a largura à Page do consumidor.
266
+ A alternativa de classes particulares por tela foi descartada para manter três escolhas revisáveis.
267
+ Segurança e Conversas exercitam os extremos; E-mails conserva a largura intermediária.
268
+
269
+ Na avaliação seguinte, a composição document passa a usar padding uniforme de 2,5rem.
270
+ O limite da coluna continua incluindo esse padding. A composição standard preserva 1rem,
271
+ assim como Drawer e Dialog; o recuo depende da composição, não da largura escolhida.
272
+
273
+ ## Correção: documento também pode preencher a altura — 2026-10-18
274
+
275
+ Conversas revelou que a composição document não deve obrigar uma listagem a crescer na página.
276
+ Ela passa a aceitar `layout="fill"`: mantém título, ausência de divisor e padding aberto, mas
277
+ limita a coluna à altura disponível e entrega a rolagem aos resultados da ActionList. O padrão
278
+ flow continua rolando título e conteúdo juntos. Isso substitui a restrição inicial do piloto;
279
+ composição visual e ocupação de altura são escolhas independentes.
280
+
281
+ ## Consolidação: uma aparência de Page — 2026-10-18
282
+
283
+ A avaliação concluiu que standard e document eram duas aparências para a mesma anatomia,
284
+ sem usos distintos que justificassem a escolha em cada tela. A Page adota o visual aberto:
285
+ padding de 2,5rem, título de 1,875rem, intervalo de 1,5rem após o cabeçalho e
286
+ 1rem entre as demais regiões, sem divisores. Removem-se composition,
287
+ pageComposition e page.composition, sem aliases. Header, Body e Footer permanecem.
288
+
289
+ Largura e ocupação continuam independentes: width narrow/default/wide e layout flow/fill.
290
+ A largura omitida é wide, preservando o espaço das listagens existentes; os antigos documentos
291
+ intermediários passam a declarar width default. Flow rola o conjunto; fill reserva altura para
292
+ a região interna. Drawer e Dialog continuam delimitados, com seu padding de 1rem.
293
+ A migração cobre consumidores e projeções; testes verificam herança da largura, fill e a anatomia
294
+ única. Essa decisão substitui os dois tratamentos visuais dos experimentos anteriores.
295
+
296
+ ## Seções e cabeçalhos declarados em Configurações — 2026-10-18
297
+
298
+ A adoção em toda a área de Configurações exige manter widgets com comportamento específico sem
299
+ transferir a página inteira para body.component. Seções de conteúdo referenciam slots nomeados;
300
+ seções de lista podem apresentar tabela ou itens por um adaptador tipado do contrato. Cabeçalho
301
+ aceita referências a título dinâmico, metadados e ações, mantendo os slots nativos de cada superfície.
302
+ Page.layout pode ser declarado junto de width. O runtime contém callbacks e dados, nunca código
303
+ serializado. Referências ausentes falham antes da montagem; o JSON não aceita funções ou HTML.
@@ -0,0 +1,68 @@
1
+ # ADR 0062 — Listas contidas e texto flexível
2
+
3
+ Data: 2026-10-15
4
+ Status: Aceita
5
+
6
+ ## Contexto
7
+
8
+ Descrições sem quebra faziam uma tabela de Habilidades ocupar 92,21rem dentro de
9
+ 63,13rem disponíveis. A coluna implícita do grid de resultados do ActionList
10
+ crescia pelo conteúdo; o contêiner da tabela crescia junto e não oferecia sua
11
+ rolagem horizontal. A largura mínima da página não limita a largura dos filhos.
12
+
13
+ ## Decisão
14
+
15
+ Table contém sua largura e quebra texto entre palavras por padrão. `overflow-wrap:
16
+ break-word` preserva a largura intrínseca das palavras, evitando que uma descrição
17
+ comprida faça uma coluna como “Inativo” quebrar no meio. Identificadores sem espaços
18
+ podem exigir rolagem interna; `wrap-anywhere` fica disponível como opção explícita.
19
+ Classes explícitas continuam permitindo
20
+ células sem quebra. ActionList limita sua coluna de resultados ao espaço
21
+ recebido e permite encolhimento ao longo da cadeia de flex/grid.
22
+
23
+ `fit` preserva valores compactos sem quebra, como números e datas. O cabeçalho
24
+ de uma coluna declarada pode quebrar entre palavras. Textos flexíveis recebem o
25
+ restante do espaço. Não há redução de tipografia nem ocultação automática de colunas.
26
+
27
+ A barra de filtros pode ocupar mais de uma linha, mantendo a ordem dos controles.
28
+ Uma tabela que ainda exceda a largura disponível rola dentro da lista: em flow,
29
+ no contêiner da tabela; em fill, na região de resultados que também ancora o
30
+ cabeçalho fixo. O rodapé e a toolbar não acompanham essa rolagem.
31
+
32
+ ## Alternativas e consequências
33
+
34
+ Largura fixa e repartição igual sacrificariam espaço das colunas textuais mesmo
35
+ quando controles curtos não precisam dele. Ocultar o excesso perderia dados e
36
+ ações. Regras CSS no aplicativo duplicariam o comportamento do pacote.
37
+
38
+ A quebra pode aumentar a altura das linhas. Consumidores com células compostas
39
+ continuam responsáveis por permitir encolhimento dos filhos flex e por declarar
40
+ larguras mínimas somente quando necessárias. Comparativos com colunas mínimas
41
+ explícitas continuam usando rolagem horizontal.
42
+
43
+ ## Verificação
44
+
45
+ Testes em Chromium medem contenção, textos longos, filtros, valores compactos e
46
+ rolagem nos modos flow e fill, incluindo a posição do cabeçalho após rolar.
47
+ Os testes estão em `tests/browser/action-list-width.test.tsx` e cobrem também
48
+ palavras curtas ao lado de descrições longas e tokens sem espaços.
49
+
50
+ ## Revisão da distribuição entre colunas — 2026-10-15
51
+
52
+ Na validação de Consumo, quatro colunas `fit` ficavam comprimidas enquanto a coluna
53
+ textual recebia cerca de 70% da largura. A largura mínima forçada fazia o navegador
54
+ quebrar títulos mesmo com espaço disponível. Retirar essa restrição reduziu a coluna
55
+ textual para cerca de 38% e acomodou os cabeçalhos numa linha, no mesmo contêiner.
56
+
57
+ Colunas de dados passam a participar da distribuição automática da tabela, considerando
58
+ cabeçalhos e valores. `fit` continua preservando valores sem quebra, mas não impõe
59
+ largura mínima artificial. Cabeçalhos podem quebrar quando o espaço realmente faltar.
60
+ Seleção, ações de linha e células contendo apenas um switch continuam compactas.
61
+ O switch pode ser filho direto ou estar envolvido pelo TooltipTrigger. A regra usa a
62
+ estrutura do controle, sem depender do nome da coluna; células com conteúdo misto
63
+ continuam participando da distribuição natural.
64
+
65
+ Não se distribui largura igualmente nem se mede texto em JavaScript. O algoritmo
66
+ nativo considera o conteúdo e o espaço recebido; a contenção e a rolagem descritas
67
+ acima permanecem. Os testes de navegador cobrem várias colunas numéricas ao lado de
68
+ texto, tanto com espaço suficiente quanto em contêiner estreito, em flow e fill.
@@ -0,0 +1,44 @@
1
+ # ADR 0063 — Metadados das superfícies em região própria
2
+
3
+ - **Status:** aceita.
4
+ - **Data:** 2026-10-15.
5
+ - **Complementa:** ADR 0060.
6
+ - **Substitui parcialmente:** ADR 0045 quanto à posição e função de SurfaceMeta.
7
+
8
+ ## Contexto
9
+
10
+ Badges, autoria e datas disputam espaço com o título ou usam o subheading como container.
11
+ A descrição é orientação textual próxima ao heading; metadados precisam de espaçamento
12
+ próprio e quebra de linha sem alterar o tamanho ou o significado do título.
13
+
14
+ ## Decisão
15
+
16
+ PageMeta, DrawerMeta, DialogMeta e SurfaceMeta compõem uma faixa opcional após a linha
17
+ que contém título, descrição e ações. Não são headings nem descrições acessíveis dos modais.
18
+ As três primeiras famílias aceitam Meta em Intro ou Header compacto; Surface mantém
19
+ Meta em SurfaceHeader, pois não possui Intro. Meta exige título na mesma composição.
20
+ Dialog em modo de alerta não aceita Meta; informações necessárias à resposta pertencem ao corpo.
21
+
22
+ O intervalo superior é de 0,75rem; itens usam 0,75rem na horizontal e 0,5rem entre linhas.
23
+ A faixa permite quebra, conserva a tipografia dos badges e não insere separadores nem
24
+ busca dados. Sem Meta não há espaço reservado. Uma composição aceita no máximo um Meta.
25
+ As formas curtas de Page e Surface aceitam a prop meta. Fieldset preserva a legend
26
+ restrita a título e mídia decorativa; seus metadados pertencem ao corpo.
27
+
28
+ SurfaceCount preserva o contador ao lado do título e recebe count na forma curta.
29
+ SurfaceMeta deixa de ocupar essa posição: consumidores de contadores explícitos migram
30
+ para SurfaceCount. Consumidores de contexto editorial permanecem em SurfaceMeta.
31
+
32
+ ## Alternativas
33
+
34
+ Usar Description conservaria a mistura de prosa e metadados. Colocar wrappers livres no
35
+ Body repetiria espaçamento nos consumidores e afastaria o contexto da identidade. Manter
36
+ SurfaceMeta como contador faria o mesmo nome expressar funções diferentes entre famílias.
37
+
38
+ ## Verificação
39
+
40
+ Testes renderizados e checker cobrem posição, unicidade, pai permitido e título obrigatório.
41
+ Contadores permanecem ao lado do título. Testes no navegador conferem intervalo e quebra
42
+ nas famílias, incluindo headers compactos com ações. As evidências pertencem aos arquivos
43
+ `tests/ui/surface-meta.test.tsx`, `tests/browser/surface-meta.test.tsx` e
44
+ `tests/check/check.test.ts`. Publicação e adoção dependem de autorização de entrega.
@@ -0,0 +1,47 @@
1
+ # ADR 0064 — ActionList apresenta itens e conecta fontes externas
2
+
3
+ - **Status:** experimental, piloto local em Segurança.
4
+ - **Data:** 2026-10-18.
5
+
6
+ ## Contexto
7
+
8
+ Coleções pequenas em Configurações usam ItemGroup com título, descrição e ações por item.
9
+ ActionList já governa consulta, erro, vazio e paginação, mas exige uma função React para
10
+ esse visual. Sessões pertencem ao IdP e não devem ganhar endpoint ou contrato de negócio
11
+ paralelo apenas para reutilizar a lista.
12
+
13
+ ## Decisão
14
+
15
+ ActionList recebe `item: { title, description? }`, cujos valores são nomes de campos do
16
+ resultado. O objeto é serializável; a renderização usa ItemGroup, Item e separadores do
17
+ catálogo. `rowActions` também atende itens. `title` nomeia a coleção e suas
18
+ `toolbarActions` ficam junto dele; filtros continuam em sua própria barra quando existem.
19
+ As ações podem receber contexto de resultados e refetch, sem uma consulta duplicada.
20
+ Uma lista em itens esconde o rodapé quando há somente uma página, mas mantém o paginador
21
+ quando há mais resultados. Tabelas e composições existentes conservam seu comportamento.
22
+
23
+ A origem continua sendo uma action por padrão. A alternativa explícita `source` recebe
24
+ uma chave de cache com escopo e um loader que retorna o envelope paginado. É um adaptador
25
+ runtime de fonte externa, não uma action nem um endpoint. A consulta usa o mesmo mecanismo
26
+ de cache e estados do driver. Fontes externas não mantêm cache após desmontar a lista e
27
+ não herdam o transporte Opus. O adapter declara paginação real sobre o conjunto recebido;
28
+ a UI nunca esconde registros para simular uma única página.
29
+
30
+ No piloto, a fonte chama o cliente Better Auth existente e projeta somente identificador,
31
+ nome do dispositivo e data formatada para a lista. Tokens ficam na closure do adapter para
32
+ revogação, fora dos itens, do DOM, do cache da lista e de declarações JSON. Operações e
33
+ permissões continuam no IdP. A fonte e callbacks não são serializáveis: a futura composição
34
+ JSON deverá referenciá-los por registro, sem embutir funções ou credenciais.
35
+
36
+ ## Alternativas
37
+
38
+ - Uma função children resolve o visual hoje, mas repete anatomia e impede declarar os campos.
39
+ - Uma action de sessões paralela duplicaria a fronteira de autenticação.
40
+ - Uma coleção inteiramente nova repetiria estados, paginação e invalidação do ActionList.
41
+
42
+ ## Verificação
43
+
44
+ Testar consulta por action e fonte externa, estado inicial, erro e recuperação, vazio,
45
+ ações por item, atualização, paginação e remoção na última página. No piloto, testar
46
+ revogação com o cliente do IdP simulado e inspecionar o visual na rota real sem encerrar
47
+ sessões de outras pessoas. O modo de tabela mantém suas regressões existentes.