@praxisui/table 5.0.0-beta.0 → 6.0.0-beta.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ---
1
+ ---
2
2
  title: "Table"
3
3
  slug: "table-overview"
4
4
  description: "Visao geral do @praxisui/table com TableConfig unificada, filtros, renderers, performance e integracao enterprise."
@@ -50,12 +50,12 @@ last_updated: "2026-03-07"
50
50
 
51
51
  # @praxisui/table
52
52
 
53
- > Estado canônico do workspace Angular: JSON Logic é o único contrato ativo de regras. Menções a DSL neste documento existem apenas como contexto histórico de migração ou referência para payloads legados.
53
+ > Estado canônico do workspace Angular: JSON Logic é o único contrato ativo de regras condicionais.
54
54
 
55
55
  ## Documentation
56
56
 
57
- - Documentação oficial: https://praxisui.dev
58
- - Aplicação de referência: https://github.com/codexrodrigues/praxis-ui-quickstart
57
+ - Documentação oficial: https://praxisui.dev
58
+ - Aplicação de referência: https://github.com/codexrodrigues/praxis-ui-quickstart
59
59
  - Indicado para: data grids enterprise com filtros, edicao, virtualizacao, renderers e governanca de configuracao
60
60
 
61
61
  ## When to use
@@ -64,7 +64,13 @@ last_updated: "2026-03-07"
64
64
  - Governar configuracao de colunas, toolbar e comportamento em runtime
65
65
  - Integrar tabelas a fluxos CRUD, IA e editores visuais do ecossistema Praxis UI
66
66
 
67
- ## `x-ui.analytics` como fallback tabular canônico
67
+ ## Rich Content Convergence
68
+
69
+ - `mapTableRendererToRichContentP0(...)` e a ponte canonica entre os renderers de celula da tabela e o vocabulario compartilhado `1.0` de rich content em `@praxisui/core`.
70
+ - O subconjunto promovido nesta fase e intencionalmente pequeno: `icon`, `image`, `badge`, `chip -> badge`, `avatar`, `progress` e `compose`.
71
+ - Renderers interativos como `button`, `toggle`, `menu`, `link`, `html` e `rating`, alem do shell de detail/expansion, continuam table-owned ate promocao semantica explicita.
72
+
73
+ ## `x-ui.analytics` como fallback tabular canônico
68
74
 
69
75
  O `@praxisui/table` materializa a familia `analytic-table` quando o `@praxisui/core`
70
76
  resolve que uma projection de `x-ui.analytics` continua valida, mas nao e um chart
@@ -95,7 +101,7 @@ Filtro runtime:
95
101
  - somente `filters` entram no request remoto nesta fase
96
102
  - `sort`, `limit` e agregacao continuam vindo da projection publicada
97
103
 
98
- > Componente de tabela empresarial avançado com arquitetura unificada
104
+ > Componente de tabela empresarial avançado com arquitetura unificada
99
105
 
100
106
  ## Customization Mode Contract
101
107
 
@@ -109,92 +115,92 @@ Filtro runtime:
109
115
  - Hosts that relied on the previous implicit authoring behavior must now declare `[enableCustomization]="true"` explicitly.
110
116
  - This is an intentional breaking change for enterprise governance: authoring is opt-in, not ambient.
111
117
 
112
- ## 🌟 Visão Geral
118
+ ## 🌟 Visão Geral
113
119
 
114
- A biblioteca `@praxisui/table` fornece um componente de tabela robusto e altamente configurável para aplicações Angular empresariais. Com a nova arquitetura unificada, oferece uma experiência de desenvolvimento simplificada mantendo todos os recursos avançados.
120
+ A biblioteca `@praxisui/table` fornece um componente de tabela robusto e altamente configurável para aplicações Angular empresariais. Com a nova arquitetura unificada, oferece uma experiência de desenvolvimento simplificada mantendo todos os recursos avançados.
115
121
 
116
- ## 🎨 Tema M3 (tokens mínimos)
122
+ ## 🎨 Tema M3 (tokens mínimos)
117
123
 
118
124
  Para garantir que a tabela, filtros e editores reflitam o tema do app host:
119
125
 
120
- - Superfícies: `--md-sys-color-surface`, `--md-sys-color-surface-variant`, `--md-sys-color-surface-container-*`
126
+ - Superfícies: `--md-sys-color-surface`, `--md-sys-color-surface-variant`, `--md-sys-color-surface-container-*`
121
127
  - Texto/contorno: `--md-sys-color-on-surface`, `--md-sys-color-on-surface-variant`, `--md-sys-color-on-primary`, `--md-sys-color-outline`, `--md-sys-color-outline-variant`
122
- - Semânticos: `--md-sys-color-primary`, `--md-sys-color-secondary`, `--md-sys-color-tertiary`, `--md-sys-color-error`
128
+ - Semânticos: `--md-sys-color-primary`, `--md-sys-color-secondary`, `--md-sys-color-tertiary`, `--md-sys-color-error`
123
129
  - Containers: `--md-sys-color-primary-container`, `--md-sys-color-secondary-container`, `--md-sys-color-tertiary-container`, `--md-sys-color-error-container`
124
130
  - Overlay: `--md-sys-color-scrim`
125
- - Elevação: `--md-sys-elevation-level1`–`--md-sys-elevation-level3`
131
+ - Elevação: `--md-sys-elevation-level1`–`--md-sys-elevation-level3`
126
132
 
127
- Observação: tokens `--md-sys-*` e `--mdc-theme-*` continuam aceitos quando presentes.
128
- Nota: a classe de tema é decisão do host (`.dark-theme` ou `.theme-dark`/`.theme-light`); mantenha tokens e componentes no mesmo escopo.
133
+ Observação: tokens `--md-sys-*` e `--mdc-theme-*` continuam aceitos quando presentes.
134
+ Nota: a classe de tema é decisão do host (`.dark-theme` ou `.theme-dark`/`.theme-light`); mantenha tokens e componentes no mesmo escopo.
129
135
 
130
- ## Características Principais
136
+ ## ✨ Características Principais
131
137
 
132
- ### 🏗️ Arquitetura Unificada
138
+ ### 🏗️ Arquitetura Unificada
133
139
 
134
- - **Interface única**: `TableConfig` consolidada
140
+ - **Interface única**: `TableConfig` consolidada
135
141
  - **Type Safety**: Tipagem forte em toda a API
136
- - **Performance otimizada**: Eliminação de overhead de adaptação
137
- - **API simplificada**: Menos confusão, mais produtividade
138
-
139
- ### 📊 Recursos Avançados
140
-
141
- - **Paginação inteligente**: Client-side e server-side
142
- - **Ordenação múltipla**: Suporte a multi-sort
143
- - **Filtros dinâmicos**: Global e por coluna
144
- - **Seleção de linhas**: Single, multiple e bulk actions
145
- - **Redimensionamento**: Colunas redimensionáveis
146
- - **Virtualização**: Para grandes volumes de dados
147
- - **Exportação**: CSV, Excel, PDF
142
+ - **Performance otimizada**: Eliminação de overhead de adaptação
143
+ - **API simplificada**: Menos confusão, mais produtividade
144
+
145
+ ### 📊 Recursos Avançados
146
+
147
+ - **Paginação inteligente**: Client-side e server-side
148
+ - **Ordenação múltipla**: Suporte a multi-sort
149
+ - **Filtros dinâmicos**: Global e por coluna
150
+ - **Seleção de linhas**: Single, multiple e bulk actions
151
+ - **Redimensionamento**: Colunas redimensionáveis
152
+ - **Virtualização**: Para grandes volumes de dados
153
+ - **Exportação**: CSV, Excel, PDF
148
154
  - **Acessibilidade**: WCAG 2.1 AA compliant
149
- - **Verificação de Schema**: ETag/If-None-Match com notificações (somente em customização)
155
+ - **Verificação de Schema**: ETag/If-None-Match com notificações (somente em customização)
150
156
 
151
157
  ## Expansion Hypermedia
152
158
 
153
- O primeiro corte de `behavior.expansion.detail.source.mode = "hypermedia"` é
159
+ O primeiro corte de `behavior.expansion.detail.source.mode = "hypermedia"` é
154
160
  `capabilities-first`:
155
161
 
156
- - a row expandida começa em `_links.capabilities`
157
- - `surfaces`, `actions` e operações canônicas vêm do snapshot agregado retornado
162
+ - a row expandida começa em `_links.capabilities`
163
+ - `surfaces`, `actions` e operações canônicas vêm do snapshot agregado retornado
158
164
  pelo backend
159
165
  - o detail renderiza um resumo contextual somente leitura, com foco em UX de
160
- negócio e affordances disponíveis naquele registro
161
- - este corte não executa `surface.open` inline nem dispara workflow inline
162
- - quando o item não expõe `rel="capabilities"`, o runtime aplica fail-closed
166
+ negócio e affordances disponíveis naquele registro
167
+ - este corte não executa `surface.open` inline nem dispara workflow inline
168
+ - quando o item não expõe `rel="capabilities"`, o runtime aplica fail-closed
163
169
 
164
- Observação de escala:
170
+ Observação de escala:
165
171
  - o prefetch por linha continua ativo quando `actions.row.enabled=true`
166
- - quando apenas o expansion `hypermedia` está ligado, o discovery contextual é
172
+ - quando apenas o expansion `hypermedia` está ligado, o discovery contextual é
167
173
  resolvido sob demanda ao expandir a linha
168
174
 
169
- ### 📄 Contrato Inline do Filtro
175
+ ### 📄 Contrato Inline do Filtro
170
176
 
171
177
  - Referencia canonica: `projects/praxis-dynamic-fields/docs/dynamic-fields-inline-components-guide.md` (slug publicado: `dynamic-fields-inline-components-guide`)
172
178
  - No contexto da tabela, use este contrato para definir `controlType` inline e politica de compatibilidade (canonica vs legado).
173
179
 
174
- ### 🧭 Decisoes de Arquitetura (ADR)
180
+ ### 🧭 Decisoes de Arquitetura (ADR)
175
181
 
176
182
  - Bundle/adapters: `projects/praxis-table/docs/adr/2026-03-filter-drawer-adapter-light-entrypoint.md`
177
183
 
178
- ### 🎨 Editores Visuais
184
+ ### 🎨 Editores Visuais
179
185
 
180
- - **Behavior Editor**: Configuração de comportamentos
181
- - **Columns Editor**: Gestão avançada de colunas
182
- - **Toolbar Editor**: Personalização de ações
183
- - **Messages Editor**: Textos e localização
186
+ - **Behavior Editor**: Configuração de comportamentos
187
+ - **Columns Editor**: Gestão avançada de colunas
188
+ - **Toolbar Editor**: Personalização de ações
189
+ - **Messages Editor**: Textos e localização
184
190
 
185
191
  Nota (Regras)
186
- - A antiga aba visual genérica foi removida deste pacote. O editor especializado de regras da Tabela está disponível no painel de configuração.
192
+ - A antiga aba visual genérica foi removida deste pacote. O editor especializado de regras da Tabela já está disponível no painel de configuração.
187
193
 
188
- ### 🧩 Editor de Regras (column-first)
194
+ ### 🧩 Editor de Regras (column-first)
189
195
 
190
- O novo editor é "column-first" e usa uma tipagem compartilhada com o Editor de Colunas. Principais pontos:
196
+ O novo editor é "column-first" e usa uma tipagem compartilhada com o Editor de Colunas. Principais pontos:
191
197
 
192
- - Escopo: aplique regras na linha inteira (rowConditionalStyles) ou em uma coluna específica (columns[].conditionalStyles).
193
- - Operadores por tipo: o conjunto de operadores é filtrado por tipo (string/number/date/boolean/enum).
194
- - Editores de valor dinâmicos: inputs numéricos, listas (CSV/múltipla seleção), datepickers.
195
- - Grupos lógicos: construa condições com AND/OR/NOT e reordene via arrastar-e-soltar (CDK DragDrop).
196
- - Preview: execute Testar para ver quantas linhas seriam afetadas pelas regras ativas.
197
- - Import/Export: exporta JSON sem o campo `enabled`; importa com validação estrutural de JSON Logic e sanitização de estilos (allowlist).
198
+ - Escopo: aplique regras na linha inteira (rowConditionalStyles) ou em uma coluna específica (columns[].conditionalStyles).
199
+ - Operadores por tipo: o conjunto de operadores é filtrado por tipo (string/number/date/boolean/enum).
200
+ - Editores de valor dinâmicos: inputs numéricos, listas (CSV/múltipla seleção), datepickers.
201
+ - Grupos lógicos: construa condições com AND/OR/NOT e reordene via arrastar-e-soltar (CDK DragDrop).
202
+ - Preview: execute “Testar” para ver quantas linhas seriam afetadas pelas regras ativas.
203
+ - Import/Export: exporta JSON sem o campo `enabled`; importa com validação estrutural de JSON Logic e sanitização de estilos (allowlist).
198
204
 
199
205
  Exemplos de JSON Logic:
200
206
 
@@ -208,80 +214,77 @@ Exemplos de JSON Logic:
208
214
  ```
209
215
 
210
216
  Notas sobre enum/CSV:
211
- - Para campos enumerados, as opções são inferidas de `valueMapping` da coluna ou de `fields?.options`.
212
- - Para `in/not in` em números/strings, use CSV (ex.: `10, 20, 30` ou `Alice, Bob`).
217
+ - Para campos enumerados, as opções são inferidas de `valueMapping` da coluna ou de `fields?.options`.
218
+ - Para `in/not in` em números/strings, use CSV (ex.: `10, 20, 30` ou `Alice, Bob`).
213
219
 
214
- #### Extensões de DSL (runtime nativo + custom)
220
+ #### Operadores e helpers de JSON Logic
215
221
 
216
- O runtime da tabela inclui helpers de JSON/tempo/listas/texto sem configuração extra:
222
+ O runtime da tabela já inclui operadores e helpers canônicos para JSON/tempo/listas/texto sem configuração extra:
217
223
 
218
224
  - JSON: `jsonGet`, `hasJsonKey`, `jsonPathMatches`, `jsonEq`, `jsonIn`, `jsonType`
219
225
  - Texto/valor: `isBlank`, `eqIgnoreCase`, `coalesce`
220
226
  - Faixas: `between`, `dateBetween`
221
- - Coleções: `containsAny`, `containsAll`, `len`, `lenEq`, `lenGt`, `lenLt`, `lenAtLeast`
227
+ - Coleções: `containsAny`, `containsAll`, `len`, `lenEq`, `lenGt`, `lenLt`, `lenAtLeast`
222
228
  - Tempo: `today`, `now`, `dateAdd`, `dateFormat`, `isToday`, `inLast`, `isPast`, `isPastOrNow`, `isFuture`, `isFutureOrNow`, `weekdayIn`
223
229
 
224
- Exemplos de DSL (canônica):
225
- - `jsonEq(payload, '$.user.name', 'Alice')`
226
- - `jsonIn(customer, '$.id', [10, 20])`
227
- - `eqIgnoreCase(status, 'ATIVO')`
228
- - `between(amount, 10, 20)`
229
- - `dateBetween(createdAt, '2025-01-01', '2025-12-31')`
230
- - `containsAll(tags, ['vip', 'gold'])`
231
-
232
- Observação de gramática:
233
- - comparações diretas sobre retorno de função (`fn(...) == 'x'`) não são suportadas pela gramática atual; prefira funções predicativas (booleanas) na `condition`.
230
+ Exemplos de JSON Logic:
231
+ - `{ "===": [{ "jsonGet": [{ "var": "payload" }, "$.user.name"] }, "Alice"] }`
232
+ - `{ "jsonIn": [{ "var": "customer" }, "$.id", [10, 20]] }`
233
+ - `{ "eqIgnoreCase": [{ "var": "status" }, "ATIVO"] }`
234
+ - `{ "between": [{ "var": "amount" }, 10, 20] }`
235
+ - `{ "dateBetween": [{ "var": "createdAt" }, "2025-01-01", "2025-12-31"] }`
236
+ - `{ "containsAll": [{ "var": "tags" }, ["vip", "gold"]] }`
234
237
 
235
- Guia completo: `projects/praxis-table/docs/DSL-Extensions-Guide.md`
238
+ Guia completo: `projects/praxis-table/docs/json-logic-operators-and-helpers.md`
236
239
 
237
- #### 🎨 Efeitos (Conteúdo C)
240
+ #### 🎨 Efeitos (Conteúdo C)
238
241
 
239
- O bloco de Efeitos permite aplicar estilo e visuais quando a condição é verdadeira:
242
+ O bloco de Efeitos permite aplicar estilo e visuais quando a condição é verdadeira:
240
243
 
241
- - Toolbar de texto com ícones (negrito, itálico, sublinhado) e presets rápidos (tachado, maiúsculas/minúsculas/capitalizar, tamanho +/- e reset).
242
- - Presets de feedback com ícones (sucesso, aviso, erro, info) mantêm o rótulo via tooltip e `aria-label`.
243
- - “Posição do valor como grupo de alternância (antes / entre-1 / entre-2 / depois / oculto).
244
- - Ordem dos visuais com seletor compacto (3 mais comuns) e menu para opções extras.
245
- - Layout do compose: espaçamento, alinhamento, quebra de linha e reticências.
244
+ - Toolbar de texto com ícones (negrito, itálico, sublinhado) e presets rápidos (tachado, maiúsculas/minúsculas/capitalizar, tamanho +/- e reset).
245
+ - Presets de feedback com ícones (sucesso, aviso, erro, info) — mantêm o rótulo via tooltip e `aria-label`.
246
+ - “Posição do valor” como grupo de alternância (antes / entre-1 / entre-2 / depois / oculto).
247
+ - “Ordem dos visuais” com seletor compacto (3 mais comuns) e menu para opções extras.
248
+ - Layout do compose: espaçamento, alinhamento, quebra de linha e reticências.
246
249
 
247
250
  Dicas
248
- - Use Resetar texto para reverter efeitos de texto sem perder cor de fundo/borda.
249
- - Para acessibilidade, os grupos possuem `role="toolbar"`, tooltips e navegação por teclado consistente.
251
+ - Use “Resetar texto” para reverter efeitos de texto sem perder cor de fundo/borda.
252
+ - Para acessibilidade, os grupos possuem `role="toolbar"`, tooltips e navegação por teclado consistente.
250
253
 
251
254
  Como reverter efeitos
252
- - Reset Text remove apenas propriedades de tipografia e transformação de texto.
253
- - Limpar efeitos apaga classe e estilo livres do bloco rápido.
255
+ - “Reset Text” remove apenas propriedades de tipografia e transformação de texto.
256
+ - “Limpar efeitos” apaga classe e estilo livres do bloco rápido.
254
257
 
255
- Observação: capturas de tela antes/depois podem ser adicionadas no PR conforme necessário.
258
+ Observação: capturas de tela “antes/depois” podem ser adicionadas no PR conforme necessário.
256
259
 
257
260
  #### Relacionais (lookup)
258
261
 
259
- Campos relacionais (FK/objetos) podem ser editados no Rules Editor com busca assíncrona (typeahead) e seleção single/multiple.
262
+ Campos relacionais (FK/objetos) podem ser editados no Rules Editor com busca assíncrona (typeahead) e seleção single/multiple.
260
263
 
261
- Boas práticas
264
+ Boas práticas
262
265
  - Informe `resourcePath` (ou `endpoint`) no `FieldDefinition` para habilitar o lookup via `GenericCrudService` do host.
263
- - Defina `valueField` (chave estável, tipicamente `id`) e `displayField` (label amigável, como `name`).
266
+ - Defina `valueField` (chave estável, tipicamente `id`) e `displayField` (label amigável, como `name`).
264
267
 
265
- ## 🔎 Filtro: Atalhos para Período (DateRange)
268
+ ## 🔎 Filtro: Atalhos para Período (DateRange)
266
269
 
267
- Habilite atalhos de período no filtro dinâmico sem alterar o contrato do `praxis-filter` apenas via metadata do campo:
270
+ Habilite atalhos de período no filtro dinâmico sem alterar o contrato do `praxis-filter` — apenas via metadata do campo:
268
271
 
269
272
  ```ts
270
273
  // Em FilterConfig (ou na metadata de campos do filtro)
271
274
  {
272
275
  name: 'period',
273
- label: 'Período',
276
+ label: 'Período',
274
277
  controlType: 'dateRange',
275
278
  showShortcuts: true,
276
279
  shortcuts: ['thisMonth','lastMonth','thisYear'],
277
280
  // Opcional:
278
- // i18nShortcuts: { thisMonth: 'Este mês', lastMonth: 'Mês passado' },
281
+ // i18nShortcuts: { thisMonth: 'Este mês', lastMonth: 'Mês passado' },
279
282
  // applyOnShortcutClick: true
280
283
  }
281
284
  ```
282
- - Para múltipla seleção, use `multiple: true` no `FieldDefinition` quando aplicável.
283
- - No runtime da tabela não é necessário registrar funções JSON/data manualmente; os helpers são embutidos.
284
- - APIs com busca: suporte a um parâmetro livre de texto (por ex. `search`) facilita a experiência do autocomplete.
285
+ - Para múltipla seleção, use `multiple: true` no `FieldDefinition` quando aplicável.
286
+ - No runtime da tabela não é necessário registrar funções JSON/data manualmente; os helpers já são embutidos.
287
+ - APIs com busca: suporte a um parâmetro livre de texto (por ex. `search`) facilita a experiência do autocomplete.
285
288
 
286
289
  Exemplo de FieldDefinition (lookup)
287
290
  ```ts
@@ -293,108 +296,107 @@ const fields: FieldDefinition[] = [
293
296
  type: 'object',
294
297
  // Habilita o lookup via GenericCrudService
295
298
  resourcePath: 'customers',
296
- // Mapeia o id/label que virão do backend
299
+ // Mapeia o id/label que virão do backend
297
300
  valueField: 'id',
298
301
  displayField: 'name',
299
- // Se quiser multiseleção em todo o app
302
+ // Se quiser multiseleção em todo o app
300
303
  // multiple: true,
301
304
  },
302
305
  ];
303
306
  ```
304
307
 
305
- Operadores e DSL gerada (relacional)
306
- - `id ==` `jsonEq(customer, '$.id', 10)`
307
- - `id in` `jsonIn(customer, '$.id', [10, 20])`
308
- - `has property` `hasJsonKey(customer, '$.meta.etag')`
309
- - Condições por caminho (join simples): use `key ==` (JSON Path + valor)
308
+ Operadores relacionais em JSON Logic
309
+ - `id ==` -> `{ "jsonEq": [{ "var": "customer" }, "$.id", 10] }`
310
+ - `id in` -> `{ "jsonIn": [{ "var": "customer" }, "$.id", [10, 20]] }`
311
+ - `has property` -> `{ "hasJsonKey": [{ "var": "customer" }, "$.meta.etag"] }`
312
+ - Condições por caminho (join simples): use `jsonEq/jsonIn` sobre o path necessário
310
313
 
311
314
  UI (no editor)
312
- - `id ==` (single): autocomplete + chip label [id] com ação Limpar”.
313
- - `id in` (multi): autocomplete + chips removíveis por item.
315
+ - `id ==` (single): autocomplete + chip “label [id]” com ação “Limpar”.
316
+ - `id in` (multi): autocomplete + chips removíveis por item.
314
317
  - `has property`: input do caminho (ex.: `$.meta.etag`).
315
318
 
316
319
  Formato esperado do payload (relacional)
317
320
 
318
- Para que o editor/preview e o runtime avaliem corretamente as regras relacionais, o valor do campo deve ser um objeto (ou compatível com JSON) contendo ao menos o identificador e, opcionalmente, propriedades exibidas:
321
+ Para que o editor/preview e o runtime avaliem corretamente as regras relacionais, o valor do campo deve ser um objeto (ou compatível com JSON) contendo ao menos o identificador e, opcionalmente, propriedades exibidas:
319
322
 
320
323
  ```ts
321
324
  // Exemplo de linha (row) com campo relacional "customer"
322
325
  const row = {
323
326
  id: 123,
324
327
  customer: {
325
- id: 10, // usado em id == / id in via jsonEq/jsonIn
326
- name: 'ACME', // usado para exibir label no autocomplete/chip
328
+ id: 10, // ← usado em id == / id in via jsonEq/jsonIn
329
+ name: 'ACME', // ← usado para exibir label no autocomplete/chip
327
330
  meta: { etag: 'v1' },
328
331
  },
329
332
  };
330
333
 
331
- // Regras DSL comuns
334
+ // Regras relacionais em JSON Logic
332
335
  // id ==
333
- // jsonEq(customer, '$.id', 10)
336
+ // { "jsonEq": [{ "var": "customer" }, "$.id", 10] }
334
337
  // id in
335
- // jsonIn(customer, '$.id', [10, 20])
338
+ // { "jsonIn": [{ "var": "customer" }, "$.id", [10, 20]] }
336
339
  // has property
337
- // hasJsonKey(customer, '$.meta.etag')
340
+ // { "hasJsonKey": [{ "var": "customer" }, "$.meta.etag"] }
338
341
  // caminho/valor (join simples)
339
- // jsonEq(customer, '$.name', 'ACME')
342
+ // { "jsonEq": [{ "var": "customer" }, "$.name", "ACME"] }
340
343
  ```
341
344
 
342
345
  Notas
343
- - O editor usa `displayField` (ex.: `name`) para compor o rótulo, e `valueField` (ex.: `id`) para gerar a DSL.
344
- - Se o backend devolver o relacionamento "normalizado" (ex.: `customerId` e `customerName` na mesma linha), você ainda pode expressar condições com operadores padrão (`==`, `in`) no campo numérico/literal a abordagem relacional é útil quando o payload contém o objeto.
346
+ - O editor usa `displayField` (ex.: `name`) para compor o rótulo, e `valueField` (ex.: `id`) para gerar o AST Json Logic correspondente.
347
+ - Se o backend devolver o relacionamento já "normalizado" (ex.: `customerId` e `customerName` na mesma linha), você ainda pode expressar condições com operadores padrão (`==`, `in`) no campo numérico/literal — a abordagem relacional é útil quando o payload contém o objeto.
345
348
 
346
- Onde é consumido (preview e runtime)
349
+ Onde é consumido (preview e runtime)
347
350
 
348
- - Preview/validação no Editor de Regras:
349
- - Authoring canônico manual e visual em JSON Logic: `projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts`
351
+ - Preview/validação no Editor de Regras:
352
+ - Authoring canônico manual e visual em JSON Logic: `projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts`
350
353
  - Runtime na Tabela (aplica `rowConditionalStyles`/`conditionalStyles`):
351
- - JSON Logic canônico + compatibilidade transitória de leitura DSL: `projects/praxis-table/src/lib/praxis-table.ts`
354
+ - JSON Logic canônico: `projects/praxis-table/src/lib/praxis-table.ts`
352
355
 
353
- Observação
354
- - JSON Logic é o contrato canônico para novas regras e para o editor de regras da tabela.
355
- - O runtime ainda mantém compatibilidade transitória para regras DSL antigas.
356
+ Observação
357
+ - JSON Logic é o contrato canônico para novas regras e para o editor de regras da tabela.
356
358
 
357
359
 
358
- ### ⚙️ Painel de Configurações
360
+ ### ⚙️ Painel de Configurações
359
361
 
360
- Para abrir o painel de configurações, habilite o modo de edição na tabela:
362
+ Para abrir o painel de configurações, habilite o modo de edição na tabela:
361
363
 
362
364
  ```html
363
365
  <praxis-table [enableCustomization]="true"></praxis-table>
364
366
  ```
365
367
 
366
- Um botão de engrenagem será exibido no canto superior direito. Ao clicar nele, o `SettingsPanel` é aberto permitindo ajustar:
368
+ Um botão de engrenagem será exibido no canto superior direito. Ao clicar nele, o `SettingsPanel` é aberto permitindo ajustar:
367
369
 
368
- - **Comportamento**: paginação, ordenação, filtros e recursos avançados.
370
+ - **Comportamento**: paginação, ordenação, filtros e recursos avançados.
369
371
  - **Colunas**: visibilidade, ordem, largura e estilo.
370
- - **Toolbar**: ações e botões da barra de ferramentas.
371
- - **Mensagens**: textos e rótulos exibidos na interface.
372
+ - **Toolbar**: ações e botões da barra de ferramentas.
373
+ - **Mensagens**: textos e rótulos exibidos na interface.
372
374
 
373
- As alterações podem ser aplicadas temporariamente com **Aplicar** ou salvas de forma persistente com **Salvar & Fechar**.
375
+ As alterações podem ser aplicadas temporariamente com **Aplicar** ou salvas de forma persistente com **Salvar & Fechar**.
374
376
 
375
- ## 🚀 Instalação
377
+ ## 🚀 Instalação
376
378
 
377
379
  ```bash
378
380
  npm install @praxisui/core @praxisui/table
379
381
  ```
380
382
 
381
- Peers necessários (instale no app host):
383
+ Peers necessários (instale no app host):
382
384
  - `@angular/core` `^20.0.0`, `@angular/common` `^20.0.0`
383
385
  - `@praxisui/core` `^0.0.1`
384
- - `@praxisui/dynamic-fields` `^0.0.1` (quando usar editores/inputs dinâmicos)
385
- - `@praxisui/dynamic-form` `^0.0.1` (quando integrar com formulários dinâmicos)
386
- - `@praxisui/settings-panel` `^0.0.1` (para painel de configuração embutido)
386
+ - `@praxisui/dynamic-fields` `^0.0.1` (quando usar editores/inputs dinâmicos)
387
+ - `@praxisui/dynamic-form` `^0.0.1` (quando integrar com formulários dinâmicos)
388
+ - `@praxisui/settings-panel` `^0.0.1` (para painel de configuração embutido)
387
389
 
388
- ## 📝 Uso Básico
390
+ ## 📝 Uso Básico
389
391
 
390
392
  ### Conectando ao Backend com `resourcePath`
391
393
 
392
- A forma mais poderosa de usar a `<praxis-table>` é conectá-la diretamente a um endpoint de API compatível com o ecossistema Praxis. Isso é feito através do input `resourcePath`.
394
+ A forma mais poderosa de usar a `<praxis-table>` é conectá-la diretamente a um endpoint de API compatível com o ecossistema Praxis. Isso é feito através do input `resourcePath`.
393
395
 
394
- Quando `resourcePath` é fornecido, a tabela se torna "inteligente":
396
+ Quando `resourcePath` é fornecido, a tabela se torna "inteligente":
395
397
 
396
- 1. **Busca automática de dados**: A tabela gerencia a paginação, ordenação e filtros, fazendo as requisições necessárias ao backend.
397
- 2. **Geração dinâmica de colunas**: A tabela busca os metadados (schema) do backend para gerar as colunas automaticamente, respeitando as configurações definidas no `praxis-metadata-core` (via anotação `@UISchema`).
398
+ 1. **Busca automática de dados**: A tabela gerencia a paginação, ordenação e filtros, fazendo as requisições necessárias ao backend.
399
+ 2. **Geração dinâmica de colunas**: A tabela busca os metadados (schema) do backend para gerar as colunas automaticamente, respeitando as configurações definidas no `praxis-metadata-core` (via anotação `@UISchema`).
398
400
 
399
401
  ```html
400
402
  <!-- Exemplo no template do seu componente -->
@@ -404,12 +406,12 @@ Quando `resourcePath` é fornecido, a tabela se torna "inteligente":
404
406
  Neste exemplo:
405
407
 
406
408
  - `resourcePath="human-resources/departamentos"` instrui a tabela a se comunicar com o endpoint `/api/human-resources/departamentos`.
407
- - A tabela fará requisições como `POST /api/human-resources/departamentos/filter` para obter os dados e `GET /schemas/filtered?path=/api/human-resources/departamentos/all&operation=get&schemaType=response` para obter o schema estrutural usado no bootstrap das colunas.
408
- - `enableCustomization` controla explicitamente o gate de edição visual. O default canônico agora é `false`; declare `[enableCustomization]="true"` quando o host quiser expor customização e surfaces editoriais.
409
+ - A tabela fará requisições como `POST /api/human-resources/departamentos/filter` para obter os dados e `GET /schemas/filtered?path=/api/human-resources/departamentos/all&operation=get&schemaType=response` para obter o schema estrutural usado no bootstrap das colunas.
410
+ - `enableCustomization` controla explicitamente o gate de edição visual. O default canônico agora é `false`; declare `[enableCustomization]="true"` quando o host quiser expor customização e surfaces editoriais.
409
411
 
410
412
  ### Consulta Declarativa com `queryContext`
411
413
 
412
- Para orquestração entre widgets em `praxis-dynamic-page`, o contrato semântico primário da tabela passa a ser `queryContext`.
414
+ Para orquestração entre widgets em `praxis-dynamic-page`, o contrato semântico primário da tabela passa a ser `queryContext`.
413
415
 
414
416
  ```html
415
417
  <praxis-table
@@ -424,23 +426,23 @@ Para orquestração entre widgets em `praxis-dynamic-page`, o contrato semântic
424
426
 
425
427
  Regras atuais:
426
428
 
427
- - `queryContext.filters` participa do pipeline efetivo da tabela
429
+ - `queryContext.filters` já participa do pipeline efetivo da tabela
428
430
  - `filterCriteria` continua aceito como bridge legada de compatibilidade
429
431
  - em novo authoring, examples e bindings, prefira `queryContext`
430
432
 
431
433
  ### Empty State + Quick Connect (sem `resourcePath`)
432
434
 
433
- Se a tabela for renderizada sem `resourcePath`, um cartão de "Empty State" é exibido convidando a conectar o componente a um recurso. Basta clicar em "Conectar a recurso" para abrir um painel rápido com um único campo:
435
+ Se a tabela for renderizada sem `resourcePath`, um cartão de "Empty State" é exibido convidando a conectar o componente a um recurso. Basta clicar em "Conectar a recurso" para abrir um painel rápido com um único campo:
434
436
 
435
437
  ```text
436
438
  resourcePath: ex.: human-resources/departamentos
437
439
  ```
438
440
 
439
- Ao aplicar/salvar, a `<praxis-table>` é automaticamente configurada para buscar o schema e os dados do backend. Esse fluxo evita telas em branco e simplifica o onboarding do componente em páginas novas.
441
+ Ao aplicar/salvar, a `<praxis-table>` é automaticamente configurada para buscar o schema e os dados do backend. Esse fluxo evita telas em branco e simplifica o onboarding do componente em páginas novas.
440
442
 
441
- ### Fluxo de Comunicação do `resourcePath`
443
+ ### Fluxo de Comunicação do `resourcePath`
442
444
 
443
- O diagrama abaixo ilustra como a propriedade `resourcePath` conecta o componente frontend ao backend no runtime atual da tabela. Antes de iniciar o fluxo remoto, a lib resolve o modo de dados com precedência **`resourcePath` explícito > `data` local > conexão persistida**. Quando o modo efetivo é `remote`, o bootstrap ocorre em três etapas principais: **Configurar**, **Carregar Schema estrutural** e **Buscar Dados**.
445
+ O diagrama abaixo ilustra como a propriedade `resourcePath` conecta o componente frontend ao backend no runtime atual da tabela. Antes de iniciar o fluxo remoto, a lib resolve o modo de dados com precedência **`resourcePath` explícito > `data` local > conexão persistida**. Quando o modo efetivo é `remote`, o bootstrap ocorre em três etapas principais: **Configurar**, **Carregar Schema estrutural** e **Buscar Dados**.
444
446
 
445
447
  ```mermaid
446
448
  sequenceDiagram
@@ -455,7 +457,7 @@ sequenceDiagram
455
457
 
456
458
  activate Praxis_Table
457
459
  Praxis_Table->>Praxis_Table: ngOnInit()/ngOnChanges() resolve dataMode
458
- Note over Praxis_Table: remote quando resourcePath efetivo
460
+ Note over Praxis_Table: remote quando há resourcePath efetivo
459
461
  Praxis_Table->>Crud_Service: 1. Chama crudService.configure("human-resources/departamentos")
460
462
 
461
463
  activate Crud_Service
@@ -466,7 +468,7 @@ sequenceDiagram
466
468
  Praxis_Table->>Crud_Service: Chama crudService.getSchema()
467
469
 
468
470
  activate Crud_Service
469
- Crud_Service->>Crud_Service: schemaUrl() preserva o base path canônico
471
+ Crud_Service->>Crud_Service: schemaUrl() preserva o base path canônico
470
472
  Crud_Service->>Crud_Service: Deriva path="/api/human-resources/departamentos/all"<br>operation="get", schemaType="response"
471
473
  Crud_Service->>Docs_Controller: GET /schemas/filtered?path=.../all&operation=get&schemaType=response
472
474
  deactivate Crud_Service
@@ -481,21 +483,21 @@ sequenceDiagram
481
483
  Crud_Service-->>Praxis_Table: Normaliza schema e retorna FieldDefinition[]
482
484
  deactivate Crud_Service
483
485
 
484
- Praxis_Table->>Praxis_Table: Constrói as colunas da tabela<br>a partir do schema recebido
486
+ Praxis_Table->>Praxis_Table: Constrói as colunas da tabela<br>a partir do schema recebido
485
487
 
486
488
  Praxis_Table->>Praxis_Table: 3. Chama this.fetchData()
487
489
  Praxis_Table->>Crud_Service: Chama crudService.filter(...) para buscar dados
488
490
 
489
491
  activate Crud_Service
490
- Crud_Service->>Crud_Service: getEndpointUrl('filter') constrói a URL: <br> "/api/human-resources/departamentos/filter"
491
- Crud_Service->>BE_Controller: Requisição HTTP POST para .../filter
492
+ Crud_Service->>Crud_Service: getEndpointUrl('filter') constrói a URL: <br> "/api/human-resources/departamentos/filter"
493
+ Crud_Service->>BE_Controller: Requisição HTTP POST para .../filter
492
494
  deactivate Crud_Service
493
495
 
494
496
  activate BE_Controller
495
- BE_Controller->>Abstract_Controller: Herda o método que lida com @PostMapping("/filter")
497
+ BE_Controller->>Abstract_Controller: Herda o método que lida com @PostMapping("/filter")
496
498
 
497
499
  activate Abstract_Controller
498
- Abstract_Controller->>Abstract_Controller: Processa a requisição e busca os dados
500
+ Abstract_Controller->>Abstract_Controller: Processa a requisição e busca os dados
499
501
  Abstract_Controller-->>BE_Controller: Retorna os dados
500
502
  deactivate Abstract_Controller
501
503
 
@@ -512,21 +514,21 @@ sequenceDiagram
512
514
 
513
515
  Notas importantes:
514
516
 
515
- - O host informa `resourcePath` sem o prefixo `/api`; o `GenericCrudService` resolve as URLs reais do backend a partir da configuração de API do host.
516
- - O bootstrap de schema não depende mais de uma chamada frontend para `GET /{resource}/schemas`; o runtime consome diretamente `/schemas/filtered` com `ETag`/`X-Schema-Hash`.
517
+ - O host informa `resourcePath` sem o prefixo `/api`; o `GenericCrudService` resolve as URLs reais do backend a partir da configuração de API do host.
518
+ - O bootstrap de schema não depende mais de uma chamada frontend para `GET /{resource}/schemas`; o runtime consome diretamente `/schemas/filtered` com `ETag`/`X-Schema-Hash`.
517
519
  - O `praxis-filter` acoplado acompanha o mesmo `resourcePath` em modo remoto e deriva seu schema via `/schemas/filtered?path=.../filter&operation=post&schemaType=request`.
518
- - Sem `resourcePath` efetivo, a tabela não entra nesse fluxo remoto; ela cai em `local` ou `empty` conforme a precedência canônica.
520
+ - Sem `resourcePath` efetivo, a tabela não entra nesse fluxo remoto; ela cai em `local` ou `empty` conforme a precedência canônica.
519
521
 
520
- ## ℹ️ Dicas de UX (Tabela)
522
+ ## ℹ️ Dicas de UX (Tabela)
521
523
 
522
- - Multisort: habilite em Comportamento Ordenação. No uso, mantenha Ctrl/Cmd pressionado ao clicar em múltiplas colunas.
523
- - Duplo clique na linha: configure em Comportamento Interação (habilitar e escolha a ação: editar/visualizar/personalizada).
524
- - Virtualização: habilite em Comportamento Virtualização para listas grandes (requer altura de linha previsível).
525
- - Densidade e linhas de grade: ajuste em Comportamento Aparência rápida (compacta/confortável/espaçosa; bordas horizontais/verticais).
524
+ - Multi‑sort: habilite em Comportamento → Ordenação. No uso, mantenha Ctrl/Cmd pressionado ao clicar em múltiplas colunas.
525
+ - Duplo clique na linha: configure em Comportamento → Interação (habilitar e escolha a ação: editar/visualizar/personalizada).
526
+ - Virtualização: habilite em Comportamento → Virtualização para listas grandes (requer altura de linha previsível).
527
+ - Densidade e linhas de grade: ajuste em Comportamento → Aparência rápida (compacta/confortável/espaçosa; bordas horizontais/verticais).
526
528
 
527
529
  ## Rolagem Horizontal (owner do scroll)
528
530
 
529
- Por padrão, a `<praxis-table>` agora assume a responsabilidade pela rolagem horizontal quando o conteúdo excede a largura do container. Isso evita cortes de conteúdo e comportamentos inconsistentes entre projetos.
531
+ Por padrão, a `<praxis-table>` agora assume a responsabilidade pela rolagem horizontal quando o conteúdo excede a largura do container. Isso evita cortes de conteúdo e comportamentos inconsistentes entre projetos.
530
532
 
531
533
  ### Input: `horizontalScroll`
532
534
 
@@ -534,17 +536,17 @@ Por padrão, a `<praxis-table>` agora assume a responsabilidade pela rolagem hor
534
536
  @Input() horizontalScroll: 'auto' | 'wrap' | 'none' = 'auto';
535
537
  ```
536
538
 
537
- - `auto` (padrão): a tabela cria um viewport com `overflow-x: auto` e permite que a tabela interna cresça com `width: max-content`. Quando a soma das colunas > container, aparece a barra de rolagem horizontal neste viewport.
538
- - `wrap`: permite quebra de linha nas células (libera `white-space: normal`), reduzindo a largura necessária; ideal quando você prefere minimizar a rolagem horizontal.
539
- - `none`: desabilita o comportamento interno; o host (página) deve fornecer o container com `overflow-x: auto` e as regras de largura necessárias.
539
+ - `auto` (padrão): a tabela cria um viewport com `overflow-x: auto` e permite que a tabela interna cresça com `width: max-content`. Quando a soma das colunas > container, aparece a barra de rolagem horizontal neste viewport.
540
+ - `wrap`: permite quebra de linha nas células (libera `white-space: normal`), reduzindo a largura necessária; ideal quando você prefere minimizar a rolagem horizontal.
541
+ - `none`: desabilita o comportamento interno; o host (página) deve fornecer o container com `overflow-x: auto` e as regras de largura necessárias.
540
542
 
541
543
  Exemplo:
542
544
 
543
545
  ```html
544
- <!-- Comportamento padrão (auto) -->
546
+ <!-- Comportamento padrão (auto) -->
545
547
  <praxis-table resourcePath="employees"></praxis-table>
546
548
 
547
- <!-- Reduz rolagem: permite quebra de linha nas células -->
549
+ <!-- Reduz rolagem: permite quebra de linha nas células -->
548
550
  <praxis-table resourcePath="employees" horizontalScroll="wrap"></praxis-table>
549
551
 
550
552
  <!-- Host controla o scroll horizontal -->
@@ -554,28 +556,28 @@ Exemplo:
554
556
  </div>
555
557
  ```
556
558
 
557
- ### Editor de Configuração (Settings Panel)
559
+ ### Editor de Configuração (Settings Panel)
558
560
 
559
- Na aba “Visão Geral & Comportamento”, um seletor Scroll Horizontal com as opções `Auto`, `Wrap` e `Host` (none). As alterações podem ser aplicadas (Aplicar) ou salvas (Salvar & Fechar). O valor é persistido junto com outras preferências da tabela.
561
+ Na aba “Visão Geral & Comportamento”, há um seletor “Scroll Horizontal” com as opções `Auto`, `Wrap` e `Host` (none). As alterações podem ser aplicadas (Aplicar) ou salvas (Salvar & Fechar). O valor é persistido junto com outras preferências da tabela.
560
562
 
561
563
  ### Notas
562
564
 
563
- - O caminho virtual (CDK Virtual Scroll) permanece sendo o owner da rolagem vertical; o viewport horizontal é um contêiner externo que não interfere no scroll vertical.
564
- - Cabeçalho sticky continua funcional. Teste combinações com colunas sticky/virt para seu caso.
565
+ - O caminho virtual (CDK Virtual Scroll) permanece sendo o owner da rolagem vertical; o viewport horizontal é um contêiner externo que não interfere no scroll vertical.
566
+ - Cabeçalho sticky continua funcional. Teste combinações com colunas sticky/virt para seu caso.
565
567
  - Para grids alternativos (ex.: Kendo), as mesmas regras de `max-content`/`min-width: 100%` se aplicam ao elemento de tabela interno.
566
568
 
567
- ## Virtualização (CDK)
569
+ ## Virtualização (CDK)
568
570
 
569
- Quando `behavior.virtualization.enabled` estiver ativo, as linhas da tabela são renderizadas com `cdk-virtual-scroll-viewport` (cabeçalho permanece igual).
571
+ Quando `behavior.virtualization.enabled` estiver ativo, as linhas da tabela são renderizadas com `cdk-virtual-scroll-viewport` (cabeçalho permanece igual).
570
572
 
571
573
  - Propriedades:
572
- - `itemHeight`: altura da linha (px); padrão 44.
574
+ - `itemHeight`: altura da linha (px); padrão 44.
573
575
  - `bufferSize`: itens adicionais de buffer.
574
- - `minContainerHeight`: altura mínima do viewport (px ou CSS, ex.: `320` ou `50vh`).
575
- - `strategy`: `fixed` | `dynamic` (atual uso visual não altera lógica de medição).
576
- - Observação: sticky/pinned em colunas pode ter limitações em conjunto com virtual scroll (mantido sob feature flag; caminho não‑virtual preservado como fallback).
576
+ - `minContainerHeight`: altura mínima do viewport (px ou CSS, ex.: `320` ou `50vh`).
577
+ - `strategy`: `fixed` | `dynamic` (atual uso visual não altera lógica de medição).
578
+ - Observação: sticky/pinned em colunas pode ter limitações em conjunto com virtual scroll (mantido sob feature flag; caminho não‑virtual preservado como fallback).
577
579
 
578
- ## Paginação (posição/estilo)
580
+ ## Paginação (posição/estilo)
579
581
 
580
582
  ### Concept Usage
581
583
 
@@ -587,16 +589,16 @@ Quando `behavior.virtualization.enabled` estiver ativo, as linhas da tabela são
587
589
  - `behavior.pagination.position`: `top` | `bottom` | `both`.
588
590
  - `behavior.pagination.style`: `default` | `compact` (aplica classe de estilo no paginator).
589
591
 
590
- Nota sobre estratégia (client vs server)
591
- - Se `behavior.pagination.strategy` não estiver definido, a tabela assume `server` automaticamente quando `resourcePath` (dados remotos). Caso contrário, usa `client`.
592
+ Nota sobre estratégia (client vs server)
593
+ - Se `behavior.pagination.strategy` não estiver definido, a tabela assume `server` automaticamente quando há `resourcePath` (dados remotos). Caso contrário, usa `client`.
592
594
  - O mesmo vale para `behavior.sorting.strategy`.
593
595
 
594
596
  ## Duplo clique na linha
595
597
 
596
- Ative em Comportamento Interação.
598
+ Ative em Comportamento → Interação.
597
599
 
598
600
  - Output: `rowDoubleClick` com payload `{ action: string; row: any }`.
599
- - Ação: `edit` | `view` | `custom` (quando `custom`, use `customAction` no Behavior para definir o identificador).
601
+ - Ação: `edit` | `view` | `custom` (quando `custom`, use `customAction` no Behavior para definir o identificador).
600
602
 
601
603
  Exemplo de uso (template do host):
602
604
 
@@ -615,16 +617,16 @@ onRowDoubleClick(evt: { action: string; row: any }) {
615
617
  } else if (evt.action === 'view') {
616
618
  // abrir detalhe somente leitura
617
619
  } else {
618
- // ação customizada
620
+ // ação customizada
619
621
  }
620
622
  }
621
623
  ```
622
624
 
623
- ## Ordenação inicial (defaultSort)
625
+ ## Ordenação inicial (defaultSort)
624
626
 
625
627
  - Configure em `behavior.sorting.defaultSort`.
626
- - Aceita objeto único (coluna/direção) ou array para multisort.
627
- - Status runtime atual: `behavior.sorting.multiSort` está **schema-only** (apenas 1 critério efetivo em runtime).
628
+ - Aceita objeto único (coluna/direção) ou array para multi‑sort.
629
+ - Status runtime atual: `behavior.sorting.multiSort` está **schema-only** (apenas 1 critério efetivo em runtime).
628
630
 
629
631
  Exemplos:
630
632
 
@@ -649,20 +651,20 @@ sorting: {
649
651
  }
650
652
  ```
651
653
 
652
- Observação: quando informado, o defaultSort é aplicado na carga inicial se não houver estado de ordenação ativo.
653
- Observação enterprise: para evitar ambiguidade de contrato, mantenha `multiSort: false` no runtime atual. Se um array for informado em `defaultSort`, trate como payload de compatibilidade/roadmap e valide no host como single-sort efetivo.
654
+ Observação: quando informado, o defaultSort é aplicado na carga inicial se não houver estado de ordenação ativo.
655
+ Observação enterprise: para evitar ambiguidade de contrato, mantenha `multiSort: false` no runtime atual. Se um array for informado em `defaultSort`, trate como payload de compatibilidade/roadmap e valide no host como single-sort efetivo.
654
656
 
655
- ### Roadmap / migração de multiSort
657
+ ### Roadmap / migração de multiSort
656
658
 
657
659
  - Curto prazo: `multiSort` segue schema-only no runtime.
658
- - Recomendação de migração: desenhar integrações com fallback para ordenação única (`column` + `direction`).
659
- - Planejamento: quando multi-sort runtime for implementado, publicar release note com guia de ativação gradual (feature-flag + validação de payload legado).
660
+ - Recomendação de migração: desenhar integrações com fallback para ordenação única (`column` + `direction`).
661
+ - Planejamento: quando multi-sort runtime for implementado, publicar release note com guia de ativação gradual (feature-flag + validação de payload legado).
660
662
 
661
- ## Coluna de ações (sticky)
663
+ ## Coluna de ações (sticky)
662
664
 
663
- Nota: por padrão a coluna de ações vem desabilitada. Habilite explicitamente em `actions.row.enabled` e defina as ações desejadas.
665
+ Nota: por padrão a coluna de ações vem desabilitada. Habilite explicitamente em `actions.row.enabled` e defina as ações desejadas.
664
666
 
665
- - Fixe a coluna de ações no início/fim configurando `actions.row.sticky`:
667
+ - Fixe a coluna de ações no início/fim configurando `actions.row.sticky`:
666
668
 
667
669
  ```ts
668
670
  actions: {
@@ -675,11 +677,11 @@ actions: {
675
677
  }
676
678
  ```
677
679
 
678
- Observação: em modo virtualizado, sticky pode ter limitações dependendo do layout.
680
+ Observação: em modo virtualizado, sticky pode ter limitações dependendo do layout.
679
681
 
680
682
  ## Colunas de dados (sticky)
681
683
 
682
- Fixe colunas específicas no início/fim usando `columns[].sticky`:
684
+ Fixe colunas específicas no início/fim usando `columns[].sticky`:
683
685
 
684
686
  ```ts
685
687
  columns: [
@@ -690,28 +692,28 @@ columns: [
690
692
  ```
691
693
 
692
694
  - Valores aceitos: `true` | `'start'` | `'end'`.
693
- - `true` equivale a `'start'` (fixa no início).
695
+ - `true` equivale a `'start'` (fixa no início).
694
696
  - Dica: combine com `width` para evitar jitter de layout.
695
697
 
696
698
  Onde configurar no Editor Visual:
697
699
 
698
- - Aba Colunas grupo “Posição Fixa”: escolha entre Nenhum / Início / Fim.
699
- - Para a coluna de ações, use a aba Barra de Ferramentas & Ações” grupo Coluna de Ações” Fixar coluna de ações”.
700
+ - Aba “Colunas” → grupo “Posição Fixa”: escolha entre Nenhum / Início / Fim.
701
+ - Para a coluna de ações, use a aba “Barra de Ferramentas & Ações” → grupo “Coluna de Ações” → “Fixar coluna de ações”.
700
702
 
701
- ## 🔒 Verificação de Schema (ETag) e Notificações (somente em customização)
703
+ ## 🔒 Verificação de Schema (ETag) e Notificações (somente em customização)
702
704
 
703
- Quando existe uma configuração salva (colunas presentes), a tabela não baixa o schema bruto do servidor para montar as colunas. Em vez disso, valida se uma nova versão do schema usando ETag/If-None-Match. Notificações são exibidas somente quando o modo de customização está ativo (`enableCustomization = true`).
705
+ Quando já existe uma configuração salva (colunas presentes), a tabela não baixa o schema bruto do servidor para montar as colunas. Em vez disso, valida se há uma nova versão do schema usando ETag/If-None-Match. Notificações são exibidas somente quando o modo de customização está ativo (`enableCustomization = true`).
704
706
 
705
707
  ### Comportamento
706
708
 
707
709
  - Primeira vez (sem colunas):
708
710
  - Baixa o schema (200), gera as colunas e persiste `config.meta` (incluindo `schemaId`, `serverHash`, `lastVerifiedAt`).
709
- - Próximas vezes (colunas existentes):
710
- - Faz uma verificação leve em `/schemas/filtered` com `If-None-Match: "<serverHash>"`.
711
- - 304 Not Modified: atualiza `config.meta.lastVerifiedAt` e segue usando a configuração local.
712
- - 200 OK (hash mudou): atualiza `config.meta.serverHash/lastVerifiedAt`, marca estado `schemaOutdated=true` e (em modo de customização) exibe aviso e CTA para reconciliar. O schema bruto não é usado/armazenado nesta etapa.
711
+ - Próximas vezes (colunas já existentes):
712
+ - Faz uma verificação leve em `/schemas/filtered` com `If-None-Match: "<serverHash>"`.
713
+ - 304 Not Modified: atualiza `config.meta.lastVerifiedAt` e segue usando a configuração local.
714
+ - 200 OK (hash mudou): atualiza `config.meta.serverHash/lastVerifiedAt`, marca estado `schemaOutdated=true` e (em modo de customização) exibe aviso e CTA para reconciliar. O schema bruto não é usado/armazenado nesta etapa.
713
715
 
714
- ### Diagrama: Verificação de Schema via ETag
716
+ ### Diagrama: Verificação de Schema via ETag
715
717
 
716
718
  ```mermaid
717
719
  sequenceDiagram
@@ -728,15 +730,15 @@ sequenceDiagram
728
730
  PT->>PT: Persiste config + meta (serverHash, lastVerifiedAt)
729
731
  end
730
732
 
731
- opt Próximas vezes (colunas existentes)
733
+ opt Próximas vezes (colunas existentes)
732
734
  PT->>API: GET /schemas/filtered?path=... (If-None-Match: "<serverHash>")
733
- alt Igual (sem mudanças)
735
+ alt Igual (sem mudanças)
734
736
  API-->>PT: 304 Not Modified (sem body)
735
737
  PT->>PT: Atualiza lastVerifiedAt; segue usando config
736
738
  else Diferente (mudou)
737
739
  API-->>PT: 200 OK (com ETag/X-Schema-Hash)
738
740
  PT->>PT: Atualiza serverHash + lastVerifiedAt; schemaOutdated=true
739
- Note over PT: Em customização: mostrar banner/snackbar + badge e CTA Reconciliar
741
+ Note over PT: Em customização: mostrar banner/snackbar + badge e CTA “Reconciliar”
740
742
  end
741
743
  end
742
744
  ```
@@ -749,30 +751,30 @@ sequenceDiagram
749
751
  - `autoOpenSettingsOnOutdated: boolean = false`
750
752
  - Outputs:
751
753
  - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; trigger?: string; tableId?: string }`
752
- - Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via `loadSchema()`).
754
+ - Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via `loadSchema()`).
753
755
  - `metadataChange: { trigger: string; meta: any; tableId?: string }`
754
- - Emitido quando `config.meta` é atualizado (ex.: após bootstrap ou verificação ETag). Útil para sincronizar sidebars/bridges de metadados.
756
+ - Emitido quando `config.meta` é atualizado (ex.: após bootstrap ou verificação ETag). Útil para sincronizar sidebars/bridges de metadados.
755
757
 
756
758
  ### Fallback Global (opcional)
757
759
 
758
- - Quando os inputs do widget permanecem com os valores padrão da biblioteca e não overrides locais equivalentes, a Tabela aplica como último fallback as preferências globais lidas via `GlobalConfigService.getSchemaPrefsGlobal()`.
759
- - Cadeia de precedência (inalterada): `@Inputs (widget)` Prefs do widget Prefs da página Prefs globais Defaults.
760
- - Não persistência no widget a partir das globais; o fallback é aplicado somente em memória.
760
+ - Quando os inputs do widget permanecem com os valores padrão da biblioteca e não há overrides locais equivalentes, a Tabela aplica como último fallback as preferências globais lidas via `GlobalConfigService.getSchemaPrefsGlobal()`.
761
+ - Cadeia de precedência (inalterada): `@Inputs (widget)` → Prefs do widget → Prefs da página → Prefs globais → Defaults.
762
+ - Não há persistência no widget a partir das globais; o fallback é aplicado somente em memória.
761
763
 
762
- ### Persistência por hash (ConfigStorage)
764
+ ### Persistência por hash (ConfigStorage)
763
765
 
764
- - `schemaIgnore:{tableId}:{serverHash}` ignora avisos para este hash.
765
- - `schemaSnooze:{tableId}:{serverHash}` ISODate até quando não avisar (lembrar depois).
766
- - `schemaNotified:{tableId}:{serverHash}` evita snackbar duplicado.
766
+ - `schemaIgnore:{tableId}:{serverHash}` → ignora avisos para este hash.
767
+ - `schemaSnooze:{tableId}:{serverHash}` → ISODate até quando não avisar (lembrar depois).
768
+ - `schemaNotified:{tableId}:{serverHash}` → evita snackbar duplicado.
767
769
 
768
770
  ### UX
769
771
 
770
- - Banner inline (acima da tabela) quando `schemaOutdated=true`, com ações:
771
- - Reconciliar (abre Configurações)
772
+ - Banner inline (acima da tabela) quando `schemaOutdated=true`, com ações:
773
+ - Reconciliar (abre Configurações)
772
774
  - Lembrar depois (snooze)
773
775
  - Ignorar (silenciar para este hash)
774
- - Snackbar opcional (uma vez por hash) com ação Reconciliar”.
775
- - Badge “!” na engrenagem com tooltip contextual: Schema do servidor mudou Reconciliar”.
776
+ - Snackbar opcional (uma vez por hash) com ação “Reconciliar”.
777
+ - Badge “!” na engrenagem com tooltip contextual: “Schema do servidor mudou — Reconciliar”.
776
778
 
777
779
  ### Exemplo de uso
778
780
 
@@ -798,56 +800,56 @@ onSchemaStatus(ev: { outdated: boolean; serverHash?: string; lastVerifiedAt?: st
798
800
 
799
801
  ### Notas
800
802
 
801
- - A verificação leve não grava nem usa o schema bruto quando `config.columns` existe.
802
- - Em ambientes sem customização (`enableCustomization=false`), não notificações visuais; ainda assim `schemaStatusChange` é emitido e `config.meta.lastVerifiedAt` atualizado.
803
+ - A verificação leve não grava nem usa o schema bruto quando `config.columns` já existe.
804
+ - Em ambientes sem customização (`enableCustomization=false`), não há notificações visuais; ainda assim `schemaStatusChange` é emitido e `config.meta.lastVerifiedAt` atualizado.
803
805
 
804
- ## Filtro Avançado (PraxisFilter)
806
+ ## Filtro Avançado (PraxisFilter)
805
807
 
806
- ### Boas práticas para estabilidade
808
+ ### Boas práticas para estabilidade
807
809
 
808
- - Evite literais em bindings para o carregador dinâmico:
809
- - Não use `[fields]="[pinnedFieldMeta]"`; prefira um array estável como `pinnedFieldMetaArray` atualizado apenas quando o metadata mudar.
810
- - Reutilize `FormGroup` quando possível. Se precisar trocar o `FormGroup` sem mudar os campos, deixe o `DynamicFieldLoader` reatribuir os controles (rebind-only) em vez de recriar componentes.
811
- - Evite recriar arrays/objetos desnecessariamente em `ngOnChanges`/`ngAfterViewInit`. Prefira atualizar valores (`setValue`, `patchValue`) e manter referências estáveis.
812
- - Observers (Resize/Mutation): atualize `overlayOrigin` e largura apenas quando houver mudanças reais; isso evita loops de CD.
810
+ - Evite literais em bindings para o carregador dinâmico:
811
+ - Não use `[fields]="[pinnedFieldMeta]"`; prefira um array estável como `pinnedFieldMetaArray` atualizado apenas quando o metadata mudar.
812
+ - Reutilize `FormGroup` quando possível. Se precisar trocar o `FormGroup` sem mudar os campos, deixe o `DynamicFieldLoader` reatribuir os controles (rebind-only) em vez de recriar componentes.
813
+ - Evite recriar arrays/objetos desnecessariamente em `ngOnChanges`/`ngAfterViewInit`. Prefira atualizar valores (`setValue`, `patchValue`) e manter referências estáveis.
814
+ - Observers (Resize/Mutation): atualize `overlayOrigin` e largura apenas quando houver mudanças reais; isso evita loops de CD.
813
815
 
814
- ### Diagnóstico e Logs
816
+ ### Diagnóstico e Logs
815
817
 
816
- - O `DynamicFieldLoader` possui logs de diagnóstico que podem ser habilitados em tempo de execução definindo `window.__PRAXIS_DEBUG_DFL__ = true` no console do navegador.
818
+ - O `DynamicFieldLoader` possui logs de diagnóstico que podem ser habilitados em tempo de execução definindo `window.__PRAXIS_DEBUG_DFL__ = true` no console do navegador.
817
819
  - Quando desabilitado (default), o carregador reduz a verbosidade de logs.
818
820
 
819
821
  ### Comportamento do carregador (v20+)
820
822
 
821
- - Guardas internas evitam re-renderizações desnecessárias:
822
- - Se o snapshot do conteúdo dos campos (nome + controlType) for idêntico e o `FormGroup` não tiver mudado, a renderização é ignorada.
823
- - Se apenas o `FormGroup` mudou (mesmo snapshot de campos), os controles são reatribuídos aos componentes existentes (rebind-only), preservando o estado visual e evitando recriações.
823
+ - Guardas internas evitam re-renderizações desnecessárias:
824
+ - Se o snapshot do conteúdo dos campos (nome + controlType) for idêntico e o `FormGroup` não tiver mudado, a renderização é ignorada.
825
+ - Se apenas o `FormGroup` mudou (mesmo snapshot de campos), os controles são reatribuídos aos componentes existentes (rebind-only), preservando o estado visual e evitando recriações.
824
826
 
825
827
  ### Testes
826
828
 
827
- - testes cobrindo:
828
- - Reatribuição de `FormControl` em troca de `FormGroup` (select/multiselect/autocomplete).
829
- - Ignorar re-render quando apenas a referência do array muda mas o conteúdo é igual.
829
+ - Há testes cobrindo:
830
+ - Reatribuição de `FormControl` em troca de `FormGroup` (select/multiselect/autocomplete).
831
+ - Ignorar re-render quando apenas a referência do array muda mas o conteúdo é igual.
830
832
  - Recriar componentes quando `controlType` muda.
831
833
 
832
834
  ### Fluxo de Schema e Metadados
833
835
 
834
836
  - O `PraxisFilter` busca schema do DTO de filtro via `/schemas/filtered` com ETag/If-None-Match
835
837
  e emite `metaChanged` com `{ schemaId, serverHash, context }`.
836
- - O schema é normalizado e `advancedConfig.metadata` é preenchido para auditoria/telemetria.
837
- - Detalhes: `projects/praxis-core/docs/schema-flow.md` (canônico) e `docs/schemas/fluxo-schema.md` (resumo operacional) para cliente/caching, 200/304 e reconciliadores Form/Filter.
838
+ - O schema é normalizado e `advancedConfig.metadata` é preenchido para auditoria/telemetria.
839
+ - Detalhes: `projects/praxis-core/docs/schema-flow.md` (canônico) e `docs/schemas/fluxo-schema.md` (resumo operacional) para cliente/caching, 200/304 e reconciliadores Form/Filter.
838
840
 
839
- ### Resolução da chave primária (idField)
841
+ ### Resolução da chave primária (idField)
840
842
 
841
843
  - O backend anota o schema com `x-ui.resource.idField` (e `idFieldValid`) via `/schemas/filtered`.
842
- - A tabela adota o campo identificador automaticamente com a seguinte precedência:
843
- - `@Input() idField` `crudContext.idField` `config.meta.idField` (persistido) `GenericCrudService.getResourceIdField()` (derivado do schema) `'id'`.
844
- - Se `config.meta.idField` divergir do servidor, o componente alerta o usuário e mantém o valor do TableConfig até reconciliação.
845
- - A resolução ocorre no `loadSchema()` e também é considerada em tempo de execução para evitar corridas.
846
- - Para recursos cuja PK não é `id`, defina `getIdFieldName()` no controller backend correspondente.
844
+ - A tabela adota o campo identificador automaticamente com a seguinte precedência:
845
+ - `@Input() idField` → `crudContext.idField` → `config.meta.idField` (persistido) → `GenericCrudService.getResourceIdField()` (derivado do schema) → `'id'`.
846
+ - Se `config.meta.idField` divergir do servidor, o componente alerta o usuário e mantém o valor do TableConfig até reconciliação.
847
+ - A resolução ocorre no `loadSchema()` e também é considerada em tempo de execução para evitar corridas.
848
+ - Para recursos cuja PK não é `id`, defina `getIdFieldName()` no controller backend correspondente.
847
849
 
848
850
  ### Diagramas
849
851
 
850
- Fluxo (Grid): adoção de schema e idField
852
+ Fluxo (Grid): adoção de schema e idField
851
853
 
852
854
  ```mermaid
853
855
  sequenceDiagram
@@ -867,7 +869,7 @@ sequenceDiagram
867
869
  PT->>PT: construir colunas e renderizar
868
870
  ```
869
871
 
870
- Fluxo (Delete): resolução do identificador
872
+ Fluxo (Delete): resolução do identificador
871
873
 
872
874
  ```mermaid
873
875
  sequenceDiagram
@@ -876,7 +878,7 @@ sequenceDiagram
876
878
  participant GS as GenericCrudService
877
879
  participant API as Backend
878
880
 
879
- PT->>PT: key = getIdField() (precedência)
881
+ PT->>PT: key = getIdField() (precedência)
880
882
  PT->>PT: id = getNestedPropertyValue(row, key)
881
883
  PT->>GS: delete(id)
882
884
  GS->>API: DELETE {resource}/{id}
@@ -885,17 +887,17 @@ sequenceDiagram
885
887
  PT->>PT: fetchData() em modo remoto
886
888
  ```
887
889
 
888
- ### Troubleshooting rápido (idField)
890
+ ### Troubleshooting rápido (idField)
889
891
 
890
- - A ação delete falhou por ID ausente: verifique se o schema contém `x-ui.resource.idField` e se a coluna correspondente existe no dataset.
891
- - O ID está em outra propriedade: defina `@Input() idField` ou `crudContext.idField` temporariamente; ajuste o backend com `getIdFieldName()` para persistir o comportamento.
892
- - Cache 304 sem idField aplicado: confirme que o serviço recebeu o body pelo menos uma vez (200) e que `GenericCrudService.getResourceIdField()` retorna o valor esperado.
892
+ - A ação delete falhou por ID ausente: verifique se o schema contém `x-ui.resource.idField` e se a coluna correspondente existe no dataset.
893
+ - O ID está em outra propriedade: defina `@Input() idField` ou `crudContext.idField` temporariamente; ajuste o backend com `getIdFieldName()` para persistir o comportamento.
894
+ - Cache 304 sem idField aplicado: confirme que o serviço recebeu o body pelo menos uma vez (200) e que `GenericCrudService.getResourceIdField()` retorna o valor esperado.
893
895
 
894
896
  ### Uso com Dados Locais (Client-Side)
895
897
 
896
- Se você precisar fornecer os dados manualmente (por exemplo, de uma fonte que não é uma API Praxis), pode usar o input `[data]` e omitir o `resourcePath`.
897
- Importante: o modo local está protegido por feature flag e exige `behavior.localDataMode.enabled = true` (default é `false`).
898
- Quando a flag está ativa, as operações de paginação, ordenação e filtro são executadas no lado do cliente.
898
+ Se você precisar fornecer os dados manualmente (por exemplo, de uma fonte que não é uma API Praxis), pode usar o input `[data]` e omitir o `resourcePath`.
899
+ Importante: o modo local está protegido por feature flag e exige `behavior.localDataMode.enabled = true` (default é `false`).
900
+ Quando a flag está ativa, as operações de paginação, ordenação e filtro são executadas no lado do cliente.
899
901
 
900
902
  ```typescript
901
903
  import { PraxisTable } from "@praxisui/table";
@@ -908,7 +910,7 @@ import { TableConfig } from "@praxisui/core";
908
910
  template: ` <praxis-table [config]="tableConfig" [data]="employees"> </praxis-table> `,
909
911
  })
910
912
  export class ExampleComponent {
911
- // Configuração de colunas e comportamento é obrigatória neste modo
913
+ // Configuração de colunas e comportamento é obrigatória neste modo
912
914
  tableConfig: TableConfig = {
913
915
  columns: [
914
916
  { field: "id", header: "ID", type: "number" },
@@ -919,57 +921,57 @@ export class ExampleComponent {
919
921
  pagination: { enabled: true, pageSize: 10 },
920
922
  sorting: { enabled: true },
921
923
  filtering: { enabled: true },
922
- localDataMode: { enabled: true }, // obrigatório para fluxo local oficial
924
+ localDataMode: { enabled: true }, // obrigatório para fluxo local oficial
923
925
  },
924
926
  };
925
927
 
926
928
  employees = [
927
- { id: 1, name: "João Silva", email: "joao@empresa.com" },
929
+ { id: 1, name: "João Silva", email: "joao@empresa.com" },
928
930
  { id: 2, name: "Maria Santos", email: "maria@empresa.com" },
929
931
  // ... mais dados
930
932
  ];
931
933
  }
932
934
  ```
933
935
 
934
- ## ⚙️ Fluxo de Paginação e Filtros (Server-Side)
936
+ ## ⚙️ Fluxo de Paginação e Filtros (Server-Side)
935
937
 
936
- Quando a `<praxis-table>` opera com `resourcePath`, o runtime resolve o modo remoto e passa a delegar paginação, ordenação e filtros ao backend. Isso reduz tráfego, preserva a semântica do DTO de filtro e mantém o banco como fonte de verdade para `WHERE`, `ORDER BY`, `LIMIT` e `OFFSET`.
938
+ Quando a `<praxis-table>` opera com `resourcePath`, o runtime resolve o modo remoto e passa a delegar paginação, ordenação e filtros ao backend. Isso reduz tráfego, preserva a semântica do DTO de filtro e mantém o banco como fonte de verdade para `WHERE`, `ORDER BY`, `LIMIT` e `OFFSET`.
937
939
 
938
- Importante: se você não configurar explicitamente as estratégias de paginação/ordenação no `TableConfig`, a tabela resolve automaticamente como `server` quando `resourcePath`. Se preferir operar no cliente, defina `behavior.pagination.strategy = 'client'` e/ou `behavior.sorting.strategy = 'client'` conscientemente.
940
+ Importante: se você não configurar explicitamente as estratégias de paginação/ordenação no `TableConfig`, a tabela resolve automaticamente como `server` quando há `resourcePath`. Se preferir operar no cliente, defina `behavior.pagination.strategy = 'client'` e/ou `behavior.sorting.strategy = 'client'` conscientemente.
939
941
 
940
- ### Versão Pedagógica de Alto Nível
942
+ ### Versão Pedagógica de Alto Nível
941
943
 
942
- Esta é a leitura adequada para documentação pública e landing pages.
944
+ Esta é a leitura adequada para documentação pública e landing pages.
943
945
 
944
946
  ```mermaid
945
947
  sequenceDiagram
946
- participant Usuario as Usuário
948
+ participant Usuario as Usuário
947
949
  participant Tabela as praxis-table
948
950
  participant Frontend as GenericCrudService
949
951
  participant Backend as API Praxis
950
952
  participant Banco as Banco de Dados
951
953
 
952
- Usuario->>Tabela: muda página, ordena ou aplica filtro
953
- Tabela->>Tabela: consolida filterCriteria + paginação + sort
954
+ Usuario->>Tabela: muda página, ordena ou aplica filtro
955
+ Tabela->>Tabela: consolida filterCriteria + paginação + sort
954
956
  Tabela->>Frontend: filter(criteria, pageable)
955
957
  Frontend->>Backend: POST /api/.../filter?page&size&sort
956
958
  Backend->>Banco: executa consulta filtrada e paginada
957
- Banco-->>Backend: retorna página de resultados
958
- Backend-->>Frontend: responde com página de DTOs
959
+ Banco-->>Backend: retorna página de resultados
960
+ Backend-->>Frontend: responde com página de DTOs
959
961
  Frontend-->>Tabela: entrega Page<T>
960
- Tabela->>Tabela: atualiza linhas, paginação e estado visual
962
+ Tabela->>Tabela: atualiza linhas, paginação e estado visual
961
963
  ```
962
964
 
963
- Leitura pedagógica:
965
+ Leitura pedagógica:
964
966
 
965
- 1. **A tabela captura a intenção do usuário**: página, ordenação e filtros viram estado de consulta.
966
- 2. **O frontend envia o DTO de filtro para o endpoint canônico**: corpo JSON para filtro, query params para paginação e sort.
967
- 3. **O backend aplica o filtro no conjunto remoto**: não é a UI que filtra localmente em modo remoto.
968
- 4. **O resultado volta paginado**: a tabela apenas renderiza a página retornada pela API.
967
+ 1. **A tabela captura a intenção do usuário**: página, ordenação e filtros viram estado de consulta.
968
+ 2. **O frontend envia o DTO de filtro para o endpoint canônico**: corpo JSON para filtro, query params para paginação e sort.
969
+ 3. **O backend aplica o filtro no conjunto remoto**: não é a UI que filtra localmente em modo remoto.
970
+ 4. **O resultado volta já paginado**: a tabela apenas renderiza a página retornada pela API.
969
971
 
970
- ### Versão Detalhada e Fiel ao Runtime Atual
972
+ ### Versão Detalhada e Fiel ao Runtime Atual
971
973
 
972
- Esta versão documenta o fluxo real do `praxis-table`, do `praxis-filter`, do `GenericCrudService` e do `praxis-metadata-starter`.
974
+ Esta versão documenta o fluxo real do `praxis-table`, do `praxis-filter`, do `GenericCrudService` e do `praxis-metadata-starter`.
973
975
 
974
976
  ```mermaid
975
977
  sequenceDiagram
@@ -997,12 +999,12 @@ sequenceDiagram
997
999
  Crud-->>Filtro: metadata de filtro
998
1000
  end
999
1001
 
1000
- alt paginação
1002
+ alt paginação
1001
1003
  Tabela->>Tabela: onPageChange(pageIndex, pageSize)
1002
- else ordenação
1004
+ else ordenação
1003
1005
  Tabela->>Tabela: onSortChange(active, direction)
1004
1006
  Tabela->>Tabela: reseta pageIndex = 0
1005
- else filtro avançado
1007
+ else filtro avançado
1006
1008
  Filtro-->>Tabela: submit/change/clear
1007
1009
  Tabela->>Tabela: onAdvancedFilterSubmit(criteria)
1008
1010
  end
@@ -1015,7 +1017,7 @@ sequenceDiagram
1015
1017
  Crud->>Controller: POST /filter?page&size&sort
1016
1018
  Note over Crud,Controller: body = filterCriteria JSON
1017
1019
 
1018
- Controller->>Controller: page,size,sort de query params
1020
+ Controller->>Controller: lê page,size,sort de query params
1019
1021
  Controller->>Controller: PageableBuilder.from(page,size,sort,...)
1020
1022
  Controller->>Service: filterMappedWithIncludeIds(filterDTO, pageable, includeIds, toDto)
1021
1023
 
@@ -1035,56 +1037,56 @@ sequenceDiagram
1035
1037
 
1036
1038
  ### Pontos-Chave do Fluxo Real
1037
1039
 
1038
- 1. **`resourcePath` não dispara fetch**: em modo remoto, a tabela primeiro configura o `GenericCrudService` e pode carregar schema antes da primeira busca.
1039
- 2. **O filtro avançado vive em `praxis-filter`**: os eventos reais são `submit`, `change` e `clear`, que a tabela recebe como `onAdvancedFilterSubmit`, `onAdvancedFilterChange` e `onAdvancedFilterClear`.
1040
- 3. **O controller não recebe `Pageable` pronto do Spring nesse endpoint**: ele reconstrói o `Pageable` a partir de `page`, `size` e `sort`.
1040
+ 1. **`resourcePath` não dispara só fetch**: em modo remoto, a tabela primeiro configura o `GenericCrudService` e pode carregar schema antes da primeira busca.
1041
+ 2. **O filtro avançado vive em `praxis-filter`**: os eventos reais são `submit`, `change` e `clear`, que a tabela recebe como `onAdvancedFilterSubmit`, `onAdvancedFilterChange` e `onAdvancedFilterClear`.
1042
+ 3. **O controller não recebe `Pageable` pronto do Spring nesse endpoint**: ele reconstrói o `Pageable` a partir de `page`, `size` e `sort`.
1041
1043
  4. **O backend do starter responde com `RestApiResponse<Page<...>>`**: o `GenericCrudService` faz `unwrapPageResponse(...)` para entregar `Page<T>` ao runtime da tabela.
1042
- 5. **A coluna ordenada pode mapear para `sortField`**: o `active` da UI não é necessariamente o campo final enviado ao backend.
1044
+ 5. **A coluna ordenada pode mapear para `sortField`**: o `active` da UI não é necessariamente o campo final enviado ao backend.
1043
1045
 
1044
- ## 🎨 Edição Visual da Tabela: O Poder do Low-Code
1046
+ ## 🎨 Edição Visual da Tabela: O Poder do Low-Code
1045
1047
 
1046
- A `<praxis-table>` vem com um poderoso editor de configuração visual que permite personalizar quase todos os aspectos da sua tabela em tempo real, sem escrever uma única linha de código. O runtime expõe esse editor somente quando o host ativa `[enableCustomization]="true"`.
1048
+ A `<praxis-table>` vem com um poderoso editor de configuração visual que permite personalizar quase todos os aspectos da sua tabela em tempo real, sem escrever uma única linha de código. O runtime expõe esse editor somente quando o host ativa `[enableCustomization]="true"`.
1047
1049
 
1048
- A seguir, veja os principais recursos que você pode configurar visualmente:
1050
+ A seguir, veja os principais recursos que você pode configurar visualmente:
1049
1051
 
1050
1052
  ### 1. Gerenciamento de Colunas
1051
1053
 
1052
- Controle total sobre as colunas da sua tabela. Dentro do editor, você pode:
1054
+ Controle total sobre as colunas da sua tabela. Dentro do editor, você pode:
1053
1055
 
1054
- - **Reordenar com Arrastar e Soltar:** Simplesmente clique e arraste uma coluna para a posição desejada.
1055
- - **Alterar Visibilidade:** Use a caixa de seleção ao lado de cada coluna para mostrá-la ou ocultá-la instantaneamente.
1056
- - **Editar Títulos e Largura:** Clique em uma coluna para abrir suas propriedades e altere o texto do cabeçalho, defina uma largura fixa (ex: `150px`) ou deixe-a automática.
1056
+ - **Reordenar com Arrastar e Soltar:** Simplesmente clique e arraste uma coluna para a posição desejada.
1057
+ - **Alterar Visibilidade:** Use a caixa de seleção ao lado de cada coluna para mostrá-la ou ocultá-la instantaneamente.
1058
+ - **Editar Títulos e Largura:** Clique em uma coluna para abrir suas propriedades e altere o texto do cabeçalho, defina uma largura fixa (ex: `150px`) ou deixe-a automática.
1057
1059
 
1058
- ### 2. Transformação de Dados Sem Código
1060
+ ### 2. Transformação de Dados Sem Código
1059
1061
 
1060
- Converta dados brutos em informações claras e formatadas para o usuário.
1062
+ Converta dados brutos em informações claras e formatadas para o usuário.
1061
1063
 
1062
- - **Formatação Automática:** Selecione uma coluna e escolha seu "Tipo de Dado". Se escolher `Moeda`, os valores serão formatados como `R$ 1.234,56`. Se escolher `Data`, você pode selecionar formatos como `dd/MM/yyyy` ou `25 de janeiro de 2025`.
1063
- - **Mapeamento de Valores:** Transforme códigos e valores brutos em texto legível. Na seção "Mapeamento de Valores", você pode definir visualmente que o valor `true` deve ser exibido como "Ativo" e `false` como "Inativo", ou que o código `1` significa "Pendente" e `2` significa "Aprovado".
1064
+ - **Formatação Automática:** Selecione uma coluna e escolha seu "Tipo de Dado". Se escolher `Moeda`, os valores serão formatados como `R$ 1.234,56`. Se escolher `Data`, você pode selecionar formatos como `dd/MM/yyyy` ou `25 de janeiro de 2025`.
1065
+ - **Mapeamento de Valores:** Transforme códigos e valores brutos em texto legível. Na seção "Mapeamento de Valores", você pode definir visualmente que o valor `true` deve ser exibido como "Ativo" e `false` como "Inativo", ou que o código `1` significa "Pendente" e `2` significa "Aprovado".
1064
1066
 
1065
- ### 3. Colunas Calculadas com Fórmulas Visuais
1067
+ ### 3. Colunas Calculadas com Fórmulas Visuais
1066
1068
 
1067
1069
  Crie novas colunas dinamicamente a partir de dados existentes, sem precisar programar.
1068
1070
 
1069
- - **Concatenar Texto:** Crie uma "Coluna Calculada", escolha a fórmula "Concatenar" e selecione os campos `nome` e `sobrenome` para criar uma coluna "Nome Completo".
1070
- - **Realizar Operações Matemáticas:** Use a fórmula "Operação Matemática" para criar uma coluna que calcula `preço * quantidade`.
1071
- - **Criar Valores Condicionais (IF/ELSE):** Com a fórmula "Condicional", você pode criar uma coluna "Nível de Risco" que exibe "Alto" se o `valor` for maior que 1000, e "Baixo" caso contrário.
1071
+ - **Concatenar Texto:** Crie uma "Coluna Calculada", escolha a fórmula "Concatenar" e selecione os campos `nome` e `sobrenome` para criar uma coluna "Nome Completo".
1072
+ - **Realizar Operações Matemáticas:** Use a fórmula "Operação Matemática" para criar uma coluna que calcula `preço * quantidade`.
1073
+ - **Criar Valores Condicionais (IF/ELSE):** Com a fórmula "Condicional", você pode criar uma coluna "Nível de Risco" que exibe "Alto" se o `valor` for maior que 1000, e "Baixo" caso contrário.
1072
1074
 
1073
- ### 4. Formatação Condicional (Regras de Estilo)
1075
+ ### 4. Formatação Condicional (Regras de Estilo)
1074
1076
 
1075
- Destaque informações importantes aplicando estilos que mudam com base nos dados da linha.
1077
+ Destaque informações importantes aplicando estilos que mudam com base nos dados da linha.
1076
1078
 
1077
- - **Crie Regras Visuais:** Na seção de "Formatação Condicional", crie uma nova regra.
1078
- - **Defina a Condição:** Estabeleça a condição, por exemplo: "Quando a coluna `status` tiver o valor igual a 'Urgente'".
1079
- - **Aplique o Estilo:** Use seletores de cor para definir que, quando a condição for verdadeira, a cor de fundo da célula ou da linha inteira deve se tornar vermelha e o texto, branco.
1079
+ - **Crie Regras Visuais:** Na seção de "Formatação Condicional", crie uma nova regra.
1080
+ - **Defina a Condição:** Estabeleça a condição, por exemplo: "Quando a coluna `status` tiver o valor igual a 'Urgente'".
1081
+ - **Aplique o Estilo:** Use seletores de cor para definir que, quando a condição for verdadeira, a cor de fundo da célula ou da linha inteira deve se tornar vermelha e o texto, branco.
1080
1082
 
1081
1083
  ### 5. Comportamentos da Tabela
1082
1084
 
1083
- Habilite e configure as funcionalidades centrais da tabela com um clique. Na aba "Comportamento", você pode:
1085
+ Habilite e configure as funcionalidades centrais da tabela com um clique. Na aba "Comportamento", você pode:
1084
1086
 
1085
- - **Ativar/Desativar Paginação:** Com um único interruptor, ative a paginação para tabelas com muitos dados e defina quantos itens exibir por página.
1086
- - **Controlar Ordenação e Filtros:** Habilite a capacidade dos usuários de ordenar colunas e filtrar os dados com simples caixas de seleção.
1087
- - **Gerenciar Seleção de Linhas:** Permita que os usuários selecionem uma ou várias linhas para realizar ações em lote.
1087
+ - **Ativar/Desativar Paginação:** Com um único interruptor, ative a paginação para tabelas com muitos dados e defina quantos itens exibir por página.
1088
+ - **Controlar Ordenação e Filtros:** Habilite a capacidade dos usuários de ordenar colunas e filtrar os dados com simples caixas de seleção.
1089
+ - **Gerenciar Seleção de Linhas:** Permita que os usuários selecionem uma ou várias linhas para realizar ações em lote.
1088
1090
 
1089
1091
  ### Editores Especializados
1090
1092
 
@@ -1093,7 +1095,7 @@ Habilite e configure as funcionalidades centrais da tabela com um clique. Na aba
1093
1095
  ```typescript
1094
1096
  import { BehaviorConfigEditorComponent } from '@praxisui/table';
1095
1097
 
1096
- // Usar como componente standalone para edição específica
1098
+ // Usar como componente standalone para edição específica
1097
1099
  <behavior-config-editor
1098
1100
  [config]="tableConfig"
1099
1101
  (configChange)="onBehaviorChange($event)">
@@ -1112,9 +1114,9 @@ import { ColumnsConfigEditorComponent } from '@praxisui/table';
1112
1114
  </columns-config-editor>
1113
1115
  ```
1114
1116
 
1115
- ## 🔧 Configuração Avançada
1117
+ ## 🔧 Configuração Avançada
1116
1118
 
1117
- ### Performance com Virtualização
1119
+ ### Performance com Virtualização
1118
1120
 
1119
1121
  ```typescript
1120
1122
  const highVolumeConfig: TableConfig = {
@@ -1162,7 +1164,7 @@ const accessibleConfig: TableConfig = {
1162
1164
  };
1163
1165
  ```
1164
1166
 
1165
- ### Aparência Customizada
1167
+ ### Aparência Customizada
1166
1168
 
1167
1169
  ```typescript
1168
1170
  const styledConfig: TableConfig = {
@@ -1195,7 +1197,7 @@ const styledConfig: TableConfig = {
1195
1197
  };
1196
1198
  ```
1197
1199
 
1198
- ## 🎯 Event Handling
1200
+ ## 🎯 Event Handling
1199
1201
 
1200
1202
  ### Eventos da Tabela
1201
1203
 
@@ -1213,7 +1215,7 @@ const styledConfig: TableConfig = {
1213
1215
  </praxis-table>
1214
1216
  ```
1215
1217
 
1216
- ### Implementação dos Handlers
1218
+ ### Implementação dos Handlers
1217
1219
 
1218
1220
  ```typescript
1219
1221
  export class MyComponent {
@@ -1240,25 +1242,25 @@ export class MyComponent {
1240
1242
  }
1241
1243
  ```
1242
1244
 
1243
- ## 🛠️ Utilitários e Helpers
1245
+ ## 🛠️ Utilitários e Helpers
1244
1246
 
1245
1247
  ### Helper Functions
1246
1248
 
1247
1249
  ```typescript
1248
1250
  import { createDefaultTableConfig, isValidTableConfig, cloneTableConfig, mergeTableConfigs } from "@praxisui/core";
1249
1251
 
1250
- // Criar configuração padrão
1252
+ // Criar configuração padrão
1251
1253
  const defaultConfig = createDefaultTableConfig();
1252
1254
 
1253
- // Validar configuração
1255
+ // Validar configuração
1254
1256
  if (isValidTableConfig(myConfig)) {
1255
- // Configuração válida
1257
+ // Configuração válida
1256
1258
  }
1257
1259
 
1258
- // Clonar configuração
1260
+ // Clonar configuração
1259
1261
  const clonedConfig = cloneTableConfig(originalConfig);
1260
1262
 
1261
- // Merge configurações
1263
+ // Merge configurações
1262
1264
  const mergedConfig = mergeTableConfigs(baseConfig, overrides);
1263
1265
  ```
1264
1266
 
@@ -1272,10 +1274,10 @@ export class MyComponent {
1272
1274
  constructor(private configService: TableConfigService) {}
1273
1275
 
1274
1276
  ngOnInit() {
1275
- // Usar serviço para gerenciar configuração
1277
+ // Usar serviço para gerenciar configuração
1276
1278
  this.configService.setConfig(this.tableConfig);
1277
1279
 
1278
- // Verificar recursos disponíveis
1280
+ // Verificar recursos disponíveis
1279
1281
  // No runtime atual, multiSort permanece schema-only.
1280
1282
  const hasMultiSort = false;
1281
1283
  const hasBulkActions = this.configService.isFeatureEnabled('bulkActions');
@@ -1283,7 +1285,7 @@ export class MyComponent {
1283
1285
  }
1284
1286
  ```
1285
1287
 
1286
- ## 🧪 Testes
1288
+ ## 🧪 Testes
1287
1289
 
1288
1290
  ### Unit Tests
1289
1291
 
@@ -1322,11 +1324,11 @@ describe("PraxisTable", () => {
1322
1324
  });
1323
1325
  ```
1324
1326
 
1325
- ## 📋 Migration Guide
1327
+ ## 📋 Migration Guide
1326
1328
 
1327
- ### Migração da Arquitetura V1/V2
1329
+ ### Migração da Arquitetura V1/V2
1328
1330
 
1329
- Se você estava usando as versões anteriores com dual architecture, aqui estão as principais mudanças:
1331
+ Se você estava usando as versões anteriores com dual architecture, aqui estão as principais mudanças:
1330
1332
 
1331
1333
  #### Imports Atualizados
1332
1334
 
@@ -1338,14 +1340,14 @@ import { TableConfigV1, TableConfigV2, TableConfigUnified } from "@praxisui/core
1338
1340
  import { TableConfig } from "@praxisui/core";
1339
1341
  ```
1340
1342
 
1341
- #### Serviços Removidos
1343
+ #### Serviços Removidos
1342
1344
 
1343
1345
  ```typescript
1344
1346
  // Antes
1345
1347
  import { TableConfigAdapterService } from "@praxisui/table";
1346
1348
 
1347
- // Depois - Não mais necessário
1348
- // Uso direto da configuração
1349
+ // Depois - Não mais necessário
1350
+ // Uso direto da configuração
1349
1351
  ```
1350
1352
 
1351
1353
  #### Tipos Simplificados
@@ -1360,29 +1362,29 @@ config: TableConfig;
1360
1362
 
1361
1363
  ### Breaking Changes
1362
1364
 
1363
- 1. **TableConfigAdapterService**: Removido - uso direto da configuração
1365
+ 1. **TableConfigAdapterService**: Removido - uso direto da configuração
1364
1366
  2. **TableConfigMigrationService**: Simplificado - funcionalidade integrada
1365
1367
  3. **TableConfigUnified**: Renomeado para `TableConfig`
1366
1368
 
1367
- ## 🔍 Troubleshooting
1369
+ ## 🔍 Troubleshooting
1368
1370
 
1369
1371
  ### Problemas Comuns
1370
1372
 
1371
- #### Configuração não está funcionando
1373
+ #### Configuração não está funcionando
1372
1374
 
1373
1375
  ```typescript
1374
- // Verificar se a configuração é válida
1376
+ // Verificar se a configuração é válida
1375
1377
  import { isValidTableConfig } from "@praxisui/core";
1376
1378
 
1377
1379
  if (!isValidTableConfig(myConfig)) {
1378
- console.error("Configuração inválida:", myConfig);
1380
+ console.error("Configuração inválida:", myConfig);
1379
1381
  }
1380
1382
  ```
1381
1383
 
1382
1384
  #### Performance Issues
1383
1385
 
1384
1386
  ```typescript
1385
- // Habilitar virtualização para grandes datasets
1387
+ // Habilitar virtualização para grandes datasets
1386
1388
  const config: TableConfig = {
1387
1389
  // ...
1388
1390
  performance: {
@@ -1398,7 +1400,7 @@ const config: TableConfig = {
1398
1400
  #### Acessibilidade
1399
1401
 
1400
1402
  ```typescript
1401
- // Garantir que acessibilidade está habilitada
1403
+ // Garantir que acessibilidade está habilitada
1402
1404
  const config: TableConfig = {
1403
1405
  // ...
1404
1406
  accessibility: {
@@ -1408,35 +1410,35 @@ const config: TableConfig = {
1408
1410
  };
1409
1411
  ```
1410
1412
 
1411
- ## 📚 API Reference
1413
+ ## 📚 API Reference
1412
1414
 
1413
1415
  ### Interfaces Principais
1414
1416
 
1415
1417
  #### TableConfig
1416
1418
 
1417
- Interface principal para configuração da tabela.
1419
+ Interface principal para configuração da tabela.
1418
1420
 
1419
1421
  #### ColumnDefinition
1420
1422
 
1421
- Define configuração individual de colunas.
1423
+ Define configuração individual de colunas.
1422
1424
 
1423
1425
  #### TableBehaviorConfig
1424
1426
 
1425
- Configurações de comportamento (paginação, ordenação, etc.).
1427
+ Configurações de comportamento (paginação, ordenação, etc.).
1426
1428
 
1427
1429
  #### TableAppearanceConfig
1428
1430
 
1429
- Configurações de aparência visual.
1431
+ Configurações de aparência visual.
1430
1432
 
1431
- Para documentação completa da API, consulte `projects/praxis-core/README.md`.
1433
+ Para documentação completa da API, consulte `projects/praxis-core/README.md`.
1432
1434
 
1433
- ## 🤝 Contribuição
1435
+ ## 🤝 Contribuição
1434
1436
 
1435
1437
  ### Como Contribuir
1436
1438
 
1437
1439
  1. Fork o projeto
1438
1440
  2. Crie branch para feature (`git checkout -b feature/nova-funcionalidade`)
1439
- 3. Commit mudanças (`git commit -m 'Add: nova funcionalidade'`)
1441
+ 3. Commit mudanças (`git commit -m 'Add: nova funcionalidade'`)
1440
1442
  4. Push para branch (`git push origin feature/nova-funcionalidade`)
1441
1443
  5. Abra Pull Request
1442
1444
 
@@ -1444,12 +1446,12 @@ Para documentação completa da API, consulte `projects/praxis-core/README.md`.
1444
1446
 
1445
1447
  - Seguir Angular Style Guide
1446
1448
  - Adicionar testes para novas features
1447
- - Manter documentação atualizada
1449
+ - Manter documentação atualizada
1448
1450
  - Usar TypeScript strict mode
1449
1451
 
1450
- ## 🔍 Exemplo de Integração com PraxisFilter
1452
+ ## 🔍 Exemplo de Integração com PraxisFilter
1451
1453
 
1452
- O `PraxisFilter` pode ser acoplado à barra de ferramentas da tabela. O exemplo abaixo mostra a busca de pessoas por CPF e status.
1454
+ O `PraxisFilter` pode ser acoplado à barra de ferramentas da tabela. O exemplo abaixo mostra a busca de pessoas por CPF e status.
1453
1455
 
1454
1456
  ```html
1455
1457
  <praxis-filter [resourcePath]="'pessoas'" [formId]="'pessoas-filter'" [persistenceKey]="'pessoas-filter-v1'" [alwaysVisibleFields]="['status']" (requestSearch)="onFilter($event)"></praxis-filter> <praxis-table [data]="tableData"></praxis-table>
@@ -1464,16 +1466,16 @@ onFilter(dto: any) {
1464
1466
  }
1465
1467
  ```
1466
1468
 
1467
- ### ⚙️ Configuração do Filtro
1469
+ ### ⚙️ Configuração do Filtro
1468
1470
 
1469
- O `PraxisFilter` pode ser configurado por inputs/JSON de configuração. O atalho
1470
- visual por ícone de engrenagem não é exposto por padrão na tabela/demo.
1471
- Quando necessário, também é possível abrir o painel programaticamente via
1472
- `openSettings()`. Nesse painel é possível ajustar:
1471
+ O `PraxisFilter` pode ser configurado por inputs/JSON de configuração. O atalho
1472
+ visual por ícone de engrenagem não é exposto por padrão na tabela/demo.
1473
+ Quando necessário, também é possível abrir o painel programaticamente via
1474
+ `openSettings()`. Nesse painel é possível ajustar:
1473
1475
 
1474
- - **alwaysVisibleFields** campos que permanecem sempre visíveis
1475
- - **alwaysVisibleFieldMetadataOverrides** patch de metadata por campo sempre visível (controle, clearButton, inlineAutoSize etc.)
1476
- - **showAdvanced** define se a seção avançada inicia aberta
1476
+ - **alwaysVisibleFields** – campos que permanecem sempre visíveis
1477
+ - **alwaysVisibleFieldMetadataOverrides** – patch de metadata por campo sempre visível (controle, clearButton, inlineAutoSize etc.)
1478
+ - **showAdvanced** – define se a seção avançada inicia aberta
1477
1479
 
1478
1480
  ```ts
1479
1481
  @ViewChild(PraxisFilter) filter!: PraxisFilter;
@@ -1483,100 +1485,100 @@ abrirConfiguracoes() {
1483
1485
  }
1484
1486
  ```
1485
1487
 
1486
- Ao aplicar ou salvar, as escolhas são validadas contra os metadados
1488
+ Ao aplicar ou salvar, as escolhas são validadas contra os metadados
1487
1489
  do **DTO de filtro** (schema de `POST /{resource}/filter`). Campos ausentes
1488
- no DTO não são aplicados em `alwaysVisibleFields`.
1489
- O componente exibe uma barra de progresso durante o processo de persistência e
1490
- mensagens de sucesso ou erro via _snack bar_, garantindo uma experiência
1490
+ no DTO não são aplicados em `alwaysVisibleFields`.
1491
+ O componente exibe uma barra de progresso durante o processo de persistência e
1492
+ mensagens de sucesso ou erro via _snack bar_, garantindo uma experiência
1491
1493
  consistente.
1492
1494
 
1493
- ### 🔖 Miniguia: Atalhos do Filtro (tags)
1495
+ ### 🔖 Mini‑guia: Atalhos do Filtro (tags)
1494
1496
 
1495
- Atalhos são chips que guardam um conjunto de filtros (DTO) para reuso rápido.
1497
+ Atalhos são “chips” que guardam um conjunto de filtros (DTO) para reuso rápido.
1496
1498
 
1497
1499
  - Criar/Salvar
1498
- - Modal (padrão): o host do diálogo exibe o botão quando `allowSaveTags === true`.
1499
- - Gaveta (Drawer): o Adapter recebe `allowSaveTags?`, `i18nSaveAsShortcut?` e `onSaveShortcut?` (opcionais). O host deve exibir o botão e chamar `onSaveShortcut(clean({ ...initialDto, ...lastValue }))`.
1500
- - O DTO é limpo antes de persistir (remove `'' | null | undefined`).
1500
+ - Modal (padrão): o host do diálogo exibe o botão quando `allowSaveTags === true`.
1501
+ - Gaveta (Drawer): o Adapter recebe `allowSaveTags?`, `i18nSaveAsShortcut?` e `onSaveShortcut?` (opcionais). O host deve exibir o botão e chamar `onSaveShortcut(clean({ ...initialDto, ...lastValue }))`.
1502
+ - O DTO é limpo antes de persistir (remove `'' | null | undefined`).
1501
1503
  - Aplicar
1502
1504
  - Clique/Enter no chip aplica imediatamente `tag.patch` (substitui o estado atual), emite `submit` e persiste.
1503
- - O chip ativo é destacado (cor/borda + ícone de check) quando o DTO atual é igual ao patch do atalho.
1505
+ - O chip ativo é destacado (cor/borda + ícone de “check”) quando o DTO atual é igual ao patch do atalho.
1504
1506
  - Editar/Renomear
1505
- - Apenas atalhos do usuário exibem ícone de lápis. Predefinidos mostram ícone de cadeado (somente leitura).
1507
+ - Apenas atalhos do usuário exibem ícone de lápis. Predefinidos mostram ícone de “cadeado” (somente leitura).
1506
1508
  - Excluir (com Undo)
1507
- - Exclusão remove imediatamente o atalho do usuário e exibe snackbar Atalho removido com ação Desfazer quando `confirmTagDelete === true`.
1508
- - Ao clicar em Desfazer”, o atalho é restaurado na mesma posição e os eventos são reemitidos.
1509
+ - Exclusão remove imediatamente o atalho do usuário e exibe snackbar “Atalho removido” com ação “Desfazer” quando `confirmTagDelete === true`.
1510
+ - Ao clicar em “Desfazer”, o atalho é restaurado na mesma posição e os eventos são reemitidos.
1509
1511
  - i18n
1510
- - Chaves úteis: `saveAsShortcut`, `renameShortcut`, `removeShortcut`, `shortcutSaved`, `shortcutRemoved`, `undo`, `readonlyShortcut`.
1512
+ - Chaves úteis: `saveAsShortcut`, `renameShortcut`, `removeShortcut`, `shortcutSaved`, `shortcutRemoved`, `undo`, `readonlyShortcut`.
1511
1513
 
1512
- Veja também: `docs/host-crud-integration.md` (guia operacional host) e `projects/praxis-crud/docs/host-crud-runtime-and-openmode.md` (contrato técnico canônico) para detalhes do contrato do Adapter.
1514
+ Veja também: `docs/host-crud-integration.md` (guia operacional host) e `projects/praxis-crud/docs/host-crud-runtime-and-openmode.md` (contrato técnico canônico) para detalhes do contrato do Adapter.
1513
1515
 
1514
1516
  ### Novos Inputs/Outputs (PraxisFilter)
1515
1517
 
1516
1518
  - Inputs (efetivos apenas quando `enableCustomization = true`):
1517
- - `enableCustomization: boolean` habilita o gate de customização para notificações de schema.
1518
- - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'` seleciona como o runtime publica avisos de drift quando a política operacional estiver habilitada.
1519
- - `snoozeMs: number = 86400000` tempo de soneca para avisos (ms).
1520
- - `autoOpenSettingsOnOutdated: boolean = false` abre Configurações ao detectar schema desatualizado.
1519
+ - `enableCustomization: boolean` — habilita o gate de customização para notificações de schema.
1520
+ - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'` — seleciona como o runtime publica avisos de drift quando a política operacional estiver habilitada.
1521
+ - `snoozeMs: number = 86400000` — tempo de soneca para avisos (ms).
1522
+ - `autoOpenSettingsOnOutdated: boolean = false` — abre Configurações ao detectar schema desatualizado.
1521
1523
  - Output:
1522
- - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; tableId?: string }` emitido após verificação leve (304/200).
1524
+ - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; tableId?: string }` — emitido após verificação leve (304/200).
1523
1525
 
1524
1526
  #### Fallback Global (opcional)
1525
1527
 
1526
- - Quando os inputs do componente permanecem com os valores padrão e não overrides locais, o Filter utiliza como último fallback as preferências globais via `GlobalConfigService.getSchemaPrefsGlobal()`.
1527
- - Cadeia de precedência (inalterada): `@Inputs (widget)` Prefs do widget Prefs da página Prefs globais Defaults.
1528
- - O fallback global não é persistido no componente; serve apenas para defaults em memória.
1528
+ - Quando os inputs do componente permanecem com os valores padrão e não há overrides locais, o Filter utiliza como último fallback as preferências globais via `GlobalConfigService.getSchemaPrefsGlobal()`.
1529
+ - Cadeia de precedência (inalterada): `@Inputs (widget)` → Prefs do widget → Prefs da página → Prefs globais → Defaults.
1530
+ - O fallback global não é persistido no componente; serve apenas para defaults em memória.
1529
1531
 
1530
- Notas rápidas (Flow ETag no Filter):
1531
- - Verificação leve sempre no init (sem baixar o corpo): usa ETag/If-None-Match em `/schemas/filtered` (path=`.../filter`, operation=`post`, schemaType=`request`, `includeInternalSchemas=true`).
1532
+ Notas rápidas (Flow ETag no Filter):
1533
+ - Verificação leve sempre no init (sem baixar o corpo): usa ETag/If-None-Match em `/schemas/filtered` (path=`.../filter`, operation=`post`, schemaType=`request`, `includeInternalSchemas=true`).
1532
1534
  - 304: atualiza `lastVerifiedAt`; emite `schemaStatusChange(outdated=false)`.
1533
- - 200: atualiza `serverHash/lastVerifiedAt`; marca `outdated=true` apenas quando em customização; não aplica o schema automaticamente.
1534
- - O corpo do schema é baixado apenas quando necessário para renderização (ex.: `alwaysVisibleFields` ou ao abrir o painel Avançado).
1535
+ - 200: atualiza `serverHash/lastVerifiedAt`; marca `outdated=true` apenas quando em customização; não aplica o schema automaticamente.
1536
+ - O corpo do schema é baixado apenas quando necessário para renderização (ex.: `alwaysVisibleFields` ou ao abrir o painel Avançado).
1535
1537
 
1536
- ## Formatação de Colunas (format)
1538
+ ## Formatação de Colunas (format)
1537
1539
 
1538
- Cada coluna pode declarar `type` e uma string de formatação `format` consumida pelo `DataFormattingService`. Os tipos suportados são: `string`, `number`, `currency`, `percentage`, `date`, `datetime`, `time`, `boolean`, `custom`.
1540
+ Cada coluna pode declarar `type` e uma string de formatação `format` consumida pelo `DataFormattingService`. Os tipos suportados são: `string`, `number`, `currency`, `percentage`, `date`, `datetime`, `time`, `boolean`, `custom`.
1539
1541
 
1540
1542
  Regra geral:
1541
- - `format` explícito continua com precedência máxima.
1542
- - Para `number`, `currency`, `percentage`, `date`, `datetime` e `time`, a tabela também consegue derivar formatação básica a partir de `type + config.localization`, mesmo quando `format` estiver ausente.
1543
- - `string`, `boolean` e `custom` continuam conservadores; nesses casos, use `format` explícito quando precisar de transformação.
1543
+ - `format` explícito continua com precedência máxima.
1544
+ - Para `number`, `currency`, `percentage`, `date`, `datetime` e `time`, a tabela também consegue derivar formatação básica a partir de `type + config.localization`, mesmo quando `format` estiver ausente.
1545
+ - `string`, `boolean` e `custom` continuam conservadores; nesses casos, use `format` explícito quando precisar de transformação.
1544
1546
 
1545
1547
  Nota de plataforma:
1546
- - o contrato público da tabela continua sendo `column.type + config.localization + format`.
1547
- - a tabela converge internamente para a semântica canônica horizontal do core, mas não expõe `valuePresentation` como bloco público de configuração de coluna.
1548
+ - o contrato público da tabela continua sendo `column.type + config.localization + format`.
1549
+ - a tabela converge internamente para a semântica canônica horizontal do core, mas não expõe `valuePresentation` como bloco público de configuração de coluna.
1548
1550
 
1549
- Tipos e padrões de `format`:
1551
+ Tipos e padrões de `format`:
1550
1552
  - number (DecimalPipe)
1551
- - Padrões: `minInt.minFrac-maxFrac`
1553
+ - Padrões: `minInt.minFrac-maxFrac`
1552
1554
  - Exemplos: `1.0-0`, `1.2-2`, `1.0-3|nosep` (remove separador de milhar)
1553
1555
  - currency (CurrencyPipe)
1554
1556
  - Sintaxe: `CURRENCY|DISPLAY|DECIMALS[|nosep]`
1555
1557
  - Exemplos: `BRL|symbol|2`, `USD|code|0`, `EUR|symbol|2|nosep`
1556
1558
  - percentage (PercentPipe/DecimalPipe)
1557
1559
  - Sem multiplicador: `1.0-0` (PercentPipe)
1558
- - Multiplicar por 100: `1.1-1|x100` (DecimalPipe×100 + `%`)
1560
+ - Multiplicar por 100: `1.1-1|x100` (DecimalPipe×100 + `%`)
1559
1561
  - date (DatePipe)
1560
1562
  - Tokens Angular: `shortDate`, `mediumDate`, `longDate`, `fullDate`, `short`, `shortTime`
1561
- - Padrões customizados: `dd/MM/yyyy`, `yyyy-MM-dd`, `dd/MM/yyyy HH:mm`
1562
- - string (transformações + truncamento)
1563
+ - Padrões customizados: `dd/MM/yyyy`, `yyyy-MM-dd`, `dd/MM/yyyy HH:mm`
1564
+ - string (transformações + truncamento)
1563
1565
  - Transform: `uppercase` | `lowercase` | `titlecase` | `capitalize` | `none`
1564
1566
  - Transform + truncar: `<transform>|truncate|<max>|<suffix>`
1565
1567
  - Exemplos: `uppercase|truncate|50|...`, `titlecase`
1566
- - boolean (pré-definidos ou custom)
1568
+ - boolean (pré-definidos ou custom)
1567
1569
  - Presets: `true-false` | `yes-no` | `active-inactive` | `on-off` | `enabled-disabled`
1568
1570
  - Custom: `custom|Verdadeiro|Falso`
1569
1571
 
1570
1572
  Exemplos de ColumnDefinition:
1571
1573
  ```ts
1572
- { field: 'salario', type: 'currency', format: 'BRL|symbol|2', header: 'Salário' }
1574
+ { field: 'salario', type: 'currency', format: 'BRL|symbol|2', header: 'Salário' }
1573
1575
  { field: 'desconto', type: 'percentage', format: '1.1-1|x100', header: 'Desconto' }
1574
1576
  { field: 'criadoEm', type: 'date', format: 'dd/MM/yyyy', header: 'Criado em' }
1575
- { field: 'nome', type: 'string', format: 'titlecase|truncate|32|…', header: 'Nome' }
1577
+ { field: 'nome', type: 'string', format: 'titlecase|truncate|32|…', header: 'Nome' }
1576
1578
  { field: 'ativo', type: 'boolean', format: 'yes-no', header: 'Ativo' }
1577
1579
  ```
1578
1580
 
1579
- Exemplos com defaults implícitos por `type + localization`:
1581
+ Exemplos com defaults implícitos por `type + localization`:
1580
1582
  ```ts
1581
1583
  {
1582
1584
  localization: {
@@ -1586,22 +1588,22 @@ Exemplos com defaults implícitos por `type + localization`:
1586
1588
  number: { decimalSeparator: ',', thousandsSeparator: '.', defaultPrecision: 2, negativeSign: '-', negativeSignPosition: 'before' },
1587
1589
  },
1588
1590
  columns: [
1589
- { field: 'salario', type: 'currency', header: 'Salário' },
1591
+ { field: 'salario', type: 'currency', header: 'Salário' },
1590
1592
  { field: 'criadoEm', type: 'date', header: 'Criado em' },
1591
1593
  { field: 'taxa', type: 'percentage', header: 'Taxa' },
1592
1594
  ],
1593
1595
  }
1594
1596
  ```
1595
1597
 
1596
- Observações:
1597
- - `|nosep` remove separadores de milhar da saída formatada.
1598
- - Para datas inválidas ou valores não numéricos, o serviço retorna o valor original (com aviso no console).
1599
- - Colunas com renderizador `custom` não passam por formatação automática.
1600
- - Precedência de locale para formatação: `config.localization.locale` -> `LOCALE_ID` do host.
1601
- - Quando `config.localization.currency` estiver presente, a tabela usa esse bloco como override para código, símbolo, posição, espaçamento e precisão da moeda.
1598
+ Observações:
1599
+ - `|nosep` remove separadores de milhar da saída formatada.
1600
+ - Para datas inválidas ou valores não numéricos, o serviço retorna o valor original (com aviso no console).
1601
+ - Colunas com renderizador `custom` não passam por formatação automática.
1602
+ - Precedência de locale para formatação: `config.localization.locale` -> `LOCALE_ID` do host.
1603
+ - Quando `config.localization.currency` estiver presente, a tabela usa esse bloco como override para código, símbolo, posição, espaçamento e precisão da moeda.
1602
1604
  - Quando `config.localization.number` estiver presente, a tabela respeita `decimalSeparator`, `thousandsSeparator`, `defaultPrecision`, `negativeSign` e `negativeSignPosition` em number/currency/percentage.
1603
1605
 
1604
- Exemplos práticos no workspace (rotas):
1606
+ Exemplos práticos no workspace (rotas):
1605
1607
  - Regras Visuais (Simples): `/table-rules-simple`
1606
1608
  - Regras Visuais (Complexas): `/table-rules-complex`
1607
1609
 
@@ -1642,22 +1644,22 @@ A11y, seguranca e performance:
1642
1644
  - URL da imagem sanitizada (bloqueia esquemas perigosos)
1643
1645
  - imagem com `loading=\"lazy\"`
1644
1646
 
1645
- ## 📊 Roadmap
1647
+ ## 📊 Roadmap
1646
1648
 
1647
- ### Próximas Versões
1649
+ ### Próximas Versões
1648
1650
 
1649
- - Arquitetura unificada (v2.0.0)
1650
- - 🔄 Enhanced mobile support (v2.1.0)
1651
- - 📋 Advanced export options (v2.2.0)
1652
- - 🎨 Theme customization (v2.3.0)
1651
+ - ✅ Arquitetura unificada (v2.0.0)
1652
+ - 🔄 Enhanced mobile support (v2.1.0)
1653
+ - 📋 Advanced export options (v2.2.0)
1654
+ - 🎨 Theme customization (v2.3.0)
1653
1655
 
1654
- ## 📄 Licença
1656
+ ## 📄 Licença
1655
1657
 
1656
- Apache-2.0 consulte `LICENSE` na raiz do workspace para detalhes.
1658
+ Apache-2.0 — consulte `LICENSE` na raiz do workspace para detalhes.
1657
1659
 
1658
1660
  ---
1659
1661
 
1660
1662
  **Parte do Praxis UI Workspace**
1661
- **Versão**: 2.0.0 (Unified Architecture)
1663
+ **Versão**: 2.0.0 (Unified Architecture)
1662
1664
  **Compatibilidade**: Angular 18+
1663
1665