@praxisui/list 8.0.0-beta.2 → 8.0.0-beta.20

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.
@@ -0,0 +1,309 @@
1
+ # ADR: Expansão Inline V1 para o `praxis-list`
2
+
3
+ ## Status
4
+
5
+ Proposto.
6
+
7
+ Nao implementado no runtime atual.
8
+
9
+ ## Problema
10
+
11
+ O `praxis-list` ja atende bem leituras fechadas em `list`, `cards` e `tiles`, mas nao oferece um mecanismo oficial para `detail row` ou expansao inline por item.
12
+
13
+ Essa lacuna ficou explicita ao tentar reproduzir referencias corporativas com duas camadas:
14
+
15
+ 1. uma linha executiva resumida;
16
+ 2. um painel expandido inline com secoes como alertas, produtos contratados e proximos eventos.
17
+
18
+ Hoje isso nao cabe no contrato publico atual de `PraxisListConfig`, nem no template do runtime.
19
+
20
+ Consequencias da ausencia de contrato formal:
21
+
22
+ - playground pode cair em hacks de apresentacao que parecem suportar algo que o componente nao suporta;
23
+ - integradores nao tem boundary claro para estado expandido, trigger e acessibilidade;
24
+ - UX corporativa fica inconsistente entre hosts;
25
+ - qualquer tentativa de resolver com `html` livre degrada governanca, consistencia visual e testabilidade.
26
+
27
+ ## Decisao
28
+
29
+ Tratar expansao inline como evolucao formal do contrato do `praxis-list`, com escopo reduzido e governado.
30
+
31
+ Regras normativas da proposta V1:
32
+
33
+ 1. A V1 cobre apenas `layout.variant = 'list'`.
34
+ 2. A V1 adiciona dois blocos novos ao contrato: `interaction` e `expansion`.
35
+ 3. `interaction` governa habilitacao, trigger e politica de estado expandido.
36
+ 4. `expansion` governa apenas conteudo expandido inline estruturado, nao markup arbitrario.
37
+ 5. O conteudo expandido e composto por secoes com tipos fechados e previsiveis.
38
+ 6. `cards` e `tiles` ficam fora do escopo da V1.
39
+ 7. `selection` e expansao podem coexistir, mas o trigger padrao deve favorecer icone dedicado quando houver selecao ativa.
40
+ 8. A API canônica so deve promover esse contrato para `Active` depois de implementacao, testes de acessibilidade e exemplos oficiais.
41
+
42
+ ## Motivacao
43
+
44
+ Essa decisao existe para resolver um problema real de produto sem quebrar o perfil enterprise do componente.
45
+
46
+ Objetivos:
47
+
48
+ - manter integridade do contrato;
49
+ - evitar hacks de playground como falsa demostracao de capacidade;
50
+ - preservar acessibilidade e navegacao por teclado;
51
+ - limitar a V1 a um conjunto pequeno de padroes forte, em vez de abrir um renderer arbitrario;
52
+ - dar base formal para examples, authoring e documentacao futura.
53
+
54
+ Referencia visual-alvo desta evolucao:
55
+
56
+ - `praxis-ui-landing-page/issues/playground/problemas/referencia-list/img.png`
57
+ - `praxis-ui-landing-page/issues/playground/problemas/referencia-list/img_1.png`
58
+
59
+ Essas imagens representam o objetivo funcional e visual da combinacao:
60
+
61
+ 1. linha executiva fechada com KPIs e acoes;
62
+ 2. expansao inline governada com secoes semanticas abaixo da linha principal.
63
+
64
+ ## Proposta de Contrato V1
65
+
66
+ ### Bloco `interaction`
67
+
68
+ ```ts
69
+ interaction?: {
70
+ expandable?: boolean;
71
+ expandTrigger?: 'row' | 'icon' | 'row+icon';
72
+ expandMode?: 'single' | 'multiple';
73
+ collapseOnPageChange?: boolean;
74
+ };
75
+ ```
76
+
77
+ Semantica:
78
+
79
+ - `expandable`
80
+ - default: `false`
81
+ - habilita ou nao o estado expandido por item.
82
+ - `expandTrigger`
83
+ - default proposto: `'row'`
84
+ - quando `selection.mode !== 'none'`, default recomendado: `'icon'`
85
+ - evita conflito entre selecao e expansao na mesma superficie.
86
+ - `expandMode`
87
+ - default: `'single'`
88
+ - `'single'`: uma linha aberta por vez.
89
+ - `'multiple'`: varias linhas abertas ao mesmo tempo.
90
+ - `collapseOnPageChange`
91
+ - default: `true`
92
+ - simplifica comportamento em listas remotas e reduz risco de estado invisivel apos paginação.
93
+
94
+ ### Bloco `expansion`
95
+
96
+ ```ts
97
+ interaction?: {
98
+ expandable?: boolean;
99
+ expandTrigger?: 'row' | 'icon' | 'row+icon';
100
+ expandMode?: 'single' | 'multiple';
101
+ collapseOnPageChange?: boolean;
102
+ };
103
+
104
+ expansion?: {
105
+ emptyLabel?: string;
106
+ sections: Array<{
107
+ id: string;
108
+ title?: string;
109
+ type: 'info-list' | 'chip-list' | 'timeline' | 'key-value';
110
+ itemsExpr: string;
111
+ emptyLabel?: string;
112
+ }>;
113
+ };
114
+ ```
115
+
116
+ Semantica:
117
+
118
+ - `expansion.sections`
119
+ - obrigatorio quando `interaction.expandable = true`
120
+ - define as secoes renderizadas abaixo da linha principal.
121
+ - `id`
122
+ - chave estavel da secao.
123
+ - `title`
124
+ - rotulo visual e acessivel da secao.
125
+ - `type`
126
+ - renderer fechado e governado da secao.
127
+ - `itemsExpr`
128
+ - expressao que aponta para a colecao renderizada a partir do item atual.
129
+ - `emptyLabel`
130
+ - fallback local ou global quando a secao nao tiver conteudo.
131
+
132
+ ## Tipos de Secao da V1
133
+
134
+ ### `info-list`
135
+
136
+ Uso:
137
+
138
+ - alertas;
139
+ - observacoes;
140
+ - pendencias simples.
141
+
142
+ Shape esperado do array:
143
+
144
+ ```ts
145
+ Array<{
146
+ label?: string;
147
+ value: string;
148
+ tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
149
+ icon?: string;
150
+ }>
151
+ ```
152
+
153
+ ### `chip-list`
154
+
155
+ Uso:
156
+
157
+ - produtos contratados;
158
+ - tags operacionais;
159
+ - capacidades ativas.
160
+
161
+ Shape esperado do array:
162
+
163
+ ```ts
164
+ Array<{
165
+ label: string;
166
+ tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
167
+ }>
168
+ ```
169
+
170
+ ### `timeline`
171
+
172
+ Uso:
173
+
174
+ - proximos eventos;
175
+ - vencimentos;
176
+ - marcos operacionais.
177
+
178
+ Shape esperado do array:
179
+
180
+ ```ts
181
+ Array<{
182
+ date?: string;
183
+ label: string;
184
+ helper?: string;
185
+ tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
186
+ }>
187
+ ```
188
+
189
+ ### `key-value`
190
+
191
+ Uso:
192
+
193
+ - bloco resumido de fatos;
194
+ - indicadores secundarios;
195
+ - metadados regulatórios.
196
+
197
+ Shape esperado do array:
198
+
199
+ ```ts
200
+ Array<{
201
+ key: string;
202
+ value: string;
203
+ }>
204
+ ```
205
+
206
+ ## Exemplo V1
207
+
208
+ ```ts
209
+ const config = {
210
+ dataSource: {
211
+ resourcePath: 'api/customer-accounts/vw-account-portfolio',
212
+ sort: ['saldoDisponivel,desc'],
213
+ },
214
+ layout: {
215
+ variant: 'list',
216
+ lines: 2,
217
+ density: 'comfortable',
218
+ dividers: 'between',
219
+ pageSize: 8,
220
+ },
221
+ interaction: {
222
+ expandable: true,
223
+ expandTrigger: 'icon',
224
+ expandMode: 'single',
225
+ collapseOnPageChange: true,
226
+ },
227
+ templating: {
228
+ leading: { type: 'text', expr: '${item.sigla}' },
229
+ primary: { type: 'text', expr: '${item.nomeConta}' },
230
+ secondary: { type: 'text', expr: '${item.segmento} • ${item.tipoConta}' },
231
+ meta: { type: 'currency', expr: '${item.saldoDisponivel}|BRL:pt-BR' },
232
+ trailing: { type: 'chip', expr: '${item.risco}', variant: 'outlined' },
233
+ features: [
234
+ { icon: 'account_balance_wallet', expr: 'Saldo ${item.saldo|currency:BRL:pt-BR}' },
235
+ { icon: 'credit_card', expr: 'Limite ${item.limite|currency:BRL:pt-BR}' },
236
+ { icon: 'percent', expr: 'Uso ${item.usoPercentual}%' },
237
+ ],
238
+ },
239
+ expansion: {
240
+ emptyLabel: 'Nenhum detalhe complementar disponivel.',
241
+ sections: [
242
+ {
243
+ id: 'alerts',
244
+ title: 'Alertas',
245
+ type: 'info-list',
246
+ itemsExpr: '${item.alertas}',
247
+ emptyLabel: 'Sem alertas ativos.',
248
+ },
249
+ {
250
+ id: 'products',
251
+ title: 'Produtos contratados',
252
+ type: 'chip-list',
253
+ itemsExpr: '${item.produtosContratados}',
254
+ },
255
+ {
256
+ id: 'events',
257
+ title: 'Próximos eventos',
258
+ type: 'timeline',
259
+ itemsExpr: '${item.proximosEventos}',
260
+ emptyLabel: 'Sem eventos futuros.',
261
+ },
262
+ ],
263
+ },
264
+ };
265
+ ```
266
+
267
+ ## Fora de Escopo na V1
268
+
269
+ - expansao em `cards` e `tiles`;
270
+ - conteudo arbitrario via `html` como surface principal da expansao;
271
+ - tabs dentro da expansao;
272
+ - formulários inline dentro da detail row;
273
+ - persistencia cross-page do estado aberto;
274
+ - nesting de expansao dentro de expansao.
275
+
276
+ ## Acessibilidade e WCAG AA
277
+
278
+ Requisitos minimos da implementacao:
279
+
280
+ 1. item expansivel deve expor `aria-expanded`;
281
+ 2. trigger por icone deve expor `aria-controls`;
282
+ 3. a regiao expandida deve ter `role="region"` e rotulo associado;
283
+ 4. foco por teclado deve permitir abrir/fechar sem mouse;
284
+ 5. contraste visual da area expandida deve respeitar AA;
285
+ 6. expansao nao deve depender apenas de cor para indicar estado.
286
+
287
+ ## Impacto Esperado
288
+
289
+ Beneficios:
290
+
291
+ - capacidade oficial para padroes de “linha + detalhe inline”;
292
+ - melhor aderencia a cenarios enterprise densos;
293
+ - playground, editor e examples passam a demonstrar capacidade real;
294
+ - reduz pressao para criar componentes duplicados apenas por detail row.
295
+
296
+ Tradeoffs:
297
+
298
+ - aumenta a superficie do contrato publico;
299
+ - exige testes adicionais de keyboard/focus/ARIA;
300
+ - exige governanca de interacao com `selection`, `actions` e paginação remota.
301
+
302
+ ## Referencias
303
+
304
+ - `projects/praxis-list/src/lib/models/list-config.model.ts`
305
+ - `projects/praxis-list/src/lib/components/praxis-list.component.html`
306
+ - `projects/praxis-list/src/lib/components/praxis-list.component.scss`
307
+ - `projects/praxis-list/docs/adr/2026-03-list-authoring-protocol.md`
308
+ - `praxis-ui-landing-page/issues/playground/problemas/referencia-list/img.png`
309
+ - `praxis-ui-landing-page/issues/playground/problemas/referencia-list/img_1.png`