@softize/opus 30.0.0 → 31.1.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 (64) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/bin/lib/check.mjs +109 -101
  3. package/bin/lib/copy.mjs +2973 -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/0060-surface-composition-separates-chrome-and-intro.md +142 -0
  7. package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
  8. package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
  9. package/docs/adr/0066-civil-date-input-and-calendar-list.md +28 -0
  10. package/docs/adr/README.md +6 -0
  11. package/package.json +1 -1
  12. package/registry/skills/build-opus-ui/SKILL.md +21 -19
  13. package/registry/skills/build-opus-ui/references/evaluations.md +13 -11
  14. package/registry/skills/build-opus-ui/references/ui-patterns.md +24 -27
  15. package/src/core/presentation.ts +938 -32
  16. package/src/core/types.ts +2 -0
  17. package/src/ui/components/patterns/form.tsx +22 -1
  18. package/src/ui/components/patterns/grouped-list.ts +2 -2
  19. package/src/ui/components/patterns/list-calendar.tsx +129 -0
  20. package/src/ui/components/patterns/list.tsx +612 -382
  21. package/src/ui/components/patterns/page-heading-context.tsx +12 -5
  22. package/src/ui/components/patterns/page.tsx +227 -197
  23. package/src/ui/components/patterns/presentation-fields.tsx +246 -0
  24. package/src/ui/components/patterns/presentation-sections.tsx +494 -0
  25. package/src/ui/components/patterns/presentation.tsx +1142 -229
  26. package/src/ui/components/patterns/structural-header.tsx +23 -32
  27. package/src/ui/components/patterns/surface-anatomy.ts +27 -217
  28. package/src/ui/components/patterns/surface.tsx +19 -29
  29. package/src/ui/components/patterns/trigger.tsx +10 -2
  30. package/src/ui/components/primitives/calendar.tsx +39 -18
  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/date-input.tsx +276 -0
  34. package/src/ui/components/primitives/detail.tsx +1 -1
  35. package/src/ui/components/primitives/dialog.tsx +19 -81
  36. package/src/ui/components/primitives/drawer.tsx +17 -79
  37. package/src/ui/components/primitives/field.tsx +1 -1
  38. package/src/ui/components/primitives/pagination.tsx +3 -2
  39. package/src/ui/components/primitives/table.tsx +1 -1
  40. package/src/ui/components/primitives/tabs.tsx +13 -2
  41. package/src/ui/docs/content/action-form.md +6 -1
  42. package/src/ui/docs/content/action-list.md +156 -68
  43. package/src/ui/docs/content/action-trigger.md +5 -0
  44. package/src/ui/docs/content/button.md +5 -6
  45. package/src/ui/docs/content/calendar-month-view.md +50 -0
  46. package/src/ui/docs/content/calendar.md +6 -1
  47. package/src/ui/docs/content/command.md +62 -50
  48. package/src/ui/docs/content/compositions.md +129 -459
  49. package/src/ui/docs/content/date-input.md +67 -0
  50. package/src/ui/docs/content/dialog.md +44 -112
  51. package/src/ui/docs/content/drawer.md +44 -103
  52. package/src/ui/docs/content/field.md +2 -1
  53. package/src/ui/docs/content/input.md +3 -0
  54. package/src/ui/docs/content/page.md +204 -412
  55. package/src/ui/docs/content/presentation.md +371 -23
  56. package/src/ui/docs/content/separator.md +1 -1
  57. package/src/ui/docs/content/surface.md +65 -120
  58. package/src/ui/docs/content/tokens.md +18 -4
  59. package/src/ui/docs/registry.tsx +38 -9
  60. package/src/ui/drivers/context.tsx +11 -4
  61. package/src/ui/drivers/react.tsx +27 -7
  62. package/src/ui/meta.ts +17 -6
  63. package/src/ui/react.tsx +41 -8
  64. 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.
@@ -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,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.
@@ -0,0 +1,295 @@
1
+ # ADR 0065 — Presentation compõe seções declaradas
2
+
3
+ - **Status:** implementado localmente; ainda não publicado.
4
+ - **Data:** 2026-10-18.
5
+
6
+ ## Contexto
7
+
8
+ A composição centralizada e a lista em itens foram validadas visualmente, mas a definição
9
+ publicável ainda conhece somente o título da página e uma boundary React opaca. Para migrar
10
+ Configurações gradualmente, a definição precisa descrever a estrutura sem incorporar funções,
11
+ credenciais ou uma segunda implementação do serviço de autenticação.
12
+
13
+ ## Decisão
14
+
15
+ Estender Presentation com `page.composition` e a alternativa `body.sections`. O piloto suporta
16
+ seções de itens estáticos e listas em itens conectadas a um adaptador externo registrado.
17
+ Títulos, descrições, ordem, campos da lista e mensagens de consulta pertencem ao JSON. Cada
18
+ seção tem id estável; a lista continua sendo renderizada por ActionList. A composição usa
19
+ Surface e ItemGroup existentes e preserva o ritmo e o visual aprovados.
20
+
21
+ Operações e conteúdo específico são extensões nomeadas no runtime: slots React para ações,
22
+ valores, feedback e overlays; adaptadores tipados para fontes externas e suas ações por item
23
+ ou coleção. Slots ausentes são erros, enquanto slots registrados com null são estados válidos.
24
+ Os adaptadores são código confiável do consumidor, nunca expressões ou imports obtidos do JSON.
25
+ A definição é publicável, mas essas extensões continuam dependentes do renderer registrado.
26
+
27
+ O piloto não cria um motor genérico de formulários ou expressões. Forms, views e listas de
28
+ actions continuam usando body.action. Abas e demais configurações serão avaliadas nos próximos
29
+ pilotos. body.component permanece uma extensão válida. O schemaVersion 1 recebe uma extensão
30
+ aditiva ainda local; consumidores antigos não interpretam sections e precisam ser atualizados
31
+ antes de adotar uma definição que a utilize.
32
+
33
+ ## Alternativas e consequências
34
+
35
+ Manter uma única boundary React não permitiria inspecionar a composição. Serializar JSX ou
36
+ callbacks confundiria conteúdo declarativo com execução. Criar actions fictícias para o IdP
37
+ violaria a fronteira existente. O modelo escolhido expõe as partes portáveis e nomeia cada
38
+ extensão, mantendo a migração reversível por página.
39
+
40
+ ## Verificação
41
+
42
+ Testar serialização e validação de ids, propriedades desconhecidas e campos inválidos; renderizar
43
+ uma definição reconstruída de JSON; falhar diante de extensões ausentes; preservar estados da
44
+ lista, comportamento de senha e revogação. O inventário de copy deve encontrar textos de seções
45
+ e itens sem tratar ids de adaptadores ou nomes de campos como linguagem humana.
46
+
47
+ ## Segundo piloto: CRUD de Unidades
48
+
49
+ Uma família de Presentations declara a lista, a criação e a edição com rotas próprias.
50
+ A página usa `page.composition: document`; formulários continuam Dialog e derivam campos,
51
+ validação, execução e invalidação dos contratos. Comandos `placement: row` declaram ações
52
+ por item, bindings e destino; exclusão delega confirmação e execução ao ActionTrigger.
53
+ Nesse recorte, bloqueio de comando por linha é sempre `action`, isolado por item.
54
+
55
+ `body.cells` referencia um adaptador tipado, vinculado ao nome da list action. Ícones dos
56
+ comandos de linha são referências ao registro runtime, sem importar uma biblioteca inteira.
57
+ A API `bindPresentationCells` preserva a tipagem do item no consumidor; o renderer confere
58
+ que o adaptador pertence à action antes de consultar. O switch Ativo permanece nessa
59
+ extensão e usa a operação já existente. Reimplementar o switch e os ícones em uma linguagem
60
+ arbitrária de expressões foi descartado: os contratos e componentes atuais já os resolvem.
61
+
62
+ O piloto mantém o mecanismo existente de lookup do registro pela primeira página sem
63
+ recorte. Um deep link fora dela continua exibindo ausência explícita; a migração não cria
64
+ uma operação de consulta por id. A composição declarativa não altera permissões de servidor.
65
+ Testes cobrem criar, editar, cancelar, validar, ativar/desativar e excluir com confirmação,
66
+ além de referências de linha incompatíveis e ausência de adaptadores.
67
+
68
+ ## Terceiro piloto: abas de E-mails
69
+
70
+ `body.tabs` declara ids, rótulos, ícones registrados, conteúdos nomeados e rotas opcionais;
71
+ `defaultTab` identifica a aba inicial e `tabLabel` nomeia a navegação acessível. A composição
72
+ usa Tabs e os slots de abas nativos dos headers de Page, Dialog e Drawer. O runtime pode
73
+ controlar a seleção para sincronizá-la com a URL; sem controle, vale o estado local.
74
+ As rotas são metadados consumidos pelo roteador da aplicação, sem imports ou execução no JSON.
75
+ Ids duplicados e aba inicial inexistente são inválidos. Conteúdos e ícones ausentes falham
76
+ antes de montar as consultas; apenas o painel ativo monta seu conteúdo.
77
+
78
+ E-mails adota a composição document. Envios, Remetentes e Modelos mantêm seus componentes
79
+ registrados, contratos, permissões, confirmações e formulários. Este passo declara a estrutura
80
+ das abas, não converte os comportamentos específicos em uma linguagem de expressões.
81
+ Testes verificam seleção, montagem do painel ativo, referências ausentes, ida e volta pela URL,
82
+ links de formulários e ausência de controles administrativos para quem tem somente leitura.
83
+
84
+ ## Consolidação: páginas declarativas como destino
85
+
86
+ A composição híbrida é uma etapa de migração, não o destino. E-mails deixa de registrar
87
+ conteúdos opacos por aba: cada aba referencia outra Presentation. O host resolve navegação,
88
+ área e permissões; a estrutura e as operações permanecem no artefato serializável.
89
+
90
+ O protocolo recebe recursos finitos necessários ao comportamento existente: apresentação
91
+ embutida, destino pai de rotas, exigência de permissão, condições de linha por comparação,
92
+ confirmação específica, células textuais ou switch de action, lookups de formulário e formatos
93
+ de view (texto, texto pré-formatado e HTML isolado). Não há eval, expressão JavaScript, import
94
+ arbitrário ou handler serializado. HTML usa iframe sem permissões e CSP que bloqueia recursos
95
+ externos, preservando a proteção da prévia anterior.
96
+
97
+ O renderer reutiliza ActionList, ActionForm, ActionView, ActionTrigger e seus drivers. Condições
98
+ visuais não concedem autorização; o servidor mantém os guards dos contratos. A seleção de abas
99
+ e formulários por URL pertence ao host genérico. Formulários de edição preservam defaults do
100
+ registro, ocultando campos conforme a metadata dos contratos. A recuperação por listagem mantém
101
+ a limitação conhecida à primeira página, explicitando ausência ou falha de consulta.
102
+
103
+ Critério de aceite: remover os quatro componentes específicos de E-mails sem movê-los para
104
+ slots equivalentes. Testar artefato reconstruído de JSON, navegação, permissões, confirmação de
105
+ risco de duplicidade, publicação, ativação, envio de teste e isolamento de HTML. Extensões
106
+ runtime continuam admitidas para necessidades reais, com exceção explícita; não contam como
107
+ migração completa de uma página.
108
+
109
+ ## Ampliação para Configurações — 18/10/2026
110
+
111
+ A estrutura das demais configurações usa as mesmas seções, sem wrappers de página opacos.
112
+ Controles próprios usam seções `content`; itens declaram associação acessível e posição do controle.
113
+ Listas de actions podem usar adaptadores tipados, preservando filtros e células existentes.
114
+ Cabeçalhos aceitam referências a dados dinâmicos, e a página transporta largura e layout.
115
+ O painel de teste do agente ocupa uma coluna declarada, com rolagem independente do conteúdo.
116
+ Abas podem referenciar tanto actions quanto seções; referências a componentes opacos continuam
117
+ reprovadas nessa modalidade. Loading, falha e ausência podem substituir o corpo temporariamente.
118
+ A autorização permanece nos contratos; as extensões não executam código vindo do JSON.
119
+
120
+ ## Arquivo autoral JSON e acesso — 18/10/2026
121
+
122
+ Declarações podem residir em `presentations/*.json`, importadas por registros estáticos e validadas
123
+ por `presentationSchema.parse`. O inventário de copy descobre esses arquivos e usa as mesmas regras
124
+ semânticas das declarações TypeScript, preservando caminho, linha e hash do JSON. JSON inválido
125
+ produz diagnóstico; não há execução de código ou resolução de imports a partir do documento.
126
+
127
+ O renderer herda `requires` do contrato da action para o corpo, comandos, destinos e switches.
128
+ A declaração pode adicionar uma restrição, mas não substituir a exigência do contrato. Uma lista
129
+ de permissões usa alternativas, conforme a semântica de `requires` nas actions; lista vazia é
130
+ inválida. Sem callback `can`, uma exigência explícita é negada. `canAccessPresentation` permite
131
+ que o roteador consumidor confira essa mesma regra antes de buscar um registro por URL.
132
+
133
+ A autorização efetiva continua em `authorize`. Condições de linha (`when`, como `canEdit` devolvido
134
+ pelo servidor) complementam essa avaliação, sem presumir acesso a um registro apenas pela área.
135
+
136
+ ## Detalhe local de coleção — 18/10/2026
137
+
138
+ Uma lista pode declarar `body.inspect` para abrir um detalhe especializado sem alterar a URL.
139
+ Esse destino referencia um adaptador estático vinculado ao mesmo contrato da lista, recebe o item
140
+ e um callback de fechamento. O renderer mantém a seleção e só monta o detalhe após o clique.
141
+ É uma alternativa exclusiva a `open`/`opens`, que continuam responsáveis por destinos roteados.
142
+ Permissão e condições de linha são verificadas ao abrir e ao renderizar; a autorização dos dados
143
+ continua nas actions do detalhe. Registro ausente ou contrato incompatível falha antes da consulta.
144
+
145
+ O caso atende transcrições de conversas e payloads de auditoria: conteúdos especializados legítimos,
146
+ sem manter um wrapper por página para seleção, filtros ou estado de abertura. Não adiciona imports
147
+ ou funções ao JSON nem converte um detalhe especializado em uma página opaca.
148
+
149
+ ## Opções de vínculos — 18/10/2026
150
+
151
+ Lookups de formulário podem declarar opções estáticas anteriores às consultadas (como “Todas as
152
+ unidades”) e um formatador de opção registrado e vinculado à list action. Isso preserva rótulos
153
+ compostos e a indicação de cadastros inativos sem mover os formulários de volta para JSX. O JSON
154
+ continua declarando campos, consultas, defaults, comandos e destinos. O formatador só projeta uma
155
+ linha em opção; não busca dados nem executa commands. O renderer verifica registro/contrato antes
156
+ de consultar e respeita o `requires` da action do lookup. Filtros iniciais de coleção usam a mesma
157
+ API `filterDefaults` do ActionList e não sobrescrevem filtros explícitos da URL.
158
+
159
+ A hidratação de detalhes roteados reutiliza `listStateToInput`, a mesma materialização que o
160
+ ActionList usa para consultar. O host conserva canal, busca, ordenação e página ao abrir o formulário;
161
+ a fonte de registro continua respeitando seu próprio contrato. Um link sem recorte ainda depende
162
+ da página padrão da consulta, e o estado de ausência deve explicitar essa limitação.
163
+
164
+ ## Campos especializados — 18/10/2026
165
+
166
+ `body.fieldComponents` associa campos de formulário a adaptadores registrados, vinculados à
167
+ action e ao campo por `bindPresentationField`. O componente monta dentro de ActionForm e usa
168
+ seu contexto; validação, envio, erros, footer e efeitos permanecem no formulário compartilhado.
169
+ O registro rejeita campo inexistente, colisão com lookup e adaptador de outro contrato antes
170
+ de montar controles. Não há imports nem funções no JSON.
171
+
172
+ O primeiro consumidor é o questionário de motivos de perda: a estrutura variável das perguntas
173
+ exige controles próprios, enquanto cadastro, edição, ativação e navegação seguem declarativos.
174
+ Testes devem provar que o componente altera os dados submetidos, que o schema rejeita conteúdo
175
+ inválido e que uma permissão negada impede a montagem do editor.
176
+
177
+ Coleções com totais especializados declaram `body.beforeContent`, vinculado à list action por
178
+ `bindPresentationListContent`. O adaptador recebe o input efetivo que ActionList materializa,
179
+ incluindo período, filtros e escopo fixo. Assim, cartões de consumo podem consultar o resumo
180
+ do período sem duplicar a montagem do recorte nem somar uma página da tabela. O conteúdo só
181
+ monta depois do gate da coleção. Ausência ou incompatibilidade do adaptador falha antes da consulta.
182
+
183
+ ### Registro único e comandos de seção
184
+
185
+ Uma Presentation pode declarar `source` com action `view` e bindings de entrada. O renderer
186
+ carrega o registro, apresenta estados de leitura e disponibiliza o dado em `record`. A permissão
187
+ da fonte é cumulativa com a da apresentação; acesso negado não consulta a fonte. Formulários
188
+ endereçáveis declaram a mesma fonte e recebem os valores por bindings explícitos, preservando
189
+ a lista de campos enviados. O cache do driver compartilha a leitura entre página e diálogo.
190
+
191
+ Itens de seção podem declarar `value.field`, `empty` e `suffix`; `content` permanece reservado
192
+ a controles específicos. Comandos com placement `section` são referenciados por action no
193
+ campo `actions` da seção. Mensagens condicionais usam as condições finitas já existentes.
194
+ Isso elimina wrappers de leitura/edição sem serializar funções nem enfraquecer autorização.
195
+
196
+ A fonte também admite uma action list com seleção explícita por campo e parâmetro de rota,
197
+ preservando o recorte e o limite do consumidor. Componentes registrados por
198
+ `bindPresentationComponent` recebem input, contexto e controles de fechamento/aside; cada
199
+ vínculo referencia um contrato existente e seu acesso é conferido antes da montagem.
200
+ Não se executa o contrato só por registrar o componente. Uma operação simple de leitura pode
201
+ abrir esse conteúdo; operações de escrita continuam executando pelo trigger.
202
+
203
+ `formGroups` declara agrupamentos de campos. `initialValues` representa o rascunho inicial,
204
+ que pode ainda ser inválido (por exemplo, nenhuma ferramenta selecionada); seus nomes são
205
+ validados contra o contrato e o envio continua usando a validação de ActionForm. Bindings
206
+ explícitos prevalecem sobre valores iniciais. Comandos de seção podem ter id próprio quando
207
+ vários grupos abrem a mesma action, e nomes acessíveis preservam a distinção entre grupos.
208
+
209
+ Rotas com registro podem declarar alternativas condicionais de mesma superfície, sem
210
+ encadeamento, como a consulta de uma revisão da plataforma por um endereço legado de edição.
211
+ O host verifica a permissão do destino e só então monta seu conteúdo. Fallbacks de criação
212
+ exigem campos declarados e vêm exclusivamente da transição em memória, nunca da querystring.
213
+
214
+ ### Fontes externas, navegação e detalhes na busca
215
+
216
+ A conta da pessoa continua sob responsabilidade do IdP. `externalSource` referencia um
217
+ adaptador de leitura registrado pelo host; não cria uma action fictícia nem permite executar
218
+ código no JSON. A leitura é local à montagem, cancela resultados obsoletos e respeita `requires`
219
+ antes de iniciar. `source` e `externalSource` são mutuamente exclusivos. Campos vindos do IdP
220
+ são conferidos pelo adaptador; não existe contrato Opus para inferir seu schema.
221
+
222
+ `bindPresentationContent` registra controles de integrações externas sem atribuir-lhes um
223
+ contrato inexistente. Formulários especializados podem declarar `body.footer`, recebendo o
224
+ alvo do rodapé e o controle de ocupação da superfície; validação e persistência continuam
225
+ no cliente oficial da integração. `links` declara navegação entre apresentações, sem simular
226
+ uma operação de domínio. O destino também precisa passar pelo controle de acesso.
227
+
228
+ Ações secundárias de seção usam `ghost`. Comandos e links podem declarar `icon`, uma
229
+ referência ao registro de ícones do runtime, para ações reconhecíveis como editar. Nesse
230
+ caso, o botão exibe somente o ícone e mantém o rótulo em tooltip e nome acessível. Links
231
+ usam seu próprio `label`; comandos podem distinguir seções com `accessibleLabel`.
232
+ Ações que precisam de texto para explicar o efeito conservam o rótulo visível. A escolha
233
+ é explícita na definição, sem inferir ícones pelo texto nem alterar ações primárias.
234
+
235
+ `route.query` identifica detalhes que compartilham o caminho da coleção. A seleção recebe
236
+ um nome de parâmetro público e um nome de input; o host conserva os filtros ao abrir e retira
237
+ somente a seleção ao fechar. Rotas de abas aceitam os mesmos parâmetros de caminho da página.
238
+ A assistência recebe o contexto já carregado e não oferece seu botão durante a carga ou recusa.
239
+
240
+ Atualizações de uma fonte já carregada não desmontam seu conteúdo. Consultas acompanhadas por
241
+ SSE podem declarar `source.retainOnError` para conservar o último resultado e apresentar um
242
+ aviso próprio. Isso não permite reutilizar um registro de outra chave nem libera comandos
243
+ quando o monitoramento ou a consulta falhar.
244
+
245
+
246
+ ## Consolidação local: listas, canvas e fontes
247
+
248
+ ### Coleções completas sem paginação
249
+
250
+ ActionList passa a respeitar `paginate: false`, já declarado no contrato ListAction.
251
+ Nesse modo não envia `page`/`limit`, ignora paginação legada da URL, não mostra rodapé
252
+ nem seletor de quantidade e preserva busca, ordenação, estados e recarga. O handler
253
+ precisa retornar o recorte completo; aumentar artificialmente o limite ou apenas
254
+ esconder o paginador foi descartado porque pode tornar registros inacessíveis.
255
+ O modo omitido, cursor ou offset conserva o comportamento anterior. Não há uma segunda
256
+ opção visual divergente no JSON de Presentation: a action é a fonte da decisão.
257
+
258
+ ### Recarga manual da lista
259
+
260
+ O ActionList não apresenta comando de recarga manual na toolbar nem em `Opções da lista`.
261
+ Invalidations de mutations e eventos do consumidor continuam atualizando os resultados;
262
+ o estado de erro mantém `Tentar novamente`. Não se adiciona polling genérico.
263
+ O menu reúne somente preferências e não aparece quando não há opções aplicáveis.
264
+ ActionFilterBar isolado conserva seu `onRefresh` explícito, sem mudar consumidores próprios.
265
+
266
+ ### Protótipo de catálogo de habilidades
267
+
268
+ `body.collection` referencia um renderer de coleção vinculado à action da lista. Ele recebe
269
+ os itens da página atual, recarga, abertura governada e ações declaradas por item. A consulta,
270
+ busca, paginação, estados e toolbar continuam no ActionList; permissões e destinos permanecem
271
+ no JSON. Isso projeta o slot `children` já existente, evitando uma segunda listagem ou
272
+ callbacks de navegação duplicados no consumidor. O renderer desenha apenas os resultados.
273
+
274
+ O primeiro consumidor agrupa cards de habilidades por uma configuração visual local.
275
+ Essas categorias não alteram o domínio nem a seleção feita pela IA. O agrupamento abrange
276
+ somente a página carregada; não promete totais globais por categoria. Testes devem preservar
277
+ destinos autorizados, comandos, busca e estados de lista.
278
+
279
+ O renderer admite `body.rowContent` e `body.toolbarContent`, vinculados à mesma list action
280
+ por adaptadores tipados. A linha personalizada convive com comandos declarados; não substitui
281
+ paginação, filtro ou estado do ActionList. Referências ausentes ou de outra action falham antes
282
+ da consulta. `successMessage` pertence ao comando e só é emitida após sucesso.
283
+
284
+ Regiões content podem declarar `layout: fill` para ocupar a altura restante sem depender de uma
285
+ lista. O elo registra a folha na cadeia de altura e interrompe sua propagação ao conteúdo próprio.
286
+ `page.flush` permite conteúdo com recuo próprio. Abas embedded mantêm o contexto Tabs; framed e
287
+ distribution são encaminhados à primitiva. Drawer respeita width wide, com expansão do assistente.
288
+
289
+ Rotas aceitam parâmetros finitos e seletores compostos de busca. Restrições valem no matching e
290
+ na geração de URL; nomes e bindings repetidos são inválidos. Fonte externa é identificada também
291
+ pelo adaptador, não apenas pela chave de rota. Refetch de uma view não desmonta conteúdo já lido.
292
+
293
+ Links com ícone podem declarar `showLabel: true` para manter o rótulo visível, usando
294
+ o tamanho textual do botão e sem tooltip redundante. O padrão dos links com ícone
295
+ continua sendo somente ícone, com rótulo acessível e tooltip.
@@ -0,0 +1,28 @@
1
+ # ADR 0066 — Datas civis e calendário mensal na lista
2
+
3
+ - **Status:** aceita para consolidação; publicação é uma etapa separada.
4
+ - **Data:** 2026-10-22.
5
+
6
+ ## Contexto
7
+
8
+ A gestão de expediente precisa escolher datas sem conversão de fuso e consultar um mês inteiro junto dos filtros de unidade e equipe. O input nativo varia entre navegadores, e uma grade implementada em cada consumidor repetiria navegação e acessibilidade. A experimentação no consumidor Grand Brasil validou a composição antes da consolidação desta API.
9
+
10
+ ## Decisão
11
+
12
+ `DateInput` compõe Input, Popover e Calendar. Aceita digitação com máscara `DD/MM/AAAA`, colagem ISO e seleção por calendário; datas válidas são emitidas como `AAAA-MM-DD`. Entradas incompletas ou impossíveis permanecem visíveis e são emitidas sem convertê-las numa data válida, para o contrato poder rejeitá-las. O campo recebe foco; o ícone é um adorno. Clique abre o picker sem impedir digitação, Alt+Seta para baixo transfere o foco, e Escape fecha somente o popover. O renderer de `ActionForm` reconhece `widget: 'date'`, preservando controle, reset, validação e acessibilidade do formulário.
13
+
14
+ `ActionList` e `ActionFilterBar` recebem `periodControl?: ReactNode`. A extensão substitui o seletor padrão no mesmo espaço, respeitando `periodPosition` e a composição com `period.basisFilter`. O consumidor controla o valor temporal e seu estado navegável. Com periodControl, ActionList ignora o preset padrão e os valores period/from/to do estado; somente o input fornecido pelo consumidor define o intervalo. O helper listStateToInput aceita applyPeriod: false para reproduzir esse recorte em detalhes roteados. Sem a propriedade, a API anterior mantém seu comportamento.
15
+
16
+ `CalendarMonthView<TItem>` é uma visualização, consumida por `ActionList.views`. Recebe mês civil, itens, extração de data, conteúdo, nome acessível e ação por dia. Gera todas as datas do mês e agrupa os itens. A navegação usa setas, Home e End, com uma única parada de Tab. Consulta, filtros, loading, erro e vazio continuam pertencendo à lista. Regras de expediente e feriados ficam no domínio consumidor. A grade é separada do DayPicker por representar uma coleção com conteúdo e ação próprios em cada dia, sem modelo de seleção de datas. Adaptar os botões e o estado de seleção do DayPicker duplicaria essa semântica; a exceção preserva teclado e roles de grid sem copiar a primitiva. A primeira versão usa cabeçalhos em pt-BR e semanas iniciadas no domingo, explicitados na documentação.
17
+
18
+ O Calendar compartilhado apresenta o mês com inicial maiúscula e barra antes do ano, preservando os formatters customizados. A raiz estável evita perder foco ao renderizar novamente. Dias selecionados usam o par de cores do botão primário sólido, incluindo as extremidades de intervalos.
19
+
20
+ ## Alternativas e consequências
21
+
22
+ O input nativo foi experimentado e descartado pela inconsistência com os outros campos. Converter datas civis para timestamps criaria dependência de fuso sem necessidade. Copiar a barra de filtros ou inserir um calendário com consulta própria duplicaria responsabilidades já cobertas por ActionList.
23
+
24
+ As extensões são aditivas. A mudança de legenda e de contraste alcança todos os consumidores do Calendar, portanto inclui regressão do modo de intervalo e dos formatters. Mês inválido em CalendarMonthView é erro de programação; consumidores validam sua entrada antes de renderizar.
25
+
26
+ ## Verificação
27
+
28
+ Testes de DateInput cobrem máscara, cursor, teclado, datas inválidas, reset e integração com ActionForm. Testes da lista cobrem posicionamento do período e grade com navegação. Testes de Calendar cobrem identidade da raiz, formatter e seleção. Os gates da release incluem tipagem, suíte completa, Chromium e instalação de um consumidor a partir do tarball.
@@ -20,3 +20,9 @@ estar documentado na superfície correspondente, sem exigir a reconstrução des
20
20
  - [ADR 0062 — Listas contidas e texto flexível](0062-listas-contidas-e-texto-flexivel.md).
21
21
 
22
22
  - [ADR 0063 — Metadados das superfícies em região própria](0063-metadados-das-superficies.md).
23
+
24
+ - [ADR 0064 — ActionList apresenta itens e conecta fontes externas](0064-action-list-com-itens-e-fontes-externas.md).
25
+
26
+ - [ADR 0065 — Presentation compõe seções declaradas](0065-presentation-composes-settings-sections.md).
27
+
28
+ - [ADR 0066 — Datas civis e calendário mensal na lista](0066-civil-date-input-and-calendar-list.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softize/opus",
3
- "version": "30.0.0",
3
+ "version": "31.1.0",
4
4
  "description": "End-to-end action protocol for TypeScript. Single package with subpath exports (core + adapters).",
5
5
  "license": "MIT",
6
6
  "type": "module",