@softize/opus 29.0.0 → 31.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +137 -0
- package/bin/lib/check.mjs +178 -94
- package/bin/lib/copy.mjs +2970 -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/0045-surface-replaces-content-and-card.md +3 -0
- package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
- package/docs/adr/0062-listas-contidas-e-texto-flexivel.md +68 -0
- package/docs/adr/0063-metadados-das-superficies.md +44 -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/README.md +8 -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 +21 -10
- package/registry/skills/build-opus-ui/references/ui-patterns.md +33 -28
- package/src/core/presentation.ts +938 -32
- package/src/core/types.ts +2 -1
- package/src/ui/components/patterns/form.tsx +2 -0
- package/src/ui/components/patterns/grouped-list.ts +2 -2
- package/src/ui/components/patterns/list.tsx +588 -365
- package/src/ui/components/patterns/page-heading-context.tsx +12 -5
- package/src/ui/components/patterns/page.tsx +238 -181
- 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 +47 -34
- package/src/ui/components/patterns/surface-anatomy.ts +27 -217
- package/src/ui/components/patterns/surface.tsx +55 -37
- package/src/ui/components/patterns/trigger.tsx +10 -2
- package/src/ui/components/primitives/close-button.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -8
- package/src/ui/components/primitives/detail.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +59 -89
- package/src/ui/components/primitives/drawer.tsx +52 -87
- 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 +3 -3
- package/src/ui/components/primitives/tabs.tsx +13 -2
- package/src/ui/docs/content/action-form.md +2 -1
- package/src/ui/docs/content/action-list.md +146 -73
- package/src/ui/docs/content/action-trigger.md +5 -0
- package/src/ui/docs/content/button.md +5 -6
- package/src/ui/docs/content/command.md +62 -50
- package/src/ui/docs/content/compositions.md +129 -459
- package/src/ui/docs/content/dialog.md +72 -101
- package/src/ui/docs/content/drawer.md +69 -92
- package/src/ui/docs/content/field.md +2 -1
- package/src/ui/docs/content/page.md +207 -386
- 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 +94 -116
- package/src/ui/docs/content/table.md +7 -0
- package/src/ui/docs/content/tokens.md +18 -4
- package/src/ui/drivers/context.tsx +11 -4
- package/src/ui/drivers/react.tsx +27 -7
- package/src/ui/meta.ts +5 -5
- package/src/ui/react.tsx +38 -8
- package/src/ui/theme.css +44 -33
|
@@ -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.
|
package/docs/adr/README.md
CHANGED
|
@@ -16,3 +16,11 @@ estar documentado na superfície correspondente, sem exigir a reconstrução des
|
|
|
16
16
|
- [ADR 0060 — Composição de superfícies com cabeçalho e intro](0060-surface-composition-separates-chrome-and-intro.md).
|
|
17
17
|
|
|
18
18
|
- [ADR 0061 — O `CLAUDE.md` importa o `AGENTS.md`](0061-claude-md-imports-agents-md.md).
|
|
19
|
+
|
|
20
|
+
- [ADR 0062 — Listas contidas e texto flexível](0062-listas-contidas-e-texto-flexivel.md).
|
|
21
|
+
|
|
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).
|
package/package.json
CHANGED
|
@@ -43,31 +43,33 @@ existentes, mantendo navegação observável e componentes reutilizáveis sem la
|
|
|
43
43
|
7. Tratar página, filtro, seleção e modal importante como estado navegável por URL quando
|
|
44
44
|
o produto precisa de deep link, back/forward ou refresh. Em `Presentation`, declarar `route`
|
|
45
45
|
no artefato e deixar o adaptador apenas conectar a spec ao router da aplicação.
|
|
46
|
-
8. Compor Page, Dialog e
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
8. Compor Page, Dialog, Drawer e Surface pela mesma anatomia: título, descrição opcional,
|
|
47
|
+
metadados e ações gerais no Header; conteúdo no Body; decisões no Footer. Não existem
|
|
48
|
+
`compact`, `sectioned`, `surfaceLayout`, `*Intro` nem a escolha visual `layout` nesses roots.
|
|
49
|
+
Preservar exatamente um heading principal. Page usa uma coluna aberta, padding de `2.5rem`
|
|
50
|
+
e título de `1.875rem`, sem divisores entre regiões. `width` limita a coluna; omitido, ocupa a
|
|
51
|
+
largura disponível. `Page.layout="flow"` rola a página inteira; `fill` mantém o header visível
|
|
52
|
+
e entrega a altura restante à lista ou à rolagem do body. Não oferecer `composition`.
|
|
53
|
+
PageBack recebe destino pai explícito e aparece como primeira ação de ícone no Header.
|
|
54
|
+
Não criar barra de breadcrumb. PageShell fornece ações sem barra paralela.
|
|
55
|
+
Headers usam botões `default`/`icon` e linha mínima de `2.25rem`. Regiões delimitadas têm recuo
|
|
56
|
+
de `1rem`, e bodies governam o ritmo vertical de `1rem`. Divisores são automáticos entre
|
|
57
|
+
regiões existentes. Surface sem moldura se alinha ao hospedeiro, sem recuo lateral ou inferior.
|
|
58
|
+
Usar `flush` quando o filho já controla o recuo; não reconstruir padding ou divisores na tela.
|
|
59
|
+
`tabs` integra a navegação ao Header; ações da coleção ficam em `ActionList.toolbarActions`
|
|
60
|
+
dentro do painel ativo. Pane distribui espaço e recebe Surface quando precisar de anatomia.
|
|
61
|
+
`Surface as="fieldset"` mantém legend nativa na faixa do cabeçalho, sem variante de moldura.
|
|
61
62
|
9. Manter margem e posicionamento no consumidor; componente reutilizável controla apenas
|
|
62
63
|
seu interior.
|
|
63
64
|
10. Não definir a fonte raiz em uma biblioteca ou componente. O navegador e a aplicação são
|
|
64
65
|
responsáveis por `font-size` em `html`; medidas escaláveis da UI usam `rem` ou a escala
|
|
65
66
|
relativa do Tailwind. Reservar `px` a hairlines e compensações presas à geometria da borda,
|
|
66
67
|
com justificativa e cobertura explícitas.
|
|
67
|
-
11. Em uma página centrada em coleção, compor `
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
11. Em uma página centrada em coleção, compor `Page + ActionList`; usar `Surface` para uma coleção
|
|
69
|
+
subordinada. Manter criação, importação e exportação em `ActionList.toolbarActions`, junto
|
|
70
|
+
de busca e filtros. Reservar ações do header à página ou superfície como um todo.
|
|
71
|
+
Usar botão textual normal, sem ícone, com `Criar`; preservar `Criar recurso` no nome acessível
|
|
72
|
+
e no título do formulário. Manter nomes específicos em menus com vários tipos de criação.
|
|
71
73
|
12. Evoluir um pattern compartilhado apenas quando a recorrência e o contrato estiverem claros.
|
|
72
74
|
13. Tratar tokens de superfície como pares indivisíveis no mesmo fragmento de classes:
|
|
73
75
|
`bg-card text-card-foreground` e `bg-popover text-popover-foreground`. Não depender da
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
- Não dispara: “Ajuste o CSS de um e-mail estático.”
|
|
5
5
|
- Execução: implementar uma lista com modal roteável e provar loading, erro, vazio e back.
|
|
6
6
|
- Execução estrutural: montar uma página de relatório isolada com `Page > PageHeader + PageBody`,
|
|
7
|
-
outra em `PageShell` com
|
|
7
|
+
outra em `PageShell` com ações contextuais no `PageHeader`, garantindo
|
|
8
8
|
exatamente um `PageTitle` no header, e uma coleção nomeada com
|
|
9
9
|
`Surface > SurfaceHeader + SurfaceBody > ActionList`. Provar que criação fica em
|
|
10
|
-
`
|
|
11
|
-
`Criar
|
|
10
|
+
`ActionList.toolbarActions`, junto das operações do recorte, como botão textual normal sem ícone
|
|
11
|
+
com `Criar`, nome acessível `Criar recurso` e formulário com título específico; incluir
|
|
12
12
|
`ActionFilterBar` separado do renderer, `ItemGroup` para
|
|
13
|
-
uma coleção secundária e um `ActionFormDialog`; provar
|
|
13
|
+
uma coleção secundária e um `ActionFormDialog`; provar ocupação de toda a largura e scroll somente no body, hierarquia por
|
|
14
14
|
`level`, vazio estrutural sólido, `Empty` apenas para criação ou vínculo, números sem alinhamento
|
|
15
15
|
inferido e footer modal com largura natural, alinhado à direita e cancelamento `ghost`; incluir
|
|
16
16
|
separadamente um caso deliberadamente equivalente com distribuição 50/50 e cancelamento
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
rejeita a mistura entre props abreviadas e headers explícitos.
|
|
23
23
|
- Execução de forma: compor uma tabela dentro de `Surface` sem moldura duplicada, manter a moldura
|
|
24
24
|
estrutural standalone em `rounded-lg` e os controles internos em `rounded-md`.
|
|
25
|
-
- Execução de Surface
|
|
25
|
+
- Execução de Surface: compor `Surface framed` com mídia e
|
|
26
26
|
`DetailGroup` com divisores; provar header com divisor, `SurfaceBody flush` sem recuo e ausência
|
|
27
27
|
de classes no consumidor que reconstruam essa anatomia. Provar `as="fieldset"` com `legend`
|
|
28
28
|
nativa sem `frameVariant`.
|
|
@@ -79,8 +79,19 @@ da label, duplicação entre hint/help e perda de `aria-describedby` quando apar
|
|
|
79
79
|
|
|
80
80
|
- Gatilho positivo: “Monte o detalhe de um recurso com menu da página separado do título.”
|
|
81
81
|
- Gatilho negativo: “Explique por que a ADR antiga juntava título e ações”, sem pedido de UI.
|
|
82
|
-
- Execução: montar o mesmo detalhe em Page, Dialog e Drawer com
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
- Execução: montar o mesmo detalhe em Page, Dialog e Drawer com título e ações gerais no Header;
|
|
83
|
+
provar um único título, linha mínima de `2.25rem`, botões normais e transição de loading para
|
|
84
|
+
conteúdo sem duplicação. Page usa coluna aberta com padding de `2.5rem`, título de `1.875rem`,
|
|
85
|
+
largura independente e rolagem flow/fill; Drawer e Dialog preservam recuo de `1rem` e divisores. Conferir tabs nativas e operações
|
|
86
|
+
de coleção dentro do painel ativo, junto à listagem.
|
|
87
|
+
- Reprovar `*Intro`, `compact`, `sectioned`, `surfaceLayout`, `tabsActions`, layout visual e
|
|
88
|
+
PageNavigation. Conferir que o checker orienta a migração. Não recriar anatomia em Pane.
|
|
89
|
+
|
|
90
|
+
## Metadados e contadores
|
|
91
|
+
|
|
92
|
+
- Execução: compor um detalhe com título, descrição e badges em PageMeta, DrawerMeta e DialogMeta;
|
|
93
|
+
conferir a faixa separada no Header. Em Surface, conferir que SurfaceCount
|
|
94
|
+
fica na linha do título e SurfaceMeta abaixo dela. Migrar um contador antigo e uma descrição
|
|
95
|
+
antiga sem alterar suas funções; provar a equivalência das formas curtas com `meta`.
|
|
96
|
+
- Reprova: contador em SurfaceMeta, metadados em Description, dois Meta, Meta sem título,
|
|
97
|
+
Meta em fieldset ou DialogMeta em alerta.
|
|
@@ -7,25 +7,21 @@
|
|
|
7
7
|
- Uma `Presentation` que representa esse estado declara `route.path` e `route.surface`. Rotas com
|
|
8
8
|
parâmetro podem declarar `route.record` para hidratar o item a partir de uma Presentation de
|
|
9
9
|
lista; não reconstruir essa decisão com condicionais no componente da página.
|
|
10
|
-
- `Page` fornece o `<main>` e
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
toolbar, seção ou coleção densa, e `xs`/`icon-xs` para ações internas de linha ou célula. Contexto
|
|
26
|
-
e variante resolvem a hierarquia visual sem alterar essa medida. Em uma coleção, a ação de
|
|
27
|
-
criar usa botão textual `sm`, sem ícone, no extremo oposto do `SurfaceHeader`. Não monte
|
|
28
|
-
cabeçalho paralelo, portal ou seletor global para reconstruir essa composição.
|
|
10
|
+
- `Page` fornece o `<main>` e a coluna com largura `narrow`, `default` ou `wide` (padrão). Sua forma explícita usa
|
|
11
|
+
`PageHeader` com `PageTitle`, `PageBody` e `PageFooter` opcional. A forma curta produz a mesma
|
|
12
|
+
anatomia; não misturar props abreviadas com slots explícitos. PageState ativo assume o título.
|
|
13
|
+
- Page, Dialog, Drawer e Surface têm Header com título, descrição opcional, metadados e ações
|
|
14
|
+
gerais, Body com ritmo de `1rem` e Footer opcional. Não há `*Intro`, `compact`, `sectioned` ou
|
|
15
|
+
escolha visual de layout. `Page.layout` preserva somente a ocupação `flow`/`fill`.
|
|
16
|
+
- Page tem uma aparência aberta, padding de `2.5rem` e título de `1.875rem`, sem divisores.
|
|
17
|
+
`flow` rola a página inteira; `fill` entrega a altura restante à lista ou ao body.
|
|
18
|
+
PageBack usa o destino pai e aparece como
|
|
19
|
+
primeira ação de ícone. PageShell entrega ações sem criar barra paralela; breadcrumbs
|
|
20
|
+
não fazem parte da composição. PageActionsTarget atende workspaces com chrome próprio.
|
|
21
|
+
- Headers usam botões `default`/`icon` e linha mínima de `2.25rem`. Regiões delimitadas
|
|
22
|
+
de Drawer, Dialog e Surface conservam recuo de `1rem` e divisores automáticos. Surface sem moldura permanece
|
|
23
|
+
alinhada ao hospedeiro. A prop `tabs` integra a navegação ao Header; operações da coleção ficam
|
|
24
|
+
em `ActionList.toolbarActions` no painel ativo. Não reconstruir isso por portais ou seletores.
|
|
29
25
|
- `PageState` substitui todo o conteúdo principal quando a página carrega, falha ou está vazia. Na
|
|
30
26
|
forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
|
|
31
27
|
explícita, fica sozinho dentro de `PageBody`. Nos três estados ativos, o cabeçalho da Page
|
|
@@ -36,18 +32,27 @@
|
|
|
36
32
|
recuperação como botão `outline` textual. Estados de seção ou coleção continuam em `DataState`,
|
|
37
33
|
`ActionView`, `ActionList` ou `Alert`; não elevar uma falha parcial a estado da página.
|
|
38
34
|
- `Surface` delimita uma região e segue a anatomia `Surface > SurfaceHeader (SurfaceMedia,
|
|
39
|
-
SurfaceTitle, SurfaceDescription, SurfaceMeta, SurfaceActions) + SurfaceBody + SurfaceFooter`.
|
|
40
|
-
Os slots nunca ficam soltos. `title`, `description`, `count`, `media` e `actions` são a abreviação
|
|
41
|
-
para o caso direto e não podem ser misturados ao header explícito.
|
|
42
|
-
|
|
43
|
-
`Criar recurso`.
|
|
35
|
+
SurfaceTitle, SurfaceCount, SurfaceDescription, SurfaceMeta, SurfaceActions) + SurfaceBody + SurfaceFooter`.
|
|
36
|
+
Os slots nunca ficam soltos. `title`, `description`, `count`, `meta`, `media` e `actions` são a abreviação
|
|
37
|
+
para o caso direto e não podem ser misturados ao header explícito. Ações do header pertencem à
|
|
38
|
+
superfície como um todo; operações da coleção ficam em `ActionList.toolbarActions`.
|
|
44
39
|
O diálogo de criação usa `Criar recurso` e o de edição, `Editar recurso`. `level` preserva a
|
|
45
|
-
hierarquia semântica do heading.
|
|
40
|
+
hierarquia semântica do heading. Declare
|
|
46
41
|
`SurfaceBody flush` quando o filho direto já possui recuo interno, como `DetailGroup` com
|
|
47
42
|
divisores, lista ou tabela. `as="fieldset"` cria a `legend` nativa sem variante de moldura.
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
`
|
|
43
|
+
- `PageMeta`, `DialogMeta` e `DrawerMeta` recebem badges, datas e autoria em faixa própria
|
|
44
|
+
após título, descrição e ações, dentro do Header da mesma família.
|
|
45
|
+
`SurfaceMeta` ocupa essa faixa em `SurfaceHeader`; `SurfaceCount` mantém o contador na linha
|
|
46
|
+
do título. Ao migrar, conferir manualmente os antigos `SurfaceMeta`: contadores passam a
|
|
47
|
+
`SurfaceCount`, frases de orientação a `SurfaceDescription`, e metadados permanecem em Meta.
|
|
48
|
+
Cada composição aceita um Meta e exige título. Page e Surface aceitam `meta` na forma curta;
|
|
49
|
+
fieldset e Dialog em `mode="alert"` não aceitam Meta. Informações necessárias à decisão
|
|
50
|
+
permanecem no corpo ou junto à ação correspondente.
|
|
51
|
+
- Uma página centrada em coleção compõe `Page + ActionList`; coleções subordinadas podem usar
|
|
52
|
+
`Surface`. Criação, importação e exportação ficam em `toolbarActions`, junto de busca e filtros.
|
|
53
|
+
O botão de criação é textual normal, sem ícone, com `Criar` e nome acessível `Criar recurso`.
|
|
54
|
+
Menus com vários tipos de criação preservam os nomes específicos. Operações de seleção usam
|
|
55
|
+
`batchActions`, e operações individuais usam `rowActions`.
|
|
51
56
|
- `Surface` e Drawer nomeiam a região principal como `SurfaceBody` e `DrawerBody`. `Pane` é apenas
|
|
52
57
|
uma unidade dimensionável de `Split` e não possui anatomia interna. `*Content` permanece
|
|
53
58
|
reservado a raízes técnicas ou painéis cujo papel não é o corpo de uma estrutura, como
|