@praxisui/table 1.0.0-beta.8 → 3.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,11 +1,99 @@
1
+ ---
2
+ title: "Table"
3
+ slug: "table-overview"
4
+ description: "Visao geral do @praxisui/table com TableConfig unificada, filtros, renderers, performance e integracao enterprise."
5
+ doc_type: "reference"
6
+ document_kind: "component-overview"
7
+ component: "table"
8
+ category: "components"
9
+ audience:
10
+ - "frontend"
11
+ - "host"
12
+ - "architect"
13
+ level: "intermediate"
14
+ status: "active"
15
+ owner: "praxis-ui"
16
+ tags:
17
+ - "table"
18
+ - "tableconfig"
19
+ - "filters"
20
+ - "renderers"
21
+ - "enterprise"
22
+ order: 25
23
+ icon: "table_chart"
24
+ toc: true
25
+ sidebar: true
26
+ search_boost: 1.0
27
+ reading_time: 14
28
+ estimated_setup_time: 25
29
+ version: "1.0"
30
+ related_docs:
31
+ - "dynamic-filter-architecture-overview"
32
+ - "dynamic-filter-host-integration-guide"
33
+ - "dynamic-filter-payload-contract"
34
+ - "dynamic-filter-range-filters-guide"
35
+ - "dynamic-filter-editor-settings-guide"
36
+ - "dynamic-inline-filter-catalog"
37
+ - "dynamic-filter-troubleshooting-guide"
38
+ - "dynamic-filter-backend-contract-cheatsheet"
39
+ - "adr-dynamic-filter-cross-lib-coupling-2026-03"
40
+ - "host-integration-guide"
41
+ - "consumer-integration-quickstart"
42
+ keywords:
43
+ - "TableConfig"
44
+ - "filters"
45
+ - "renderers"
46
+ - "performance"
47
+ - "dynamic filter"
48
+ last_updated: "2026-03-07"
49
+ ---
50
+
1
51
  # @praxisui/table
2
52
 
53
+ ## Documentation
54
+
55
+ - Documentação oficial: https://praxisui.dev
56
+ - Aplicação de referência: https://github.com/codexrodrigues/praxis-ui-quickstart
57
+ - Indicado para: data grids enterprise com filtros, edicao, virtualizacao, renderers e governanca de configuracao
58
+
59
+ ## When to use
60
+
61
+ - Exibir grandes volumes de dados com filtros e operacoes ricas
62
+ - Governar configuracao de colunas, toolbar e comportamento em runtime
63
+ - Integrar tabelas a fluxos CRUD, IA e editores visuais do ecossistema Praxis UI
64
+
3
65
  > Componente de tabela empresarial avançado com arquitetura unificada
4
66
 
67
+ ## Customization Mode Contract
68
+
69
+ - `enableCustomization` is the canonical public input for runtime customization mode.
70
+ - The default is `false`; hosts opt in when they want settings, authoring affordances and schema-drift UX.
71
+ - Customization mode does not change the table data mode. It only gates configuration/editorial surfaces.
72
+
73
+ ## Migration Note
74
+
75
+ - This release treats `enableCustomization=false` as the canonical default.
76
+ - Hosts that relied on the previous implicit authoring behavior must now declare `[enableCustomization]="true"` explicitly.
77
+ - This is an intentional breaking change for enterprise governance: authoring is opt-in, not ambient.
78
+
5
79
  ## 🌟 Visão Geral
6
80
 
7
81
  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.
8
82
 
83
+ ## 🎨 Tema M3 (tokens mínimos)
84
+
85
+ Para garantir que a tabela, filtros e editores reflitam o tema do app host:
86
+
87
+ - Superfícies: `--md-sys-color-surface`, `--md-sys-color-surface-variant`, `--md-sys-color-surface-container-*`
88
+ - 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`
89
+ - Semânticos: `--md-sys-color-primary`, `--md-sys-color-secondary`, `--md-sys-color-tertiary`, `--md-sys-color-error`
90
+ - Containers: `--md-sys-color-primary-container`, `--md-sys-color-secondary-container`, `--md-sys-color-tertiary-container`, `--md-sys-color-error-container`
91
+ - Overlay: `--md-sys-color-scrim`
92
+ - Elevação: `--md-sys-elevation-level1`–`--md-sys-elevation-level3`
93
+
94
+ Observação: tokens `--md-sys-*` e `--mdc-theme-*` continuam aceitos quando presentes.
95
+ Nota: a classe de tema é decisão do host (`.dark-theme` ou `.theme-dark`/`.theme-light`); mantenha tokens e componentes no mesmo escopo.
96
+
9
97
  ## ✨ Características Principais
10
98
 
11
99
  ### 🏗️ Arquitetura Unificada
@@ -27,6 +115,15 @@ A biblioteca `@praxisui/table` fornece um componente de tabela robusto e altamen
27
115
  - **Acessibilidade**: WCAG 2.1 AA compliant
28
116
  - **Verificação de Schema**: ETag/If-None-Match com notificações (somente em customização)
29
117
 
118
+ ### 📄 Contrato Inline do Filtro
119
+
120
+ - Referencia canonica: `projects/praxis-dynamic-fields/docs/dynamic-fields-inline-components-guide.md` (slug publicado: `dynamic-fields-inline-components-guide`)
121
+ - No contexto da tabela, use este contrato para definir `controlType` inline e politica de compatibilidade (canonica vs legado).
122
+
123
+ ### 🧭 Decisoes de Arquitetura (ADR)
124
+
125
+ - Bundle/adapters: `projects/praxis-table/docs/adr/2026-03-filter-drawer-adapter-light-entrypoint.md`
126
+
30
127
  ### 🎨 Editores Visuais
31
128
 
32
129
  - **Behavior Editor**: Configuração de comportamentos
@@ -34,12 +131,211 @@ A biblioteca `@praxisui/table` fornece um componente de tabela robusto e altamen
34
131
  - **Toolbar Editor**: Personalização de ações
35
132
  - **Messages Editor**: Textos e localização
36
133
 
134
+ Nota (Regras)
135
+ - 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.
136
+
137
+ ### 🧩 Editor de Regras (column-first)
138
+
139
+ O novo editor é "column-first" e usa uma tipagem compartilhada com o Editor de Colunas. Principais pontos:
140
+
141
+ - Escopo: aplique regras na linha inteira (rowConditionalStyles) ou em uma coluna específica (columns[].conditionalStyles).
142
+ - Operadores por tipo: o conjunto de operadores é filtrado por tipo (string/number/date/boolean/enum).
143
+ - Editores de valor dinâmicos: inputs numéricos, listas (CSV/múltipla seleção), datepickers.
144
+ - Grupos lógicos: construa condições com AND/OR/NOT e reordene via arrastar-e-soltar (CDK DragDrop).
145
+ - Preview: execute “Testar” para ver quantas linhas seriam afetadas pelas regras ativas.
146
+ - Import/Export: exporta JSON sem o campo `enabled`; importa com validação de DSL e sanitização de estilos (allowlist).
147
+
148
+ Exemplos de DSL:
149
+
150
+ ```text
151
+ contains(status, 'Ativo')
152
+ not (status in ['A', 'I'])
153
+ (price >= 10 and price <= 20)
154
+ (createdAt >= '2024-10-01' and createdAt <= '2024-10-31')
155
+ (name == null or name == '')
156
+ active == true
157
+ ```
158
+
159
+ Notas sobre enum/CSV:
160
+ - Para campos enumerados, as opções são inferidas de `valueMapping` da coluna ou de `fields?.options`.
161
+ - Para `in/not in` em números/strings, use CSV (ex.: `10, 20, 30` ou `Alice, Bob`).
162
+
163
+ #### Extensões de DSL (runtime nativo + custom)
164
+
165
+ O runtime da tabela já inclui helpers de JSON/tempo/listas/texto sem configuração extra:
166
+
167
+ - JSON: `jsonGet`, `hasJsonKey`, `jsonPathMatches`, `jsonEq`, `jsonIn`, `jsonType`
168
+ - Texto/valor: `isBlank`, `eqIgnoreCase`, `coalesce`
169
+ - Faixas: `between`, `dateBetween`
170
+ - Coleções: `containsAny`, `containsAll`, `len`, `lenEq`, `lenGt`, `lenLt`, `lenAtLeast`
171
+ - Tempo: `today`, `now`, `dateAdd`, `dateFormat`, `isToday`, `inLast`, `isPast`, `isPastOrNow`, `isFuture`, `isFutureOrNow`, `weekdayIn`
172
+
173
+ Exemplos de DSL (canônica):
174
+ - `jsonEq(payload, '$.user.name', 'Alice')`
175
+ - `jsonIn(customer, '$.id', [10, 20])`
176
+ - `eqIgnoreCase(status, 'ATIVO')`
177
+ - `between(amount, 10, 20)`
178
+ - `dateBetween(createdAt, '2025-01-01', '2025-12-31')`
179
+ - `containsAll(tags, ['vip', 'gold'])`
180
+
181
+ Observação de gramática:
182
+ - 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`.
183
+
184
+ Guia completo: `projects/praxis-table/docs/DSL-Extensions-Guide.md`
185
+
186
+ #### 🎨 Efeitos (Conteúdo C)
187
+
188
+ O bloco de Efeitos permite aplicar estilo e visuais quando a condição é verdadeira:
189
+
190
+ - Toolbar de texto com ícones (negrito, itálico, sublinhado) e presets rápidos (tachado, maiúsculas/minúsculas/capitalizar, tamanho +/- e reset).
191
+ - Presets de feedback com ícones (sucesso, aviso, erro, info) — mantêm o rótulo via tooltip e `aria-label`.
192
+ - “Posição do valor” como grupo de alternância (antes / entre-1 / entre-2 / depois / oculto).
193
+ - “Ordem dos visuais” com seletor compacto (3 mais comuns) e menu para opções extras.
194
+ - Layout do compose: espaçamento, alinhamento, quebra de linha e reticências.
195
+
196
+ Dicas
197
+ - Use “Resetar texto” para reverter efeitos de texto sem perder cor de fundo/borda.
198
+ - Para acessibilidade, os grupos possuem `role="toolbar"`, tooltips e navegação por teclado consistente.
199
+
200
+ Como reverter efeitos
201
+ - “Reset Text” remove apenas propriedades de tipografia e transformação de texto.
202
+ - “Limpar efeitos” apaga classe e estilo livres do bloco rápido.
203
+
204
+ Observação: capturas de tela “antes/depois” podem ser adicionadas no PR conforme necessário.
205
+
206
+ #### Relacionais (lookup)
207
+
208
+ Campos relacionais (FK/objetos) podem ser editados no Rules Editor com busca assíncrona (typeahead) e seleção single/multiple.
209
+
210
+ Boas práticas
211
+ - Informe `resourcePath` (ou `endpoint`) no `FieldDefinition` para habilitar o lookup via `GenericCrudService` do host.
212
+ - Defina `valueField` (chave estável, tipicamente `id`) e `displayField` (label amigável, como `name`).
213
+
214
+ ## 🔎 Filtro: Atalhos para Período (DateRange)
215
+
216
+ Habilite atalhos de período no filtro dinâmico sem alterar o contrato do `praxis-filter` — apenas via metadata do campo:
217
+
218
+ ```ts
219
+ // Em FilterConfig (ou na metadata de campos do filtro)
220
+ {
221
+ name: 'period',
222
+ label: 'Período',
223
+ controlType: 'dateRange',
224
+ showShortcuts: true,
225
+ shortcuts: ['thisMonth','lastMonth','thisYear'],
226
+ // Opcional:
227
+ // i18nShortcuts: { thisMonth: 'Este mês', lastMonth: 'Mês passado' },
228
+ // applyOnShortcutClick: true
229
+ }
230
+ ```
231
+ - Para múltipla seleção, use `multiple: true` no `FieldDefinition` quando aplicável.
232
+ - No runtime da tabela não é necessário registrar funções JSON/data manualmente; os helpers já são embutidos.
233
+ - APIs com busca: suporte a um parâmetro livre de texto (por ex. `search`) facilita a experiência do autocomplete.
234
+
235
+ Exemplo de FieldDefinition (lookup)
236
+ ```ts
237
+ import type { FieldDefinition } from '@praxisui/core';
238
+
239
+ const fields: FieldDefinition[] = [
240
+ {
241
+ name: 'customer',
242
+ type: 'object',
243
+ // Habilita o lookup via GenericCrudService
244
+ resourcePath: 'customers',
245
+ // Mapeia o id/label que virão do backend
246
+ valueField: 'id',
247
+ displayField: 'name',
248
+ // Se quiser multiseleção em todo o app
249
+ // multiple: true,
250
+ },
251
+ ];
252
+ ```
253
+
254
+ Operadores e DSL gerada (relacional)
255
+ - `id ==` → `jsonEq(customer, '$.id', 10)`
256
+ - `id in` → `jsonIn(customer, '$.id', [10, 20])`
257
+ - `has property` → `hasJsonKey(customer, '$.meta.etag')`
258
+ - Condições por caminho (join simples): use `key ==` (JSON Path + valor)
259
+
260
+ UI (no editor)
261
+ - `id ==` (single): autocomplete + chip “label [id]” com ação “Limpar”.
262
+ - `id in` (multi): autocomplete + chips removíveis por item.
263
+ - `has property`: input do caminho (ex.: `$.meta.etag`).
264
+
265
+ Formato esperado do payload (relacional)
266
+
267
+ 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:
268
+
269
+ ```ts
270
+ // Exemplo de linha (row) com campo relacional "customer"
271
+ const row = {
272
+ id: 123,
273
+ customer: {
274
+ id: 10, // ← usado em id == / id in via jsonEq/jsonIn
275
+ name: 'ACME', // ← usado para exibir label no autocomplete/chip
276
+ meta: { etag: 'v1' },
277
+ },
278
+ };
279
+
280
+ // Regras DSL comuns
281
+ // id ==
282
+ // jsonEq(customer, '$.id', 10)
283
+ // id in
284
+ // jsonIn(customer, '$.id', [10, 20])
285
+ // has property
286
+ // hasJsonKey(customer, '$.meta.etag')
287
+ // caminho/valor (join simples)
288
+ // jsonEq(customer, '$.name', 'ACME')
289
+ ```
290
+
291
+ Notas
292
+ - O editor usa `displayField` (ex.: `name`) para compor o rótulo, e `valueField` (ex.: `id`) para gerar a DSL.
293
+ - 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.
294
+
295
+ Onde é consumido (preview e runtime)
296
+
297
+ - Preview/validação no Editor de Regras (usa `DslParser` interno):
298
+ - Validação da expressão (parse): projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts:536
299
+ - Preview “Testar” (parse + evaluate): projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts:909
300
+ - Runtime na Tabela (aplica `rowConditionalStyles`/`conditionalStyles`):
301
+ - Parser interno do componente: projects/praxis-table/src/lib/praxis-table.ts:282
302
+
303
+ Observação
304
+ - O runtime da tabela já injeta o registry DSL padrão para validação/parse/execução.
305
+ - Para funções realmente custom, injete via input `[dslFunctionRegistry]` no componente.
306
+
307
+ Exemplo de Provider (recomendado)
308
+
309
+ ```ts
310
+ import { Injectable } from '@angular/core';
311
+ import { FunctionRegistry } from '@praxisui/specification';
312
+
313
+ @Injectable({ providedIn: 'root' })
314
+ export class TableDslRegistryFactory {
315
+ private readonly registry = FunctionRegistry.getInstance<any>('orders-table-rules');
316
+
317
+ constructor() {
318
+ this.registry.clear();
319
+ this.registry.register('isStatus', (_row: any, value: any, expected: any) =>
320
+ String(value ?? '').toLowerCase() === String(expected ?? '').toLowerCase(),
321
+ );
322
+ }
323
+
324
+ get(): FunctionRegistry<any> {
325
+ return this.registry;
326
+ }
327
+ }
328
+
329
+ // Uso no host:
330
+ // <praxis-table [dslFunctionRegistry]="tableDslRegistryFactory.get()" ... />
331
+ ```
332
+
37
333
  ### ⚙️ Painel de Configurações
38
334
 
39
335
  Para abrir o painel de configurações, habilite o modo de edição na tabela:
40
336
 
41
337
  ```html
42
- <praxis-table [editModeEnabled]="true"></praxis-table>
338
+ <praxis-table [enableCustomization]="true"></praxis-table>
43
339
  ```
44
340
 
45
341
  Um botão de engrenagem será exibido no canto superior direito. Ao clicar nele, o `SettingsPanel` é aberto permitindo ajustar:
@@ -77,14 +373,14 @@ Quando `resourcePath` é fornecido, a tabela se torna "inteligente":
77
373
 
78
374
  ```html
79
375
  <!-- Exemplo no template do seu componente -->
80
- <praxis-table resourcePath="human-resources/departamentos" [editModeEnabled]="true"> </praxis-table>
376
+ <praxis-table resourcePath="human-resources/departamentos" [enableCustomization]="true"> </praxis-table>
81
377
  ```
82
378
 
83
379
  Neste exemplo:
84
380
 
85
381
  - `resourcePath="human-resources/departamentos"` instrui a tabela a se comunicar com o endpoint `/api/human-resources/departamentos`.
86
382
  - A tabela fará requisições como `POST /api/human-resources/departamentos/filter` para obter os dados e `GET /api/human-resources/departamentos/schemas` para obter a configuração das colunas.
87
- - `[editModeEnabled]="true"` permite a edição visual da configuração da tabela em tempo real.
383
+ - `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.
88
384
 
89
385
  ### Empty State + Quick Connect (sem `resourcePath`)
90
386
 
@@ -233,14 +529,18 @@ Quando `behavior.virtualization.enabled` estiver ativo, as linhas da tabela são
233
529
 
234
530
  ### Concept Usage
235
531
 
236
- - [Schemadriven UI](../../../../docs/concepts/schema-driven-ui.md)
237
- - [Selfdescribing APIs](../../../../docs/concepts/self-describing-apis.md)
238
- - [Rules Engines & Specifications](../../../../docs/concepts/rules-engines-and-specifications.md)
239
- - [Configurationdriven development](../../../../docs/concepts/configuration-driven-development.md)
532
+ - Schema-driven UI
533
+ - Self-describing APIs
534
+ - Rules engines and specifications
535
+ - Configuration-driven development
240
536
 
241
537
  - `behavior.pagination.position`: `top` | `bottom` | `both`.
242
538
  - `behavior.pagination.style`: `default` | `compact` (aplica classe de estilo no paginator).
243
539
 
540
+ Nota sobre estratégia (client vs server)
541
+ - Se `behavior.pagination.strategy` não estiver definido, a tabela assume `server` automaticamente quando há `resourcePath` (dados remotos). Caso contrário, usa `client`.
542
+ - O mesmo vale para `behavior.sorting.strategy`.
543
+
244
544
  ## Duplo clique na linha
245
545
 
246
546
  Ative em Comportamento → Interação.
@@ -274,6 +574,7 @@ onRowDoubleClick(evt: { action: string; row: any }) {
274
574
 
275
575
  - Configure em `behavior.sorting.defaultSort`.
276
576
  - Aceita objeto único (coluna/direção) ou array para multi‑sort.
577
+ - Status runtime atual: `behavior.sorting.multiSort` está **schema-only** (apenas 1 critério efetivo em runtime).
277
578
 
278
579
  Exemplos:
279
580
 
@@ -299,9 +600,18 @@ sorting: {
299
600
  ```
300
601
 
301
602
  Observação: quando informado, o defaultSort é aplicado na carga inicial se não houver estado de ordenação ativo.
603
+ 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.
604
+
605
+ ### Roadmap / migração de multiSort
606
+
607
+ - Curto prazo: `multiSort` segue schema-only no runtime.
608
+ - Recomendação de migração: desenhar integrações com fallback para ordenação única (`column` + `direction`).
609
+ - Planejamento: quando multi-sort runtime for implementado, publicar release note com guia de ativação gradual (feature-flag + validação de payload legado).
302
610
 
303
611
  ## Coluna de ações (sticky)
304
612
 
613
+ Nota: por padrão a coluna de ações vem desabilitada. Habilite explicitamente em `actions.row.enabled` e defina as ações desejadas.
614
+
305
615
  - Fixe a coluna de ações no início/fim configurando `actions.row.sticky`:
306
616
 
307
617
  ```ts
@@ -340,7 +650,7 @@ Onde configurar no Editor Visual:
340
650
 
341
651
  ## 🔒 Verificação de Schema (ETag) e Notificações (somente em customização)
342
652
 
343
- 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 (`editModeEnabled = true`).
653
+ 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`).
344
654
 
345
655
  ### Comportamento
346
656
 
@@ -383,12 +693,16 @@ sequenceDiagram
383
693
 
384
694
  ### Inputs/Outputs
385
695
 
386
- - Inputs (efetivos apenas quando `editModeEnabled = true`):
696
+ - Inputs (efetivos apenas quando `enableCustomization = true`):
387
697
  - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'`
388
- - `snoozeMs: number = 86400000` (24h)
698
+ - `snoozeMs: number = 86400000`
389
699
  - `autoOpenSettingsOnOutdated: boolean = false`
390
- - Output:
391
- - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; resourcePath?: string }`
700
+ - `dslFunctionRegistry: FunctionRegistry<any> | null = null`
701
+ - Outputs:
702
+ - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; trigger?: string; tableId?: string }`
703
+ - Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via `loadSchema()`).
704
+ - `metadataChange: { trigger: string; meta: any; tableId?: string }`
705
+ - Emitido quando `config.meta` é atualizado (ex.: após bootstrap ou verificação ETag). Útil para sincronizar sidebars/bridges de metadados.
392
706
 
393
707
  ### Fallback Global (opcional)
394
708
 
@@ -415,7 +729,7 @@ sequenceDiagram
415
729
 
416
730
  ```html
417
731
  <praxis-table
418
- [editModeEnabled]="true"
732
+ [enableCustomization]="true"
419
733
  [notifyIfOutdated]="'both'"
420
734
  [snoozeMs]="12 * 60 * 60 * 1000"
421
735
  [autoOpenSettingsOnOutdated]="false"
@@ -436,14 +750,14 @@ onSchemaStatus(ev: { outdated: boolean; serverHash?: string; lastVerifiedAt?: st
436
750
  ### Notas
437
751
 
438
752
  - A verificação leve não grava nem usa o schema bruto quando `config.columns` já existe.
439
- - Em ambientes sem customização (`editModeEnabled=false`), não há notificações visuais; ainda assim `schemaStatusChange` é emitido e `config.meta.lastVerifiedAt` atualizado.
753
+ - Em ambientes sem customização (`enableCustomization=false`), não há notificações visuais; ainda assim `schemaStatusChange` é emitido e `config.meta.lastVerifiedAt` atualizado.
440
754
 
441
755
  ## Filtro Avançado (PraxisFilter)
442
756
 
443
757
  ### Boas práticas para estabilidade
444
758
 
445
759
  - Evite literais em bindings para o carregador dinâmico:
446
- - Não use `[fields]="[quickFieldMeta]"`; prefira um array estável como `quickFieldMetaArray` atualizado apenas quando o metadata mudar.
760
+ - Não use `[fields]="[pinnedFieldMeta]"`; prefira um array estável como `pinnedFieldMetaArray` atualizado apenas quando o metadata mudar.
447
761
  - 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.
448
762
  - Evite recriar arrays/objetos desnecessariamente em `ngOnChanges`/`ngAfterViewInit`. Prefira atualizar valores (`setValue`, `patchValue`) e manter referências estáveis.
449
763
  - Observers (Resize/Mutation): atualize `overlayOrigin` e largura apenas quando houver mudanças reais; isso evita loops de CD.
@@ -471,7 +785,7 @@ onSchemaStatus(ev: { outdated: boolean; serverHash?: string; lastVerifiedAt?: st
471
785
  - O `PraxisFilter` busca schema do DTO de filtro via `/schemas/filtered` com ETag/If-None-Match
472
786
  e emite `metaChanged` com `{ schemaId, serverHash, context }`.
473
787
  - O schema é normalizado e `advancedConfig.metadata` é preenchido para auditoria/telemetria.
474
- - Detalhes: `docs/schemas/fluxo-schema.md` (cliente/caching, 200/304, reconciliadores Form/Filter).
788
+ - 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.
475
789
 
476
790
  ### Resolução da chave primária (idField)
477
791
 
@@ -528,7 +842,9 @@ sequenceDiagram
528
842
 
529
843
  ### Uso com Dados Locais (Client-Side)
530
844
 
531
- 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`. Neste modo, todas as operações (paginação, ordenação, filtro) são realizadas no lado do cliente.
845
+ 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`.
846
+ Importante: o modo local está protegido por feature flag e exige `behavior.localDataMode.enabled = true` (default é `false`).
847
+ Quando a flag está ativa, as operações de paginação, ordenação e filtro são executadas no lado do cliente.
532
848
 
533
849
  ```typescript
534
850
  import { PraxisTable } from "@praxisui/table";
@@ -548,12 +864,13 @@ export class ExampleComponent {
548
864
  { field: "name", header: "Nome", type: "string" },
549
865
  { field: "email", header: "Email", type: "string" },
550
866
  ],
551
- behavior: {
552
- pagination: { enabled: true, pageSize: 10 },
553
- sorting: { enabled: true },
554
- filtering: { enabled: true },
555
- },
556
- };
867
+ behavior: {
868
+ pagination: { enabled: true, pageSize: 10 },
869
+ sorting: { enabled: true },
870
+ filtering: { enabled: true },
871
+ localDataMode: { enabled: true }, // obrigatório para fluxo local oficial
872
+ },
873
+ };
557
874
 
558
875
  employees = [
559
876
  { id: 1, name: "João Silva", email: "joao@empresa.com" },
@@ -567,6 +884,8 @@ export class ExampleComponent {
567
884
 
568
885
  Quando a `<praxis-table>` é conectada a um `resourcePath`, as operações de paginação, ordenação e filtro são delegadas ao backend. Isso garante alta performance, pois apenas os dados visíveis na tela são trafegados pela rede.
569
886
 
887
+ 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.
888
+
570
889
  O diagrama abaixo detalha a sequência de eventos, desde a interação do usuário na UI até a construção da consulta JPA no servidor.
571
890
 
572
891
  ```mermaid
@@ -638,7 +957,7 @@ sequenceDiagram
638
957
 
639
958
  ## 🎨 Edição Visual da Tabela: O Poder do Low-Code
640
959
 
641
- 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. Ative o editor passando a propriedade `[editModeEnabled]="true"` para o componente.
960
+ 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"`.
642
961
 
643
962
  A seguir, veja os principais recursos que você pode configurar visualmente:
644
963
 
@@ -871,7 +1190,8 @@ export class MyComponent {
871
1190
  this.configService.setConfig(this.tableConfig);
872
1191
 
873
1192
  // Verificar recursos disponíveis
874
- const hasMultiSort = this.configService.isFeatureEnabled('multiSort');
1193
+ // No runtime atual, multiSort permanece schema-only.
1194
+ const hasMultiSort = false;
875
1195
  const hasBulkActions = this.configService.isFeatureEnabled('bulkActions');
876
1196
  }
877
1197
  }
@@ -1022,7 +1342,7 @@ Configurações de comportamento (paginação, ordenação, etc.).
1022
1342
 
1023
1343
  Configurações de aparência visual.
1024
1344
 
1025
- Para documentação completa da API, consulte a [documentação da @praxisui/core](../praxis-core/README.md).
1345
+ Para documentação completa da API, consulte `projects/praxis-core/README.md`.
1026
1346
 
1027
1347
  ## 🤝 Contribuição
1028
1348
 
@@ -1046,7 +1366,7 @@ Para documentação completa da API, consulte a [documentação da @praxisui/cor
1046
1366
  O `PraxisFilter` pode ser acoplado à barra de ferramentas da tabela. O exemplo abaixo mostra a busca de pessoas por CPF e status.
1047
1367
 
1048
1368
  ```html
1049
- <praxis-filter [resourcePath]="'pessoas'" [formId]="'pessoas-filter'" [persistenceKey]="'pessoas-filter-v1'" [quickField]="'cpf'" [alwaysVisibleFields]="['status']" (submit)="onFilter($event)"></praxis-filter> <praxis-table [data]="tableData"></praxis-table>
1369
+ <praxis-filter [resourcePath]="'pessoas'" [formId]="'pessoas-filter'" [persistenceKey]="'pessoas-filter-v1'" [alwaysVisibleFields]="['status']" (submit)="onFilter($event)"></praxis-filter> <praxis-table [data]="tableData"></praxis-table>
1050
1370
  ```
1051
1371
 
1052
1372
  ```ts
@@ -1058,15 +1378,15 @@ onFilter(dto: any) {
1058
1378
  }
1059
1379
  ```
1060
1380
 
1061
- ### ⚙️ Painel de Configurações do Filtro
1381
+ ### ⚙️ Configuração do Filtro
1062
1382
 
1063
- O `PraxisFilter` possui um painel de configurações acessível pelo ícone de
1064
- engrenagem na barra do filtro ou programaticamente através do método
1383
+ O `PraxisFilter` pode ser configurado por inputs/JSON de configuração. O atalho
1384
+ visual por ícone de engrenagem não é exposto por padrão na tabela/demo.
1385
+ Quando necessário, também é possível abrir o painel programaticamente via
1065
1386
  `openSettings()`. Nesse painel é possível ajustar:
1066
1387
 
1067
- - **quickField** – campo utilizado para a busca rápida
1068
1388
  - **alwaysVisibleFields** – campos que permanecem sempre visíveis
1069
- - **placeholder** – texto exibido no campo de busca
1389
+ - **alwaysVisibleFieldMetadataOverrides** – patch de metadata por campo sempre visível (controle, clearButton, inlineAutoSize etc.)
1070
1390
  - **showAdvanced** – define se a seção avançada inicia aberta
1071
1391
 
1072
1392
  ```ts
@@ -1078,19 +1398,43 @@ abrirConfiguracoes() {
1078
1398
  ```
1079
1399
 
1080
1400
  Ao aplicar ou salvar, as escolhas são validadas contra os metadados
1081
- disponíveis. O componente exibe uma barra de progresso durante o processo
1082
- de persistência e mensagens de sucesso ou erro via _snack bar_, garantindo
1083
- uma experiência consistente.
1401
+ do **DTO de filtro** (schema de `POST /{resource}/filter`). Campos ausentes
1402
+ no DTO não são aplicados em `alwaysVisibleFields`.
1403
+ O componente exibe uma barra de progresso durante o processo de persistência e
1404
+ mensagens de sucesso ou erro via _snack bar_, garantindo uma experiência
1405
+ consistente.
1406
+
1407
+ ### 🔖 Mini‑guia: Atalhos do Filtro (tags)
1408
+
1409
+ Atalhos são “chips” que guardam um conjunto de filtros (DTO) para reuso rápido.
1410
+
1411
+ - Criar/Salvar
1412
+ - Modal (padrão): o host do diálogo exibe o botão quando `allowSaveTags === true`.
1413
+ - Gaveta (Drawer): o Adapter recebe `allowSaveTags?`, `i18nSaveAsShortcut?` e `onSaveShortcut?` (opcionais). O host deve exibir o botão e chamar `onSaveShortcut(clean({ ...initialDto, ...lastValue }))`.
1414
+ - O DTO é limpo antes de persistir (remove `'' | null | undefined`).
1415
+ - Aplicar
1416
+ - Clique/Enter no chip aplica imediatamente `tag.patch` (substitui o estado atual), emite `submit` e persiste.
1417
+ - O chip ativo é destacado (cor/borda + ícone de “check”) quando o DTO atual é igual ao patch do atalho.
1418
+ - Editar/Renomear
1419
+ - Apenas atalhos do usuário exibem ícone de lápis. Predefinidos mostram ícone de “cadeado” (somente leitura).
1420
+ - Excluir (com Undo)
1421
+ - Exclusão remove imediatamente o atalho do usuário e exibe snackbar “Atalho removido” com ação “Desfazer” quando `confirmTagDelete === true`.
1422
+ - Ao clicar em “Desfazer”, o atalho é restaurado na mesma posição e os eventos são reemitidos.
1423
+ - i18n
1424
+ - Chaves úteis: `saveAsShortcut`, `renameShortcut`, `removeShortcut`, `shortcutSaved`, `shortcutRemoved`, `undo`, `readonlyShortcut`.
1425
+
1426
+ 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.
1084
1427
 
1085
1428
  ### Novos Inputs/Outputs (PraxisFilter)
1086
1429
 
1087
- - Inputs (efetivos apenas quando `editModeEnabled = true`):
1088
- - `editModeEnabled: boolean` — habilita o gate de customização para notificações de schema.
1089
- - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'` — canal de notificação quando o schema muda.
1430
+ - Inputs (efetivos apenas quando `enableCustomization = true`):
1431
+ - `enableCustomization: boolean` — habilita o gate de customização para notificações de schema.
1432
+ - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'` — seleciona como o runtime publica avisos de drift quando a política operacional estiver habilitada.
1090
1433
  - `snoozeMs: number = 86400000` — tempo de soneca para avisos (ms).
1091
1434
  - `autoOpenSettingsOnOutdated: boolean = false` — abre Configurações ao detectar schema desatualizado.
1435
+ - `dslFunctionRegistry: FunctionRegistry<any> | null = null` — adiciona funções DSL custom sem substituir o registry nativo.
1092
1436
  - Output:
1093
- - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string }` — emitido após verificação leve (304/200).
1437
+ - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; tableId?: string }` — emitido após verificação leve (304/200).
1094
1438
 
1095
1439
  #### Fallback Global (opcional)
1096
1440
 
@@ -1104,6 +1448,88 @@ Notas rápidas (Flow ETag no Filter):
1104
1448
  - 200: atualiza `serverHash/lastVerifiedAt`; marca `outdated=true` apenas quando em customização; não aplica o schema automaticamente.
1105
1449
  - O corpo do schema é baixado apenas quando necessário para renderização (ex.: `alwaysVisibleFields` ou ao abrir o painel Avançado).
1106
1450
 
1451
+ ## Formatação de Colunas (format)
1452
+
1453
+ 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`, `boolean`, `custom`.
1454
+
1455
+ Regra geral: a formatação só é aplicada quando há `format` não vazio e `type !== 'custom'`.
1456
+
1457
+ Tipos e padrões de `format`:
1458
+ - number (DecimalPipe)
1459
+ - Padrões: `minInt.minFrac-maxFrac`
1460
+ - Exemplos: `1.0-0`, `1.2-2`, `1.0-3|nosep` (remove separador de milhar)
1461
+ - currency (CurrencyPipe)
1462
+ - Sintaxe: `CURRENCY|DISPLAY|DECIMALS[|nosep]`
1463
+ - Exemplos: `BRL|symbol|2`, `USD|code|0`, `EUR|symbol|2|nosep`
1464
+ - percentage (PercentPipe/DecimalPipe)
1465
+ - Sem multiplicador: `1.0-0` (PercentPipe)
1466
+ - Multiplicar por 100: `1.1-1|x100` (DecimalPipe×100 + `%`)
1467
+ - date (DatePipe)
1468
+ - Tokens Angular: `shortDate`, `mediumDate`, `longDate`, `fullDate`, `short`, `shortTime`
1469
+ - Padrões customizados: `dd/MM/yyyy`, `yyyy-MM-dd`, `dd/MM/yyyy HH:mm`
1470
+ - string (transformações + truncamento)
1471
+ - Transform: `uppercase` | `lowercase` | `titlecase` | `capitalize` | `none`
1472
+ - Transform + truncar: `<transform>|truncate|<max>|<suffix>`
1473
+ - Exemplos: `uppercase|truncate|50|...`, `titlecase`
1474
+ - boolean (pré-definidos ou custom)
1475
+ - Presets: `true-false` | `yes-no` | `active-inactive` | `on-off` | `enabled-disabled`
1476
+ - Custom: `custom|Verdadeiro|Falso`
1477
+
1478
+ Exemplos de ColumnDefinition:
1479
+ ```ts
1480
+ { field: 'salario', type: 'currency', format: 'BRL|symbol|2', header: 'Salário' }
1481
+ { field: 'desconto', type: 'percentage', format: '1.1-1|x100', header: 'Desconto' }
1482
+ { field: 'criadoEm', type: 'date', format: 'dd/MM/yyyy', header: 'Criado em' }
1483
+ { field: 'nome', type: 'string', format: 'titlecase|truncate|32|…', header: 'Nome' }
1484
+ { field: 'ativo', type: 'boolean', format: 'yes-no', header: 'Ativo' }
1485
+ ```
1486
+
1487
+ Observações:
1488
+ - `|nosep` remove separadores de milhar da saída formatada.
1489
+ - Para datas inválidas ou valores não numéricos, o serviço retorna o valor original (com aviso no console).
1490
+ - Colunas com renderizador `custom` não passam por formatação automática.
1491
+
1492
+ Exemplos práticos no workspace (rotas):
1493
+ - Regras Visuais (Simples): `/table-rules-simple`
1494
+ - Regras Visuais (Complexas): `/table-rules-complex`
1495
+
1496
+ ## Auto-render de Avatar (strict mode)
1497
+
1498
+ No bootstrap de schema (quando `config.columns` esta vazio), a tabela detecta automaticamente colunas de avatar e aplica `renderer.type = 'avatar'`.
1499
+
1500
+ Deteccao:
1501
+ - somente quando `FieldDefinition.controlType === 'avatar'`
1502
+
1503
+ Renderer aplicado:
1504
+ - `renderer: { type: 'avatar', avatar: { srcField, initialsExpr, shape: 'circle', size: 28 } }`
1505
+ - alinhamento central e largura compacta (~56px)
1506
+ - `initialsExpr` com fallback para `nomeCompleto|nome|fullName|name|title`
1507
+
1508
+ Avatar explicito:
1509
+ - `renderer: { type: 'avatar', avatar: { srcField, initialsExpr, initialsField, shape: 'circle', size: 28 } }`
1510
+ - `initialsField` deriva automaticamente as iniciais de um campo textual quando `srcField` nao resolve imagem e `initialsExpr` nao foi informado
1511
+ - `initialsExpr` deve retornar as iniciais prontas; ele nao transforma automaticamente um campo bruto em iniciais
1512
+ - quando quiser derivar iniciais a partir de um campo textual, prefira `initialsField`
1513
+ - exemplo recomendado: `avatar: { srcField: 'photoUrl', initialsField: 'name' }`
1514
+ - exemplo de `initialsExpr` explicito: `avatar: { initialsExpr: \"= (row.name || '').trim().split(/\\s+/).slice(0,2).map(p => p[0] || '').join('').toUpperCase()\" }`
1515
+
1516
+ Comportamento importante:
1517
+ - a autodeteccao ocorre apenas no bootstrap (nao sobrescreve configuracoes de colunas persistidas)
1518
+ - se quiser desabilitar, defina renderer explicito na coluna (`image` ou `text`)
1519
+ - para cenarios sem `x-ui`, exponha renderer no config ou ajuste backend para enviar `x-ui.controlType`
1520
+
1521
+ Ajustes comuns:
1522
+ - `renderer.avatar.shape`: `'square' | 'rounded' | 'circle'`
1523
+ - `renderer.avatar.size`: numero em px
1524
+ - `renderer.avatar.alt` / `altField`
1525
+ - use `conditionalRenderers` para variar renderer por linha
1526
+
1527
+ A11y, seguranca e performance:
1528
+ - `alt`/`altField` sao respeitados
1529
+ - fallback para iniciais quando imagem falha/nao existe
1530
+ - URL da imagem sanitizada (bloqueia esquemas perigosos)
1531
+ - imagem com `loading=\"lazy\"`
1532
+
1107
1533
  ## 📊 Roadmap
1108
1534
 
1109
1535
  ### Próximas Versões
@@ -1115,7 +1541,7 @@ Notas rápidas (Flow ETag no Filter):
1115
1541
 
1116
1542
  ## 📄 Licença
1117
1543
 
1118
- Apache-2.0 — consulte [LICENSE](../../LICENSE) para detalhes.
1544
+ Apache-2.0 — consulte `LICENSE` na raiz do workspace para detalhes.
1119
1545
 
1120
1546
  ---
1121
1547