@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.
- package/CHANGELOG.md +123 -0
- package/bin/lib/check.mjs +109 -101
- package/bin/lib/copy.mjs +2973 -1801
- package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +52 -0
- package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +27 -2
- package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
- package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
- package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
- package/docs/adr/0066-civil-date-input-and-calendar-list.md +28 -0
- package/docs/adr/README.md +6 -0
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/SKILL.md +21 -19
- package/registry/skills/build-opus-ui/references/evaluations.md +13 -11
- package/registry/skills/build-opus-ui/references/ui-patterns.md +24 -27
- package/src/core/presentation.ts +938 -32
- package/src/core/types.ts +2 -0
- package/src/ui/components/patterns/form.tsx +22 -1
- package/src/ui/components/patterns/grouped-list.ts +2 -2
- package/src/ui/components/patterns/list-calendar.tsx +129 -0
- package/src/ui/components/patterns/list.tsx +612 -382
- package/src/ui/components/patterns/page-heading-context.tsx +12 -5
- package/src/ui/components/patterns/page.tsx +227 -197
- package/src/ui/components/patterns/presentation-fields.tsx +246 -0
- package/src/ui/components/patterns/presentation-sections.tsx +494 -0
- package/src/ui/components/patterns/presentation.tsx +1142 -229
- package/src/ui/components/patterns/structural-header.tsx +23 -32
- package/src/ui/components/patterns/surface-anatomy.ts +27 -217
- package/src/ui/components/patterns/surface.tsx +19 -29
- package/src/ui/components/patterns/trigger.tsx +10 -2
- package/src/ui/components/primitives/calendar.tsx +39 -18
- package/src/ui/components/primitives/close-button.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -8
- package/src/ui/components/primitives/date-input.tsx +276 -0
- package/src/ui/components/primitives/detail.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +19 -81
- package/src/ui/components/primitives/drawer.tsx +17 -79
- package/src/ui/components/primitives/field.tsx +1 -1
- package/src/ui/components/primitives/pagination.tsx +3 -2
- package/src/ui/components/primitives/table.tsx +1 -1
- package/src/ui/components/primitives/tabs.tsx +13 -2
- package/src/ui/docs/content/action-form.md +6 -1
- package/src/ui/docs/content/action-list.md +156 -68
- package/src/ui/docs/content/action-trigger.md +5 -0
- package/src/ui/docs/content/button.md +5 -6
- package/src/ui/docs/content/calendar-month-view.md +50 -0
- package/src/ui/docs/content/calendar.md +6 -1
- package/src/ui/docs/content/command.md +62 -50
- package/src/ui/docs/content/compositions.md +129 -459
- package/src/ui/docs/content/date-input.md +67 -0
- package/src/ui/docs/content/dialog.md +44 -112
- package/src/ui/docs/content/drawer.md +44 -103
- package/src/ui/docs/content/field.md +2 -1
- package/src/ui/docs/content/input.md +3 -0
- package/src/ui/docs/content/page.md +204 -412
- package/src/ui/docs/content/presentation.md +371 -23
- package/src/ui/docs/content/separator.md +1 -1
- package/src/ui/docs/content/surface.md +65 -120
- package/src/ui/docs/content/tokens.md +18 -4
- package/src/ui/docs/registry.tsx +38 -9
- package/src/ui/drivers/context.tsx +11 -4
- package/src/ui/drivers/react.tsx +27 -7
- package/src/ui/meta.ts +17 -6
- package/src/ui/react.tsx +41 -8
- 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
|
-
|
|
39
|
-
|
|
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.
|
package/docs/adr/README.md
CHANGED
|
@@ -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).
|