---
title: "praxis-table JSON API (Canonical)"
slug: "praxis-table-json-api"
doc_type: "api-reference"
component: "praxis-table"
document_kind: "json-api-canonical"
reference_mode: "canonical"
contract_format: "json"
contract_source: "runtime-and-code"
description: "Referencia canonica do contrato JSON do praxis-table com cobertura de runtime, precedencia, defaults e compatibilidade."
category: "components"
sub_category: "table"
audience:
  - "frontend"
  - "architect"
  - "platform-team"
level: "advanced"
status: "active"
owner: "praxis-ui"
source_of_truth:
  - "projects/praxis-table/src/lib/praxis-table.ts"
  - "projects/praxis-table/src/lib/praxis-table.html"
  - "projects/praxis-table/src/lib/praxis-table.scss"
  - "projects/praxis-table/src/lib/praxis-table-toolbar.ts"
  - "projects/praxis-table/src/lib/praxis-table-config-editor.ts"
  - "projects/praxis-table/src/lib/behavior-config-editor/behavior-config-editor.component.ts"
  - "projects/praxis-table/src/lib/header-appearance-editor/header-appearance-editor.component.ts"
  - "projects/praxis-table/src/lib/columns-config-editor/columns-config-editor.component.ts"
  - "projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts"
  - "projects/praxis-table/src/lib/toolbar-actions-editor/toolbar-actions-editor.component.ts"
  - "projects/praxis-table/src/lib/filter-settings/filter-settings.component.ts"
  - "projects/praxis-table/src/lib/messages-localization-editor/messages-localization-editor.component.ts"
  - "projects/praxis-table/src/lib/dialogs/confirm-dialog-appearance-editor.component.ts"
  - "projects/praxis-table/src/lib/crud-integration-editor/crud-integration-editor.component.ts"
  - "projects/praxis-core/src/lib/models/table-config-v2.model.ts"
  - "projects/praxis-table/src/lib/utils/action-utils.ts"
  - "projects/praxis-core/src/lib/tokens/global-action.catalog.ts"
  - "projects/praxis-core/src/lib/models/global-action.model.ts"
  - "projects/praxis-core/src/lib/actions/global-action-ui.ts"
source_of_truth_last_verified: "2026-06-24"
publish_source_of_truth: false
last_updated: "2026-06-24"
toc: true
sidebar: true
tags:
  - "json-api"
  - "canonical-contract"
  - "praxis-table"
api_stability: "canonical"
schema_verified: true
runtime_verified: true
editor_coverage_verified: false
runtime_scope: "public"
legacy_paths_present: false
has_known_mismatches: true
related_components: []
---

# praxis-table

Este documento e a referencia canonica da API JSON de praxis-table.

## Summary

- Tipo documental: API reference canonica de contrato JSON.
- Evidencia canonica permanece governada no frontmatter para auditoria interna, sem expor paths na publicacao.
- Objetivo operacional: consulta rapida, auditavel e deterministica sob pressao.
- Resumo funcional herdado: Referencia canonica da API JSON do `praxis-table`.

## Authoring contract

- O contrato primario de autoria do `praxis-table` e `TableAuthoringDocument` (`kind: "praxis.table.editor"`).
- `TableAuthoringDocument` encapsula `config` + `bindings` e e o formato correto para editor visual, editor JSON, playground e fluxos de IA.
- `TableConfig` continua sendo a projeção canonica de runtime consumida pela tabela apos normalizacao e apply plan.
- `meta.schemaId` e `meta.serverHash` devem ser tratados como snapshot persistido de reconciliacao, nao como fonte primaria do runtime.
- Em contexto de `praxis-crud`, o authoring canonico de `CrudMetadata` pertence a `@praxisui/crud`, mesmo que o ponto visual de entrada continue sendo o icone da tabela.
- A superficie `crud-integration-editor` da tabela existe apenas para overrides operacionais de runtime e nao deve ser tratada como editor canonico do documento CRUD.

## Scope and positioning

- Escopo: contrato JSON publico e limites de comportamento observavel.
- Fora de escopo: tutorial de adocao e walkthrough operacional detalhado.
- Posicionamento: referencia canonicamente governada para consumidores, arquitetos e mantenedores.

## Collection export actions

- `config.export.enabled` habilita o pipeline nativo de exportacao da tabela e deve declarar os formatos permitidos em `config.export.formats`.
- O menu nativo de exportacao dispara `exportAction` e baixa o artefato retornado por `PraxisCollectionExportService`.
- Acoes em massa podem acionar o mesmo pipeline quando usam uma chave claramente de exportacao, como `bulk-export` ou `export-selected`, ou quando declaram `exportFormat`.
- Quando `exportFormat` e declarado, o formato precisa estar habilitado em `config.export.formats`; a tabela nao deve substituir silenciosamente por outro formato.
- Acoes genericas de download, como `download-contract`, permanecem no output `bulkAction` enquanto nao declararem `exportFormat`; isso evita capturar workflows corporativos que nao sejam exportacao tabular.
- Para exportar apenas a selecao, combine `behavior.selection.enabled`, `config.export.general.scope: "selected"` e uma bulk action visivel apenas quando `selectedCount > 0`.
- Quando `config.export.general.scope` e `"selected"`, a exportacao sem linhas selecionadas e bloqueada com feedback de usuario em vez de gerar um arquivo vazio.

## AI assistant entrypoint

- `config.ai.assistant.enabled` controla a visibilidade e o acionamento do assistente de IA embarcado na tabela.
- Ausencia do campo equivale ao comportamento historico: o entrypoint continua disponivel quando o adapter de IA da tabela estiver carregado.
- Use `false` para surfaces em que o host precisa remover a acao de IA por contrato publico, sem CSS contra classes internas da tabela ou do Angular Material.
- Ao mudar para `false`, a tabela fecha o assistente e remove a sessao contextual da tabela no registry compartilhado de IA.

## Columns visibility dropdown

- `config.toolbar.columnsVisibility.enabled` controla a exibição do botão de visibilidade de colunas na barra de ferramentas.
- Por padrão, o botão de visibilidade rápida de colunas estará habilitado caso a toolbar esteja visível.
- **Guardrail de UX**: O último controle ativo no dropdown de colunas é automaticamente desabilitado quando apenas 1 coluna permanece visível, para impedir que o usuário oculte todas as colunas de dados da tabela.
- A desativação rápida de colunas reflete instantaneamente no layout visual (`displayedColumns`) e emite o evento `configChange`.

> [!WARNING]
> **Segurança Corporativa em Cenários Corporativos**: A visibilidade de colunas via dropdown da toolbar é um recurso estritamente visual (layout de apresentação do lado do cliente). A ocultação de colunas **não** protege o dado sensível da transmissão de rede nem de inspeção técnica. Se determinados campos (ex: salários, senhas ou tokens) forem confidenciais para o nível de permissão do usuário atual, a restrição de dados deve ser realizada obrigatoriamente no lado do servidor (através da filtragem de propriedades nas APIs de CRUD e consulta), e nunca por meio de ocultação puramente visual na tabela.

## Quick filters and density

- `config.toolbar.filters.quickFilters[]` materializa um pequeno seletor de escopo na toolbar. Cada item declara `id`, `label`, `filter` e `icon` opcional. O runtime mantém no máximo um item ativo; acionar novamente o item atual restaura os critérios anteriores.
- O filtro rápido é combinado com os critérios já ativos. Ao desativá-lo, a tabela restaura os critérios anteriores sem perder o contexto do operador.
- Aplicar ou limpar o formulário de filtros avançados encerra o estado visual do filtro rápido para evitar dois controles aparentarem governar critérios divergentes.
- A composição adaptativa é responsabilidade do runtime: identidade, escopo, consulta e comandos se reorganizam pela largura do container da tabela. Dentro da consulta, campos editáveis formam a região de critérios; tags/atalhos salvos e comandos de gerenciamento formam um único cluster auxiliar. Em largura intermediária, os critérios e esse cluster completo compartilham o mesmo fluxo de quebra para aproveitar a faixa final sem criar uma linha órfã; em largura estreita, o cluster migra inteiro para a faixa seguinte. O host não precisa declarar coordenadas, breakpoints ou ordem visual adicional.
- Em superfícies de até `640px`, os campos de consulta absorvem o espaço residual da própria linha até o limite do arquétipo; em `320px`, entradas que não cabem em pares ocupam a largura útil integral. Presets e comandos curtos preservam largura intrínseca. Grupos binários de filtros rápidos equilibram as duas opções em até `540px`, enquanto grupos maiores mantêm largura por conteúdo e overflow acessível.
- `advancedFilters.settings.alwaysVisibleFields` deve conter apenas critérios frequentes. Atalhos persistidos e comandos de gerenciamento não devem ser simulados como campos sempre visíveis nem reposicionados por seletores CSS internos do host.
- Cada item de `tags[]` deve declarar `id`, `label` e `patch`; as chaves e os valores de `patch` devem corresponder ao `FilterDTO` canônico. Tags fornecidas pelo host são acionáveis, mas não podem ser renomeadas ou excluídas como atalhos persistidos pelo usuário. A aplicação imediata é emitida por `submit`.
- `config.toolbar.densityToggle.enabled` materializa o seletor de densidade. `values` pode restringir as opções entre `compact`, `comfortable` e `spacious`.
- A alteração de densidade atualiza `config.appearance.density` e emite `configChange`, permitindo ao host decidir se a preferência será apenas transitória ou persistida.

## Rich content convergence

- `mapTableRendererToRichContentP0(...)` e a ponte publica e restrita entre a taxonomia atual de cell renderers do `praxis-table` e o vocabulario compartilhado `1.0` de rich content em `@praxisui/core`.
- O subconjunto promovido nesta fase e intencionalmente pequeno: `icon`, `image`, `badge`, `chip -> badge`, `avatar`, `progress` e `compose`.
- Renderers interativos como `button`, `toggle`, `menu`, `link`, `html` e `rating`, alem do shell de detail/expansion, continuam table-owned e fora do contrato compartilhado `1.0` ate promocao semantica explicita.

## Detail rich surfaces
- `actionBar` entra na mesma fronteira canônica de detail row para agrupar ações contextuais host-mediated.
- `actionBar` é host-mediated:
  - o host resolve visibilidade, disabled e dispatch
  - o conteúdo visual de cada botão continua em `PraxisRichContent`
- `timeline` entra na mesma fronteira canônica de detail row ao lado de `detailList` e `cardGrid`.
- `timeline` e host-mediated:
  - a colecao vem de `field` ou `items`
  - cada entrada usa `itemSchema` para mapear `title`, `subtitle`, `meta`, `icon` e `badge`
  - o host resolve dados e fallback, mas o rendering cronologico final fica no `PraxisRichContent`

- `behavior.expansion.detail.schemaContract.allowedNodes` inclui `detailList` e `cardGrid` como surfaces canônicas de detail row.
- `list` continua sendo lista simples e nao aceita subtree declarativa por item.
- `mediaBlock` tambem faz parte da fronteira canonica do detail row, como primitive compartilhada para avatar/imagem, headline, subtitle, meta e trailing leve.
- `detailList` e host-mediated:
  - a colecao vem de `field` ou `items`
  - cada item usa `itemSchema.nodes` com `RichBlockNode[]`
  - o contexto do item expõe `detailItem` e `detailIndex`, com aliases opcionais via `itemContext`
  - `itemActions` permanecem no host, mas o conteudo visual do botao usa `PraxisRichContent`
- `cardGrid` tambem e host-mediated:
  - o host resolve o shell do grid
  - cada card e convertido para `RichCardNode` e renderizado por `PraxisRichContent`
  - o conteudo dos cards e limitado a `RichPresenterNode | RichComposeNode`
- `mediaBlock` e primitive compartilhada:
  - a tabela nao cria renderer proprio; ela delega diretamente para `PraxisRichContent`
  - o shape e voltado a avatar/imagem, headline, subtitle, meta e trailing leve
- O contrato alvo do primeiro corte de colecao rica e:

```ts
type DetailListNode = {
  type: 'detailList';
  title?: string;
  field?: string;
  items?: unknown[];
  emptyText?: string;
  itemKeyField?: string;
  itemSchema: {
    layout?: 'stack' | 'row' | 'card-list';
    nodes: RichBlockNode[];
  };
  itemContext?: {
    itemAlias?: string;
    indexAlias?: string;
  };
  itemActions?: Array<{
    actionId: string;
    label: string;
    icon?: string;
    payloadExpr?: string;
    visibleWhen?: JsonLogicExpression | null;
    disabledWhen?: JsonLogicExpression | null;
  }>;
};
```

- O contrato alvo do segundo corte de cards densos e:

```ts
type CardGridNode = {
  type: 'cardGrid';
  title?: string;
  subtitle?: string;
  columns?: 1 | 2 | 3 | 4 | 'auto';
  minCardWidth?: number;
  cards: Array<{
    id?: string;
    title?: string;
    subtitle?: string;
    content: Array<RichPresenterNode | RichComposeNode>;
  }>;
};
```

- O contrato alvo do terceiro corte de topo rico e:

```ts
type MediaBlockNode = {
  type: 'mediaBlock';
  avatar?: RichAvatarNode;
  title?: RichTextNode;
  subtitle?: RichTextNode;
  meta?: RichComposeNode;
  trailing?: RichBlockNode[];
};
```

- O contrato alvo do quarto corte cronologico e:

```ts
type TimelineNode = {
  type: 'timeline';
  title?: string;
  field?: string;
  items?: unknown[];
  emptyText?: string;
  itemSchema?: {
    titleField?: string;
    subtitleField?: string;
    metaField?: string;
    iconField?: string;
    badgeField?: string;
  };
};
```

```ts
type ActionBarNode = {
  type: 'actionBar';
  title?: string;
  emptyText?: string;
  actions: Array<{
    actionId: string;
    label: string;
    icon?: string;
    payloadExpr?: string;
    visibleWhen?: JsonLogicExpression | null;
    disabledWhen?: JsonLogicExpression | null;
  }>;
};
```

## Support legend

- Active: suportado e observado no runtime atual.
- Partial: suporte parcial, com restricoes conhecidas.
- Declared-only: declarado em tipos/schema sem ligacao runtime confirmada.
- Schema-only: presente em schema/modelo sem confirmacao de execucao.
- Deprecated: mantido por compatibilidade legada com migracao prevista.

## Contract classification

### Canonical runtime paths (public contract)

| Path | Type | Required | Default | Status | Notes |
| --- | --- | --- | --- | --- | --- |
| `meta` | object | No | `{}` | Active | Metadados de versao/hash/contexto da configuracao. |
| `columns[]` | array | Yes | `[]` | Active | Definicao estrutural principal da tabela. |
| `behavior` | object | No | component-defaults | Active | Regras de paginação, sort, filter, selection, expansion, loading. |
| `behavior.loading.type` | `spinner \| skeleton \| progress` | No | `skeleton` | Active | Seleciona um dos três indicadores materializados pelo runtime. O valor legado `custom`, sem renderer local canônico, foi removido durante o beta. |
| `behavior.loading.position` | `overlay \| inline \| replace` | No | `replace` | Active | Controla se o indicador cobre, acompanha ou substitui a superfície de dados. |
| `behavior.loading.text` | string | No | `Carregando dados...` | Active | Mensagem acessível e visual apresentada durante a leitura. |
| `behavior.loading.delay` | number | No | `0` | Active | Adia apenas o indicador visual; estado, bloqueio e timeout começam com o request. |
| `behavior.loading.showForQuickOperations` | boolean | No | `false` | Active | Quando `true`, ignora o atraso visual e mostra o indicador imediatamente. |
| `behavior.loading.requestTimeoutMs` | number | No | `30000` | Active | Encerra requests de schema, coleção REST ou `analyticsProjection` que excedem o SLA e apresenta erro recuperável; `0` delega a política ao host. |
| `behavior.loading.allowCancel` | boolean | No | `true` | Active | Em schema, coleção REST e `analyticsProjection`, exibe cancelamento acessível, aborta o transporte por unsubscribe e preserva dados estáveis já renderizados. |
| `behavior.loading.skeleton.rows` | number | No | `3` | Active | Quantidade de linhas visuais, normalizada pelo runtime entre 1 e 12. |
| `behavior.loading.skeleton.animated` | boolean | No | `true` | Active | Controla a animação do skeleton. |
| `appearance` | object | No | component-defaults | Active | Densidade, responsividade, tokens e comportamento visual. |
| `toolbar` | object | No | component-defaults | Active | Ações globais, busca e controles de topo. |
| `actions` | object | No | component-defaults | Active | Ações por linha/lote e integrações de comando. |
| `messages` | object | No | component-defaults | Active | Textos de UX e feedbacks operacionais. |
| `data` | object | No | component-defaults | Partial | Configuração de integração de dados server/client. |
| `localization` | object | No | component-defaults | Partial | i18n/localização em campos e mensagens. |
| `accessibility` | object | No | component-defaults | Partial | A11y semântica e atalhos de interação. |
| `rowConditionalStyles[]` | array | No | `[]` | Partial | Estilos condicionais por linha. |
| `_rowStyleRulesState` | any | No | `undefined` | Partial | Estado serializado do editor (round-trip). |

### Supported legacy paths

Nenhum path legado suportado foi identificado nesta revisão baseada em evidência textual preservada.

### Canonical authoring envelope

```ts
type TableAuthoringDocument = {
  kind: 'praxis.table.editor';
  version: 1;
  config: TableConfig;
  bindings?: {
    resourcePath?: string | null;
    horizontalScroll?: 'auto' | 'wrap' | 'none';
  };
};
```

### Internal-only paths

| Path | Internal consumer | Runtime presence | Public support | Notes |
| --- | --- | --- | --- | --- |
| `__forceRemoteMode__` | reconciliacao de modo de dados | Yes | No | Flag interna para forcar modo remoto em cenarios de editor/runtime. |

### Experimental paths

| Path | Enablement (flag/guard) | Stability | Rollout notes | Notes |
| --- | --- | --- | --- | --- |
| `behavior.expansion.detail.source.resourcePath` | `resourceAllowList` + `schemaContract` + renderer contract | Partial | Guard rails ativos; requer evidência de host para produção | Fluxo com fail-closed quando contrato/allowlist falha. |
| `behavior.expansion.detail.source.hypermedia` | `_links.capabilities` + `schemaContract` + renderer contract | Partial | Usa discovery canônico do backend; fail-closed sem `rel="capabilities"` | Primeiro corte gera detail schema leve a partir do snapshot agregado. |

### Hypermedia detail semantics

- `behavior.expansion.detail.source.mode = "hypermedia"` começa sempre em `_links.capabilities`.
- `surfaces`, `actions` e `canonicalOperations` são lidos do `ResourceCapabilitySnapshot` retornado pelo backend.
- O primeiro corte monta um detail schema leve de resumo contextual; ele não embute execução inline de `surface.open` nem de workflow.
- O runtime faz prefetch por linha somente quando existe ao menos uma ação contextual configurada para projeção inline (`display="icons"|"buttons"`). Ações restritas ao menu preservam discovery sob demanda ao abrir o overflow; expansion `hypermedia` sem row actions continua resolvendo o contexto ao expandir a linha.
- `actions.collection.discovery.enabled=false` desliga somente a materialização automática de ações da coleção, incluindo create e workflows descobertos por HATEOAS/capabilities. Dados, schema, paginação, capabilities de leitura, ações explícitas da toolbar e ações por linha permanecem disponíveis. O default permanece habilitado quando o campo é omitido.
- `actions.row.discovery.enabled=false` desliga somente o enriquecimento automático de ações por linha. Use este modo para telas corporativas curadas, nas quais o host quer expor apenas `actions.row.actions[]` e evitar overflow/actions descobertas por HATEOAS/capabilities. O default permanece habilitado quando o campo é omitido.

## Overview

Este arquivo foi adaptado para o padrao canonico atual sem remover conteudo tecnico existente. O conteudo detalhado anterior foi preservado para manter rastreabilidade historica e reduzir perda de contexto.

## Public contract surface

### Top-level configuration blocks

| Block | Purpose | Required | Merge strategy | Notes |
| --- | --- | --- | --- | --- |
| `meta` | Identidade/versionamento da configuração | No | shallow-merge | Pode carregar `schemaId` e `serverHash` como snapshot persistido de reconciliação; o runtime usa estado transitório para verificação ativa de schema. |
| `columns[]` | Estrutura de colunas e renderers | Yes | replace-array | Nucleo funcional do runtime de tabela. |
| `behavior` | Regras operacionais (sort/filter/paginação/expansion) | No | deep-merge | Defaults internos aplicados por `ensureConfigDefaults()`. |
| `appearance` | Densidade, responsividade e tema | No | deep-merge | Inclui normalização de `horizontalScroll` e breakpoints. |
| `toolbar` | Ações e UX de topo | No | deep-merge | Integrado com editor e quick actions. |
| `actions` | Ações de linha/lote | No | deep-merge | Roteia para eventos `rowAction`, `bulkAction` e flows de delete. |
| `messages` | Mensagens de feedback/runtime | No | deep-merge | Fallback para mensagens padrão quando ausente. |
| `data` | Estratégia de integração de dados | No | deep-merge | Convivência de modo remoto e local com `data` input. |

### Nested configuration blocks

| Path | Type | Required | Default | Constraints | Notes |
| --- | --- | --- | --- | --- | --- |
| `behavior.pagination` | object | No | component-defaults | component-defined | Estratégia client/server e tamanho de página. |
| `behavior.filtering` | object | No | component-defaults | component-defined | Filtros simples/avançados e debounce. |
| `behavior.selection` | object | No | component-defaults | component-defined | Single/multiple, persistência e UX visual. |
| `behavior.expansion` | object | No | component-defaults | contract-version-aware | Contrato de detail row e políticas fail-closed/fallback. |
| `behavior.expansion.interaction.toggleIcon` | object | No | runtime-defaults | icon-name strings | Customiza ícones recolhido/expandido e `ariaLabelCollapsed`/`ariaLabelExpanded` do toggle sem alterar a lógica de expansão; usa o pipeline `[praxisIcon]` do host e preserva fallback legado para `ariaLabel`. |
| `behavior.expansion.interaction.motion` | object | No | runtime-defaults | preset-driven | Presets controlados (`none`, `subtle-slide`, `accordion`, `fade-scale`) com respeito a `prefers-reduced-motion`; `durationMs` aceita `0` para desabilitar motion temporal. |
| `appearance.responsive` | object | No | component-defaults | numeric-breakpoint | Breakpoint móvel inválido é normalizado para `768`. |
| `toolbar.actions[]` | array | No | `[]` | action-contract | Ações de toolbar com roteamento para `toolbarAction`/`bulkAction`. |
| `toolbar.appearance` | object | No | Material 3 fallback | token-contract | Governa preset, variante, densidade, forma, divisores e tokens públicos da toolbar sem alterar a semântica das ações. |
| `actions.collection.discovery.enabled` | boolean | No | `true` | collection-action-discovery | Controla se ações de coleção podem ser materializadas por HATEOAS/capabilities. Configure `false` em lookups/seletores para manter consulta remota e somente ações explicitamente declaradas. |
| `actions.row.actions[].recordSurface` | object | No | none | `ResourceSurfaceCatalogItem` | Preserva a identidade canônica da superfície relacionada aberta por uma ação de linha, mantendo `actions.row.actions[].id` como identidade do botão. |
| `actions.row.discovery.enabled` | boolean | No | `true` | row-action-discovery | Controla se row actions podem ser enriquecidas por HATEOAS/capabilities. Configure `false` para manter somente ações declaradas em `actions.row.actions[]`. |
| `columns[].renderer` | object | No | field-type-driven | renderer-contract | Renderers condicionais, payload expr e ações interativas. |

Quando `actions.row.discovery.enabled` esta ativo e o item publica
capabilities CRUD canonicas, `PraxisTable` pode sintetizar entradas
contextuais `view`, `edit` e `delete`. Quando o backend publica
explicitamente `operations["duplicate-draft"]`, a tabela tambem materializa
`duplicate-draft` como operacao estendida de item. Essas entradas continuam
sendo capabilities, nao workflow actions. Em uma tabela standalone, `view`/`byId`
abre um Dynamic Form somente leitura por `surface.open`, usando a resolucao
canonica do GET de item e do schema de resposta. O host deve fornecer o runtime
de surfaces e autorizar essas leituras na sua politica de rede. Surfaces nomeadas
preservam seus proprios ids, paths e schemas. Dentro de um contexto CRUD, `view`
continua emitindo `rowAction` com `actionConfig` apontando para a capability;
as demais capabilities delegadas e actions globais explicitas preservam seu fluxo.
Injector e origem do foco acompanham apenas o contexto efemero de execucao,
nunca o JSON authorado ou o payload HTTP.

Renderer defaults:
- `columns[].renderer.type = "avatar"` aplica `columns[].align = "center"` quando a coluna não declara alinhamento explícito. Esse default governa header e célula para manter foto/avatar centralizados em colunas dedicadas, preservando `align`, `width` e demais overrides declarados pelo host.
- `columns[].renderer.type = "microVisualization"` renderiza a visualização compacta declarada em `renderer.microVisualization.visualization`. O caminho preferencial é metadata-driven: campos de schema com `presentation.presenter = "microVisualization"` e `presentation.visualization.surface = "table-cell"` são convertidos automaticamente para esse renderer quando o tipo é seguro para tabela. O contrato visual e a normalização pertencem a `@praxisui/core` (`PraxisPresentationVisualizationConfig`); a tabela apenas hospeda o HTML compacto em célula, compose item ou renderer condicional.

- Em `renderer.compose.items[]` com `type = "value"`, `emphasis = "strong"` representa o valor primário e `emphasis = "subtle"` o contexto de apoio. São os únicos níveis de hierarquia visual no item de texto; `style` arbitrário não integra o contrato de compose.

- Em tabela, campos `*Expr` da visualizacao, como `valueExpr`, `targetExpr`, `segmentsExpr`, `toneExpr` e `fallbackTextExpr`, sao resolvidos contra o contexto da linha antes de renderizar. Strings simples sao caminhos (`row.slaAtual`) e objetos seguem Json Logic. Para `kind = "comparison"`, use `points`/`pointsExpr`; `items` fica reservado para visualizacoes orientadas a itens/etapas.

### Toolbar contract

- Acoes globais de toolbar, row e bulk usam `effects[].kind = "global-action"` como envelope canonico de novo authoring.
  O campo `globalAction` plano continua aceito como fallback compatibilidade, mas nao e a superficie preferida.
- `payloadExpr` e escape avancado explicito de `GlobalActionRef`; visual authoring deve preferir `payload` estruturado e
  preservar `payloadExpr` existente apenas quando a mesma `actionId` for mantida.

- O bloco `toolbar` continua parte do contrato público principal.
- Use `toolbar.actions[]` para quick actions e `toolbar.search` para busca quando o host não injeta shell própria.
- Use `toolbar.appearance` para personalizar o chrome da toolbar por contrato governado. O runtime materializa `variant`, `density`, `shape`, `divider` e `tokens` como classes e CSS custom properties públicas; o host pode trocar aparência sem redefinir intenção, capability ou roteamento.
- Use `toolbar.appearance.preset = "table-integrated"` para compor toolbar e tabela como um unico bloco visual com tokens públicos estáveis, evitando CSS do host sobre classes internas como `praxis-toolbar-stack-top` ou `table-stack-top`.
- Tokens públicos suportados em `toolbar.appearance.tokens`: `bg`, `fg`, `borderColor`, `borderWidth`, `radius`, `shadow`, `paddingBlock`, `paddingInline`, `minHeight`, `gap`, `actionsGap`, `dividerColor`, `actionSize`, `actionRadius`, `actionBg`, `actionFg`, `actionHoverBg`, `actionActiveBg`, `actionFocusRing`, `aiAccentColor`, `statusFg`, `titleFg`, `subtitleFg`, `iconFg`, `titleFontSize`, `subtitleFontSize`, `titleFontWeight`, `identityGap`, `identityFilterGap`, `identityMinHeight`, `identityMarginBottom`, `identityIconSize` e `identityIconRadius`.
- Ações da toolbar e do estado vazio compartilham a geometria pública `--praxis-action-control-*`. `actionSize` e `actionRadius` continuam sendo overrides por tabela e têm precedência sobre os defaults compartilhados.
- Em coleções relacionadas graváveis, CREATE permanece estável na toolbar nos estados vazio e preenchido. O estado vazio gerado é informativo e não repete CREATE; `behavior.emptyState.actions` fica reservado a uma intenção contextual explícita e distinta, preservada exatamente quando declarada pelo host.
- Para localizar paths específicos de toolbar, complemente a leitura com o `Appendix: JSON path index`.

### Messages contract

- O bloco `messages` governa copy operacional, affordances de confirmação, labels de toolbar e feedbacks corporativos.
- Prefira `messages` para texto/public contract; reserve providers globais para políticas de tenant.
- Para busca rápida de paths e defaults parciais, complemente a leitura com o `Appendix: JSON path index`.

### Input bindings

| Binding/Path | Type | Required | Source | Runtime normalization | Notes |
| --- | --- | --- | --- | --- | --- |
| `config` | `TableConfig` | Yes (logical) | component-input | `ensureConfigDefaults` + guards | Contrato JSON principal da tabela. |
| `resourcePath` | `string` | Conditional | component-input | `crudService.configure(resourcePath)` | Fonte remota de dados/schema quando em modo remoto. |
| `data` | `any[] \| null` | No | component-input | `dataSource.data = data` | Ativa caminho de dados locais. |
| `tableId` | `string` | Yes | component-input | trim + component key builder | Necessário para persistência/configuração por instância. |
| `componentInstanceId` | `string \| undefined` | No | component-input | component key scoping | Isola preferências por instância em mesma rota. |
| `configPersistenceStrategy` | `'local-first' \| 'input-first' \| 'volatile'` | No | component-input | default `local-first` | Controla a hidratação de preferências persistidas. `volatile` renderiza apenas por inputs/runtime e não consulta nem grava `ASYNC_CONFIG_STORAGE`, útil para surfaces executivas efêmeras abertas por `surface.open`. |
| `title` | `string` | No | component-input | host-surface passthrough | Título opcional consumido por superfícies auxiliares, quick connect e contextos host. |
| `subtitle` | `string` | No | component-input | host-surface passthrough | Subtítulo opcional para contexto operacional do host. |
| `icon` | `string` | No | component-input | host-surface passthrough | Ícone opcional usado em affordances auxiliares do runtime. |
| `autoDelete` | `boolean` | No | component-input | boolean coercion | Ativa deleção automática quando o host delega esse fluxo ao runtime. |
| `enableCustomization` | `boolean` | No | component-input | boolean coercion | Controla entrada em editor/configuração; default canônico `false`. |
| `dense` | `boolean` | No | component-input | boolean coercion | Entrada legada de compactação. Equivale a `appearance.density="compact"` apenas quando o contrato não informa `appearance.density`. |
| `notifyIfOutdated` | `'inline' \| 'snackbar' \| 'both' \| 'none'` | No | component-input | enum validation + prefs fallback | Política de aviso de drift de schema; o host escolhe banner inline, snackbar, ambos ou silêncio explícito. |
| `snoozeMs` | `number` | No | component-input | numeric fallback + prefs fallback | Janela de snooze para avisos de drift; default do input é `86400000` (24h) e políticas globais podem complementar. |
| `autoOpenSettingsOnOutdated` | `boolean` | No | component-input | schema-prefs resolution | Abre automaticamente o settings panel quando drift de schema é detectado. |
| `crudContext` | `any` | No | component-input | host-context passthrough | Contexto opcional usado por flows compostos e integrações host/CRUD. |

Migration note:
- `enableCustomization=false` is now the canonical default.
- Hosts that need runtime authoring/settings must pass `enableCustomization=true` explicitly.

### Output events

`selectionChange` is an active output for Dynamic Page composition. It emits
`{ trigger, row?, selectedRows, selectedCount, tableId? }` when the user changes
row selection through table affordances.

When the table assistant is opened, selected rows are projected into a governed
`table-row-selection` runtime digest with `selectedCount`, `idField`,
`selectedIds` and a limited sanitized `sampleRows` array. This digest grounds
LLM answers or requested actions about the selected records, but it does not
route the user's primary intent and it is not a second source of business rules.

The assistant can also materialize declared runtime operations through
`tableRuntimeOperations`. This is a reviewed, table-owned operation envelope,
not a free-form component patch. Supported operations are:

| Operation | Input | Effect |
| --- | --- | --- |
| `table.filter.apply` | `{ criteria }` | Applies advanced filter criteria through the same runtime path used by the filter UI. `criteria` is currently a simple conjunction over declared filter fields; boolean composition such as OR, `anyOf`, `oneOf` or `allOf` is not part of this runtime contract yet. |
| `table.export.run` | `{ format, scope? }` | Runs the canonical Collection Export pipeline. `scope` may override the configured export scope for this runtime action only. |

Compound filter semantics should evolve through the canonical
`PraxisDataQueryContext.filterExpression` proposal in
`projects/praxis-core/docs/rfc-query-context-filter-expression.md`, not through
implicit OR payloads in `criteria`.

When `/schemas/filtered` publishes `x-ui.resource.capabilities`, the table
assistant includes a resource capability digest in its authoring contract.
`capabilities.filter=true` only declares the flat `/filter` DTO/simple
conjunction surface. `capabilities.filterExpression=false` tells the assistant
to clarify or explain OR/nested boolean requests instead of silently applying a
degraded filter.

| Event | Payload | Trigger | Stability | Notes |
| --- | --- | --- | --- | --- |
| `rowClick` | `{ row, index }` | Clique em linha. | Partial | Preservado da documentação anterior. |
| `rowDoubleClick` | `{ action, row }` | Duplo clique quando habilitado. | Partial | Preservado da documentação anterior. |
| `rowExpansionChange` | `RowExpansionChangeEvent` | Evento canônico para expand/collapse de detail row no runtime P0A (caminho não virtualizado), com payload discriminado por política de exposição (`allowRawExposure` + `eventExposureDefault`). | Partial | Preservado da documentação anterior. |
| `rowAction` | `{ action, row, payload?, actionConfig?, localMode?, preventedHttp? }` | Acao de linha (coluna `_actions`, renderer interativo ou CRUD capability sintetizada). `payload` e emitido quando houver `payloadExpr` em renderer interativo. Quando `actionConfig.globalAction` aponta para `navigation.openRoute`, o runtime resolve templates como `${row.id}` antes de executar a navegação interna. Para actions como `surface.open`, `payload.*` continua sendo o envelope canônico do evento entregue ao destino. Para capabilities delegadas ao host (`view` em CRUD, `edit/delete/duplicate-draft`), `actionConfig` carrega a operacao canonica. O `view`/`byId` standalone abre a leitura por `surface.open` e nao emite um segundo pedido local. | Partial | Preservado da documentação anterior. |
| `toolbarAction` | `{ action, actionConfig? }` | Acao clicada em `toolbar.actions[]` que nao foi roteada para fluxo bulk; `actionConfig` carrega o objeto da acao quando disponivel. A acao `create` de colecao pode ser materializada automaticamente a partir de `_links.create`, rel `capabilities`, surfaces e `CrudOperationResolutionService`. Dentro de CRUD, a tabela delega ao owner antes de abrir. Standalone, uma surface selecionada usa uma unica tentativa de `surface.open`; falha de execução é fail-closed e não emite `toolbarAction` como segundo caminho. O fallback local só permanece quando nenhuma surface executável foi selecionada. | Partial | Preservado da documentação anterior com materializacao CRUD de colecao e ownership explícito. |
| `exportAction` | `{ format, request?, result?, error?, tableId? }` | Acao de exportacao acionada pelo menu `export.formats[]`; `request` segue `PraxisCollectionExportRequest`. | Active | Usa o contrato canonico de Collection Export em `@praxisui/core`. |
| `exportAction` | `{ format, request?, result?, error?, tableId? }` | Acao de exportacao acionada pelo menu `export.formats[]`; `request` segue `PraxisCollectionExportRequest`. | Active | Usa o contrato canonico de Collection Export em `@praxisui/core`. |
| `bulkAction` | `{ action, rows, actionConfig? }` | Acao em lote; `actionConfig` carrega a configuracao da acao quando disponivel. | Partial | Preservado da documentação anterior. |
| `columnReorder` | `ColumnReorderEvent` | Reordenação de coluna concluída (drag/keyboard). | Partial | Inclui metadados de origem, destino e operação. |
| `columnReorderAttempt` | `ColumnReorderAttemptEvent` | Tentativa bloqueada por política de drop-zone. | Partial | Evento diagnóstico para observabilidade e auditoria. |
| `columnResize` | `{ action: 'columnResize', trigger: 'pointer' \| 'keyboard' \| 'auto-fit', tableId, field, header, previousWidth, currentWidth, persisted }` | Redimensionamento de coluna concluido pelo separador do header. | Partial | Usa `behavior.resizing.enabled`, respeita `columns[].resizable !== false` e persiste `columns[].width` em px quando `persistWidths !== false`. `autoFit !== false` habilita duplo clique para medir cabeçalho e células renderizadas. A largura interna nunca fica menor que o viewport; crescimento excedente usa scroll horizontal. |
| `beforeDelete` | `row` | Antes de delete de linha. | Partial | Preservado da documentação anterior. |
| `afterDelete` | `row` | Depois de delete com sucesso. | Partial | Preservado da documentação anterior. |
| `deleteError` | `{ row, error }` | Erro no delete de linha. | Partial | Preservado da documentação anterior. |
| `beforeBulkDelete` | `rows[]` | Antes de bulk delete. | Partial | Preservado da documentação anterior. |
| `afterBulkDelete` | `rows[]` | Depois de bulk delete com sucesso. | Partial | Preservado da documentação anterior. |
| `bulkDeleteError` | `{ rows, error }` | Erro em operação de delete em lote. | Partial | Preservado da documentação anterior. |
| `schemaStatusChange` | `{ outdated, serverHash?, lastVerifiedAt?, trigger?, tableId? }` | Verificação de versão de schema concluída. | Partial | Usado para notificação de drift entre runtime e servidor. |
| `configChange` | `TableConfig` | Configuração materializada pelo runtime/editor/assistente. | Active | Permite que o host sincronize mudanças feitas por authoring em tempo de execução. |
| `metadataChange` | `{ trigger, meta, tableId? }` | Metadados operacionais atualizados pelo runtime/editor. | Partial | Emite contexto de trigger e a carga corrente de `config.meta`. |
| `loadingStateChange` | `LoadingState` | Mudança de estado (`config/schema/data/render`), incluindo `loading`, `success`, `error` e `cancelled`. | Active | Unifica schema, coleção REST e `analyticsProjection`; timeout permanece `error` com causa preservada. |

### External side channels

| Channel | Direction | Contract | Failure mode | Notes |
| --- | --- | --- | --- | --- |
| `ASYNC_CONFIG_STORAGE` | bidirectional | `loadConfig/saveConfig/clearConfig` | fail-open | Persistência de config e inputs por `tableId`/instância; não é acessado quando `configPersistenceStrategy='volatile'`. |
| `CONNECTION_STORAGE` | bidirectional | `loadConnection/saveConnection` | fail-open | Persistência de `resourcePath` para quick-connect. |
| `SettingsPanelService` | bidirectional | `open(...).applied$/saved$` | fail-open | Canal de edição em runtime (quick connect/editor). |
| `PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER` | outbound call | Angular DI token (`TableDetailResourceResolver`) | fail-closed | Resolução externa e governada de detail schema por `resource`; o host deve fornecer o token por DI. |
| `AnalyticsTableStatsApiService.execute` | outbound call | `Observable<AnalyticsTableRow[]>` | fail-closed | A subscription é proprietária do transporte HTTP. `unsubscribe`, supersessão, timeout e destruição abortam o request em andamento; use `firstValueFrom(...)` apenas na borda de um consumidor que deliberadamente precise de Promise. |

`resourcePath` mantém precedência canônica sobre `analyticsProjection`: quando ambos estão presentes, o runtime cancela o transporte analítico e materializa somente a coleção REST.

### Host/runtime dependencies

| Dependency | Required | Environment | Purpose | Notes |
| --- | --- | --- | --- | --- |
| `GenericCrudService` | Yes | browser/dev/prod | data + schema I/O | Configura endpoint e executa `filter/getSchema`. |
| `TableDefaultsProvider` | Yes | browser/dev/prod/ssr | defaults canônicos | Base para merge inicial e fallback de configuração. |
| `SettingsPanelService` | Yes | browser/dev/prod | edição runtime | Abre editor e quick setup/quick connect. |
| `ASYNC_CONFIG_STORAGE` | Yes | browser/dev/prod | persistência | Guarda configurações por escopo de componente. |
| `CONNECTION_STORAGE` | Yes | browser/dev/prod | persistência de conexão | Mantém vínculo `tableId -> resourcePath`. |
| `LoadingOrchestrator` | Yes | browser/dev/prod/ssr | estado de loading | Coordena bloqueio/feedback por fase. |
| `PRAXIS_LOADING_RENDERER` | Optional | browser/dev/prod/ssr | renderer global de infraestrutura | É independente de `behavior.loading.type`: hoje a Table o usa no lifecycle de montagem, enquanto os indicadores de schema/coleção são materializados localmente. |

## Coverage matrix

| Surface | Verified | Coverage status | Evidence | Notes |
| --- | --- | --- | --- | --- |
| Runtime | true | Active | source_of_truth + conteudo preservado | Revisao estrutural concluida; validacao comportamental fina pode exigir follow-up. |
| Schema/Types | true | Partial | interfaces/modelos citados | Mapeamento formal de todos os campos ainda pode requerer refinamento. |
| Editor/Tooling | false | Partial | secoes de editor quando presentes | Cobertura de editor/tooling nem sempre confirmada por evidencia direta. |

## Runtime coverage boundaries

- Cobertura consolidada com base em documentacao existente e source of truth declarado.
- Comportamentos fora de evidencia direta foram marcados como not-yet-verified ou Partial.
- Compatibilidade legada, quando detectada, foi separada em classificacao explicita.

## Resolution model

### Merge order

1. defaults base (`createDefaultTableConfig` + `TableDefaultsProvider`)
2. contrato recebido em `@Input() config`
3. hidratação opcional de config persistida (`table-config:*`) e inputs persistidos (`table-inputs:*`)
4. ajustes de runtime (`ensureConfigDefaults`, guards de recursos não suportados, reconciliação de modo de dados)
5. alterações vindas de editor/settings panel (`applied$`/`saved$`)

### Fallback order

`resourcePath` explícito -> conexão persistida (`CONNECTION_STORAGE`) -> `data` local -> tabela sem fetch remoto.

### Override points

- `@Input() config`, `@Input() resourcePath`, `@Input() data`
- edição via `SettingsPanelService` (config editor, quick connect, quick setup)
- persistência de host (`ASYNC_CONFIG_STORAGE` e `CONNECTION_STORAGE`)

### Runtime normalization

- `ensureConfigDefaults()` preenche blocos ausentes sem sobrescrever intenção explícita do contrato.
- `parseLegacyOrTableDocument()` absorve payloads legados do editor e converte para o envelope canônico de autoria antes do apply plan.
- `sanitizeExpansionDetailSchema()` aplica contrato de nós permitidos e política de fallback.

### Precedence rules

- input explícito de runtime tem precedência sobre persistência local.
- paths canônicos têm precedência sobre aliases internos remanescentes (`__forceRemoteMode__`).
- em `behavior.expansion.detail`, contrato inválido aplica fail-closed para detail row.
- `behavior.expansion.detail.source.mode = "hypermedia"` usa `_links.capabilities` como ponto único de entrada e não executa `surface.open` inline no primeiro corte.

Observação adicional:
- no primeiro corte, `behavior.expansion.detail.source.mode = "hypermedia"` usa `_links.capabilities` como ponto único de entrada, consome `surfaces/actions/canonicalOperations` do snapshot agregado e não executa `surface.open` inline.

## Validation and error semantics

### Validation model

| Path/Rule | Validation phase | Behavior on fail | Error code / warning | Notes |
| --- | --- | --- | --- | --- |
| `tableId` para persistência | init/runtime | warn + disable persistence | `praxis-table:missing-table-id` | Tabela segue funcional sem persistir preferências. |
| `appearance.responsive.breakpoints.mobile` | runtime normalization | fallback para `768` | `praxis-table:responsive-breakpoint-mobile-invalid` | Comportamento fail-open com warning deduplicado. |
| `behavior.expansion.detail.schemaContract.kind/version` | runtime validation | fail-closed (sem render de detail) | `praxis-table:expansion:detail:schema-contract-kind-version-invalid` | Bloqueia detail schema inválido. |
| `behavior.expansion.detail.source.resourcePath` allowlist | runtime validation | fail-closed | `praxis-table:expansion:detail:resource-path-not-allowlisted` | Bloqueia path fora de allowlist/URL absoluta. |
| `behavior.expansion.detail.source.hypermedia` sem `_links.capabilities` | runtime validation | fail-closed | `praxis-table:expansion:detail:hypermedia-links-missing` | Bloqueia detail hypermedia quando o item não expõe affordance canônica. |
| `detail rendering contract` | runtime validation | fail-closed | `praxis-table:expansion:detail:rendering-invalid` | Exige estratégia/registry consistentes. |

### Error semantics

Warnings cobrem preferências inválidas e ausência de `tableId` para persistência. Falhas de contratos de detail schema aplicam bloqueio local (detail row) sem derrubar renderização base da tabela.

### Fail-open / fail-closed behavior

| Condition | Mode | Runtime behavior | Consumer impact |
| --- | --- | --- | --- |
| Configuração persistida indisponível | fail-open | ignora storage e usa defaults/inputs | componente continua operacional |
| `resourcePath` inválido para detail schema | fail-closed (escopo detail) | não expande detail row e registra warning/error | linha segue visível sem detalhe |
| Contrato `schemaContract` inválido | fail-closed (escopo detail) | bloqueia render de detail | evita execução de contrato não confiável |
| Campos opcionais desconhecidos no JSON | fail-open | ignorados ou mantidos sem efeito | baixo impacto, requer revisão de contrato |

### Invalid or unknown field handling

- Campos desconhecidos: comportamento depende da estrategia do componente (ignore, warn ou reject).
- Campos invalidos: podem gerar fallback, warning ou falha conforme implementacao.
- Registrar divergencias observadas em Known limitations and mismatches.

### Runtime warnings vs hard failures

| Condition | Severity | Observability | Consumer action |
| --- | --- | --- | --- |
| partial-or-declared-only-coverage | warning | logs/eventos do componente | confirmar ligacao runtime antes de uso critico |

## Detailed API

### Preserved technical reference (normalized from previous revision)

### Summary

Referencia canonica da API JSON do `praxis-table`.
- O componente consome `TableConfig` + inputs externos (`resourcePath`, `data`, `tableId`) e side-channels de integracao.
- Este documento cobre contrato, cobertura de runtime, precedencia, defaults, eventos e exemplos copiaveis.
- Fora de escopo: implementacao detalhada do host app, backend e UI de editores alem dos contratos que afetam runtime.

### Support legend

- **Active**
- **Partial**
- **Declared-only**
- **Schema-only**
- **Deprecated**

### Overview
`praxis-table` é uma superfície operacional para dados corporativos. Com uma
declaração pequena, a aplicação consegue exibir dados reais, paginação, colunas,
filtros, ações, mensagens e regras visuais sem reconstruir a tela a cada novo
cenário. A primeira renderização pode nascer do recurso publicado pelo backend;
os refinamentos podem vir da aplicação, do editor visual ou das preferências
persistidas.

Em arquiteturas tradicionais, cada variação de colunas, ações e filtros costuma
virar uma nova camada de HTML, estado e condicionais. Aqui, a estratégia é
inverter esse custo: a mudança entra em uma configuração governada. Quando o
requisito muda, a experiência evolui sem transformar cada ajuste em uma nova
implementação de tabela.

Conceitos-chave:

- Uma declaração publicada define estrutura, dados e experiência.
- O backend pode descrever o recurso para que a tabela derive a primeira leitura.
- Dados, apresentação e interação ficam separados, mas evoluem no mesmo contrato.
- Regras condicionais governam estilos, visibilidade e renderização sem espalhar decisões pelo template.
- Fluxos remotos ou locais preservam paginação, ordenação e filtros de forma previsível.

#### Por que este componente é diferente
O valor da Table aparece quando a tela deixa de ser um template isolado e passa
a ser uma superfície governada por contrato. Em tabelas convencionais, cada
mudança de coluna, filtro, ação ou visual pede código e template; aqui, essas
mudanças entram em uma configuração declarativa e o componente responde de forma consistente:

- A configuração da tabela governa visual, dados e regras sem espalhar decisões pelo template.
- Dados remotos e dados locais têm estratégias próprias, com impacto claro na experiência.
- O editor visual convive com a tabela renderizada para permitir autoria governada.
- Regras condicionais cobrem destaque visual, renderização e comportamento sem duplicar tela.
- Identidade estável permite persistir preferências e reconciliar instâncias com segurança.

O resultado é um componente "plataforma": cada bloco do contrato vira um módulo
do componente, e as interações entre esses módulos permitem evoluir experiências
corporativas sem transformar cada nova regra em uma nova implementação de tela.

#### Valor em uma leitura rápida
Uma tabela que vira plataforma. `praxis-table` transforma decisões declarativas
em experiência: colunas, ações, filtros, mensagens e regras vivem no mesmo
contrato operacional, pronto para dados remotos ou locais, sem retrabalho de
template.

- **Entrega rápida**: ajuste comportamento e visual por configuração governada.
- **Padrão de UX**: regras, ações e mensagens consistentes entre telas.
- **Escalável**: regras e comandos estruturados permitem crescer a complexidade sem criar forks de tela.

#### Menos código de tela, mais contrato
Uma tabela que vira plataforma. Em vez de programar cada capacidade de tabela
do zero, você ativa recursos nativos via contrato:

- **Iteração sem código de tela**: adicionar botões, trocar densidade, ajustar
  colunas, filtros e diálogos por configuração governada.
- **Lógica desacoplada**: destaque de linha, visibilidade de ação
  e variação visual ficam em regras condicionais, não em `*ngIf` espalhado.
- **Ecossistema embutido**: paginação remota, virtual scroll, reorder de colunas,
  exportação e `praxis-filter` avançado como capacidades prontas.
- **Eventos estruturados**: ações de linha, lote, toolbar, exportação e reordenação
  entregam intenções claras para a aplicação.
- **Governança de estado**: identidade estável organiza persistência,
  reconciliação e isolamento de instância.

#### Receitas de impacto
As receitas abaixo mostram capacidades que normalmente exigiriam código de tela,
mas que a Table materializa a partir do contrato. Elas funcionam como portas de
entrada para o leitor entender o valor antes de mergulhar na matriz completa da
API.

1. **Dashboard financeiro**: prova `computed` + densidade + regra visual.
2. **Micro-layout compose (CRM)**: prova poder de layout sem componente custom.
3. **Backoffice seguro**: prova bulk com travas de negócio e confirmação.
4. **Rastreador de SLA**: prova de regra temporal em JSON Logic + alerta visual declarativo.

**Receita 1 - Dashboard Financeiro**
```json
{
  "appearance": { "density": "compact" },
  "columns": [
    { "field": "asset", "header": "Ativo" },
    { "field": "costPrice", "header": "Custo", "type": "currency", "format": "BRL|symbol|2" },
    { "field": "salePrice", "header": "Venda", "type": "currency", "format": "BRL|symbol|2" },
    {
      "field": "margin",
      "header": "Margem",
      "type": "currency",
      "format": "BRL|symbol|2",
      "computed": { "expression": { "-": [{ "var": "salePrice" }, { "var": "costPrice" }] }, "outputType": "number" }
    }
  ],
  "rowConditionalStyles": [
    { "condition": { "<": [{ "var": "computed.margin" }, 0] }, "cssClass": "row--danger" }
  ]
}
```

**Receita 2 - Micro-layout sem scroll (compose)**
```json
{
  "columns": [
    {
      "field": "contact",
      "header": "Cliente",
      "renderer": {
        "type": "compose",
        "compose": {
          "layout": { "direction": "row", "gap": 8, "align": "center" },
          "items": [
            { "type": "avatar", "avatar": { "srcField": "photoUrl", "initialsField": "name" } },
            { "type": "value", "field": "name" },
            { "type": "badge", "badge": { "textField": "status", "variant": "soft" } }
          ]
        }
      }
    }
  ]
}
```

**Receita 3 - Backoffice Seguro (ações em lote)**
```json
{
  "actions": {
    "row": {
      "enabled": true,
      "actions": [
        {
          "id": "approve",
          "label": "Aprovar",
          "action": "approve",
          "visibleWhen": { "===": [{ "var": "status" }, "PENDENTE"] }
        }
      ]
    },
    "bulk": {
      "enabled": true,
      "position": "toolbar",
      "actions": [
        {
          "id": "delete",
          "label": "Excluir selecionados",
          "action": "delete",
          "minSelections": 1,
          "requiresConfirmation": true
        }
      ]
    }
  },
  "messages": {
    "actions": {
      "confirmations": {
        "deleteMultiple": "Tem certeza que deseja excluir os itens selecionados?"
      }
    }
  }
}
```

### Internal route global action

Configurações novas devem persistir a integração em `effects[].globalAction`. O runtime e os validadores também
leem `globalAction` plano para documentos existentes, mas editores e AI manifest devem tratar esse campo como
compatibilidade. O adapter da Table preserva `payload`/`payloadExpr` ao reabrir e re-selecionar a mesma `actionId`,
e limpa payloads ao trocar de global action para evitar semântica cruzada.

```json
{
  "actions": {
    "row": {
      "enabled": true,
      "actions": [
        {
          "id": "open-details",
          "label": "Abrir detalhe",
          "icon": "open_in_new",
          "globalAction": {
            "actionId": "navigation.openRoute",
            "payload": {
              "path": "/funcionarios/detalhe",
              "query": { "id": "${row.id}" },
              "state": { "source": "table", "selectedId": "${row.id}" }
            }
          }
        }
      ]
    }
  }
}
```

**Receita 4 - Rastreador de SLA (tempo + alerta visual)**
```json
{
  "columns": [
    {
      "field": "ageDays",
      "header": "Dias em aberto",
      "computed": { "expression": { "daysSince": [{ "var": "createdAt" }] }, "outputType": "number" }
    }
  ],
  "rowConditionalStyles": [
    {
      "condition": {
        "and": [
          { ">": [{ "var": "computed.ageDays" }, 5] },
          { "!==": [{ "var": "status" }, "RESOLVIDO"] }
        ]
      },
      "cssClass": "row--danger text-bold"
    }
  ],
  "rowConditionalRenderers": [
    {
      "condition": {
        "and": [
          { ">": [{ "var": "computed.ageDays" }, 5] },
          { "!==": [{ "var": "status" }, "RESOLVIDO"] }
        ]
      },
      "tooltip": { "text": "SLA violado: ação imediata necessária", "position": "top" },
      "animation": { "preset": "warning-attention", "repeat": 3 }
    }
  ]
}
```

Essas quatro receitas cobrem o primeiro impacto. Cenários mais longos, como
filtros avançados, logs massivos e overrides CRUD, pertencem à trilha de exemplos
completos para não diluir a tese principal do runtime.

#### Dominando a cauda longa das interfaces
Em sistemas corporativos e aplicações complexas, o esforço de engenharia
raramente está nos fluxos principais. O custo aparece na cauda longa dos
requisitos de UI: variações de regras condicionais, formatações específicas,
mensagens baseadas em estado e permissões de ação que mudam por linha, perfil
ou contexto operacional.

`praxis-table` foi desenhado para reduzir drasticamente esse custo de
manutenção. Em vez de espalhar condicionais pelo código da tela, o componente
move essas decisões para uma configuração governada. Quem define a experiência
ganha controle fino sobre leitura visual, ações, filtros e mensagens, com mais
autonomia para produto e menos acoplamento no frontend.

Impacto prático:

- Menos ramificação de código no frontend.
- Mais autonomia para evoluir UX por configuração.
- Menor risco de regressão ao escalar regras condicionais.

#### Mapa de contrato e superfícies
O contrato governa 6 áreas principais:

| Área | O que governa | Impacto na experiência |
| --- | --- | --- |
| Estrutura e leitura | Colunas, aparência, comportamento, mensagens e localização | Define densidade, textos, ordenação e comportamento base da tabela. |
| Dados e operação | Recurso remoto, dados locais, paginação, filtros e ordenação | Decide como a tabela busca, pagina, filtra e apresenta os registros. |
| Regras condicionais | Regras de destaque, visibilidade e variação visual | Transforma estado operacional em sinais visuais consistentes. |
| Ações e jornada | Toolbar, ações de linha, ações em lote, diálogos e exportação | Materializa comandos e confirmações sem duplicar fluxo em cada tela. |
| Integração externa | Identidade da instância, preferências e reconciliação | Preserva persistência e isolamento entre telas, usuários e contextos. |
| Eventos de saída | Intenções estruturadas do usuário | Entrega comandos claros para a aplicação executar navegação, auditoria e regra de negócio. |

A API detalha cada área e explicita onde o comportamento está ativo, parcial,
declarado ou dependente de schema.

#### Arquitetura orientada a contrato (como funciona)
O componente separa estritamente dados, apresentação e interação, operando em
dois eixos principais: motor interno da tabela e integrações externas.

Fluxo simplificado de execução:

1. **Interpretação da configuração**: resolve se a tabela usará dados remotos,
   dados locais ou estado vazio.
2. **Montagem da superfície**: renderiza colunas, toolbar, filtros e
   comportamentos visuais definidos pela configuração.
3. **Pipeline de dados + motor de regras**:
   - remoto: consulta a operação publicada pelo backend;
   - local: aplica paginação, ordenação e filtros no conjunto recebido;
   - regras: avalia destaque visual, visibilidade de ações e variações por linha.
4. **Ciclo de eventos**: emite ações estruturadas para que a aplicação reaja às
   intenções do usuário.

#### Integração com ecossistema Praxis (frontend e backend)
`praxis-table` compõe o ecossistema Praxis de ponta a ponta. O mapa de
integração cobre frontend, contratos e backend.

Frontend (UI):

| Componente | Papel na experiência | Como se conecta |
| --- | --- | --- |
| `praxis-table-toolbar` | Barra superior/inferior com ações, bulk e export | `toolbar`, `actions`, `export`, `behavior.filtering.*` |
| `praxis-filter` | Filtro avançado acoplado à toolbar | `behavior.filtering.advancedFilters.*`, `behavior.filtering.debounceTime`, `resourcePath` |
| `praxis-empty-state-card` | Estado inicial quando não há conexão remota | exibido quando não há `resourcePath` válido |
| `PraxisAiAssistantShellComponent` | Copiloto semântico opcional nos slots de toolbar | habilitado pelo runtime com turn orchestration e contexto seguro; ao minimizar, a sessão fica no registry com `presence: "origin-anchor"` e o affordance volta ao gatilho da tabela (não exposto no JSON) |
| Angular Material + CDK | Base de tabela, menus, seleção e virtual scroll | `behavior.pagination.*`, `behavior.selection.*`, `behavior.virtualization.*`, `appearance.spacing.*` |

Backend e contratos:

| Componente | Papel na experiência | Como se conecta |
| --- | --- | --- |
| `praxis-metadata-starter` | Publica OpenAPI + `x-ui` e o endpoint `GET /schemas/filtered` | A tabela deriva colunas, filtros e validações a partir do contrato |
| `praxis-api-quickstart` | Exemplo pronto com recursos, filtros e CRUD padronizados | Demonstra o fluxo completo com `resourcePath` apontando para a API |

No modo de edição, quando a aplicação habilita customização, a tabela exibe o
editor visual para ajustar colunas, comportamento, aparência e regras sem editar
código de tela. Esse editor compõe a configuração com consistência e evita
divergência entre o que o usuário authora e o que a tabela renderiza.

#### Checklist de integração (pre-flight)
Antes de plugar a tabela em uma aplicação, valide estes pontos:

- A instância tem identidade estável para persistir preferências sem colisão.
- O modo de dados está decidido: recurso remoto ou conjunto local informado pela aplicação.
- As colunas descrevem o conjunto de dados real e usam apresentação coerente.
- Ações de linha, lote e toolbar estão alinhadas com os comandos da aplicação.
- Regras condicionais têm fonte clara e não ficam espalhadas pelo template.
- Aparência, mensagens e localização foram revisadas para evitar inconsistências
  entre padrões globais e comportamento esperado.

### Top-level contract

O contrato principal e `TableConfig` (alias de `TableConfigV2`) com extensoes de runtime aceitas no JSON:
- Base tipada: `meta`, `columns`, `columnProjection`, `behavior`, `appearance`, `toolbar`, `actions`, `export`, `messages`, `localization`.
- Extensoes fora do tipo estrito: `dialogs.confirm.delete`, `rowConditionalRenderers[]`, aliases legados de `behavior.virtualScroll.*` e chaves legadas de header em `actions.row.*`.
- Artefatos auxiliares fora do `TableConfig`: `crud-overrides:<componentKeyId>` e o envelope autorado `TableAuthoringDocument`, que carrega `bindings.resourcePath` e `bindings.horizontalScroll`. A chave operacional da linha pertence ao `TableConfig` em `config.meta.idField`.

#### Projeção governada de colunas

Quando `columnProjection.source = "schema"`, a lista estrutural de colunas é
materializada a partir de `/schemas/filtered`; a página declara apenas diferenças
em `columnProjection.overrides`, indexadas pelo nome canônico do campo:

```json
{
  "columns": [],
  "columnProjection": {
    "source": "schema",
    "include": ["competencia", "salarioBruto", "salarioLiquido"],
    "overrides": {
      "salarioLiquido": {
        "sticky": "end",
        "width": "160px"
      }
    }
  }
}
```

O runtime reaplica os overrides após bootstrap e atualização do schema. Uma chave
desconhecida não cria coluna, e `field` não pode ser alterado pelo override. Este
contrato não cria “defaults da surface” paralelos: tipo, visibilidade, ordem e
apresentação continuam pertencendo ao schema canônico; a página conserva apenas
as decisões editoriais específicas da experiência.

Durante a renderização, `columns` contém a materialização completa somente em
memória. Ao salvar, aplicar ou emitir `configChange`, o runtime compacta essa
materialização novamente: a ordem e os campos canônicos formam `include`, as
diferenças formam `overrides` e colunas computadas/client-owned sem equivalente
no schema formam `additions`. Uma `addition` cujo `field` colida com o schema é
ignorada; ela não pode sombrear a identidade canônica.

`include` é uma allowlist ordenada. Em recursos financeiros, pessoais ou
regulados, ela deve ser preferida para impedir que um novo campo do schema passe
a integrar a experiência sem decisão editorial explícita. A ausência de
`include` significa “todos os campos que o backend marcou como visíveis”.

### Coverage matrix

Resumo de cobertura por bloco:

| Bloco | Leitura executiva | Referencia detalhada |
| --- | --- | --- |
| `TableConfig + extensoes` | Contrato canônico consumido pelo runtime | `### JSON coverage matrix (TableConfig + extras)` |
| Inputs/outputs do componente | API pública para host Angular | `### Component inputs` e `### Component outputs` |
| Caminhos JSON completos | Índice detalhado para escrita manual e validação | `## JSON path index` |

### Preserved source snapshot

| Source | Kind | Notes |
| --- | --- | --- |
| `projects/praxis-table/src/lib/praxis-table.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/praxis-table.html` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/praxis-table.scss` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/praxis-table-toolbar.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/praxis-table-config-editor.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/behavior-config-editor/behavior-config-editor.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/header-appearance-editor/header-appearance-editor.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/columns-config-editor/columns-config-editor.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/toolbar-actions-editor/toolbar-actions-editor.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/filter-settings/filter-settings.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/messages-localization-editor/messages-localization-editor.component.ts` | local-file | referencia preservada da versao anterior |
| `projects/praxis-table/src/lib/dialogs/confirm-dialog-appearance-editor.component.ts` | local-file | referencia preservada da versao anterior |

## Events

`selectionChange` is an active output for Dynamic Page composition. It emits
`{ trigger, row?, selectedRows, selectedCount, tableId? }` when the user changes
row selection through table affordances.

| Event | Payload | Trigger | Stability | Notes |
| --- | --- | --- | --- | --- |
| `rowClick` | `{ row, index }` | Clique em linha. | Partial | Preservado da documentação anterior. |
| `rowDoubleClick` | `{ action, row }` | Duplo clique quando habilitado. | Partial | Preservado da documentação anterior. |
| `rowExpansionChange` | `RowExpansionChangeEvent` | Evento canônico para expand/collapse de detail row no runtime P0A (caminho não virtualizado), com payload discriminado por política de exposição (`allowRawExposure` + `eventExposureDefault`). | Partial | Preservado da documentação anterior. |
| `rowAction` | `{ action, row, payload?, actionConfig?, localMode?, preventedHttp? }` | Acao de linha (coluna `_actions` ou renderer interativo). `payload` e emitido quando houver `payloadExpr` em renderer interativo. | Partial | Preservado da documentação anterior. |
| `toolbarAction` | `{ action, actionConfig? }` | Acao clicada em `toolbar.actions[]` que nao foi roteada para fluxo bulk; `actionConfig` carrega o objeto da acao quando disponivel. | Partial | Preservado da documentação anterior. |
| `bulkAction` | `{ action, rows, actionConfig? }` | Acao em lote; `actionConfig` carrega a configuracao da acao quando disponivel. | Partial | Preservado da documentação anterior. |
| `columnReorder` | `{ action, trigger: 'drag' \ | 'keyboard' \ | Partial | Preservado da documentação anterior. |
| `columnReorderAttempt` | `{ action: 'columnReorderAttempt', trigger: 'drag' \ | 'keyboard', operationId, tableId, sourceField, targetField, previousIndex, currentIndex, sourceZone, targetZone, result: 'blocked', reasonCode: 'drop-zone-policy-blocked', configuredColumnDropZones[] }` | Partial | Preservado da documentação anterior. |
| `columnResize` | `{ action: 'columnResize', trigger: 'pointer' \| 'keyboard' \| 'auto-fit', tableId, field, header, previousWidth, currentWidth, persisted }` | Separador de resize no header. | Partial | Mutacao visual/runtime de largura; nao redefine schema nem dados. A tabela ocupa ao menos o viewport, pode crescer com scroll horizontal e, com `autoFit !== false`, ajusta a coluna ao conteúdo renderizado por duplo clique. |
| `beforeDelete` | `row` | Antes de delete de linha. | Partial | Preservado da documentação anterior. |
| `afterDelete` | `row` | Depois de delete com sucesso. | Partial | Preservado da documentação anterior. |
| `deleteError` | `{ row, error }` | Erro no delete de linha. | Partial | Preservado da documentação anterior. |
| `beforeBulkDelete` | `rows[]` | Antes de bulk delete. | Partial | Preservado da documentação anterior. |

## Styling API

#### CSS vars principais
| CSS var | Efeito |
| --- | --- |
| `--p-table-header-bg` | fundo do header |
| `--p-table-header-fg` | cor de texto/icone do header |
| `--p-table-border-color` | cor de borda da tabela |
| `--p-table-row-even-bg` | zebra row |
| `--p-table-row-hover-bg` | hover row |
| `--p-table-row-selected-bg` | row selecionada |
| `--p-table-row-height` | altura da linha; sobrescreve o default do preset de densidade |
| `--p-table-header-height` | altura do header; sobrescreve o default do preset de densidade |
| `--p-table-column-resize-hit-area` | area clicavel do separador de resize |
| `--p-table-column-resize-separator-color` | cor base da divisoria de resize |
| `--p-table-column-resize-separator-hover-color` | cor da divisoria em hover/focus |
| `--p-table-column-resize-active-color` | cor da divisoria durante resize |
| `--p-header-padding` | padding do header |
| `--p-cell-padding` | padding das células; sobrescreve o default do preset de densidade |
| `--p-header-font-size` | fonte do header |
| `--p-header-font-weight` | peso do header |
| `--p-header-letter-spacing` | tracking do header |
| `--p-header-text-transform` | caixa do texto do header |
| `--p-table-reorder-transition-duration` | duracao da animacao de reorder das colunas |
| `--p-table-drag-preview-scale` | escala visual do preview durante drag |
| `--p-table-drag-preview-shadow` | sombra do preview durante drag |
| `--p-table-drag-status-enter-duration` | duracao da entrada da mensagem visual de reorder |
| `--p-actions-btn-size` | tamanho da superfície visível dos botões de ação; o alvo interativo permanece em 44px |
| `--p-actions-icon-size` | tamanho dos ícones de ação dentro da superfície canônica |
| `--p-table-paginator-container-min-height` | altura minima do paginator |
| `--p-table-paginator-container-padding` | padding do paginator |
| `--p-table-paginator-container-gap` | espaçamento entre controles do paginator |
| `--p-table-paginator-action-size` | tamanho dos botoes de navegacao do paginator |
| `--p-table-paginator-select-width` | largura do seletor de tamanho de pagina |
| `--p-table-paginator-select-height` | altura do seletor de tamanho de pagina |
| `--p-table-paginator-select-padding-inline` | padding horizontal do seletor de tamanho de pagina |
| `--p-table-state-success-*` | tokens de estado success |
| `--p-table-state-warning-*` | tokens de estado warning |
| `--p-table-state-danger-*` | tokens de estado danger |
| `--p-table-state-highlight-*` | tokens de estado highlight |

#### Host classes
| Classe no host | Efeito |
| --- | --- |
| `density-compact` | densidade compacta |
| `density-comfortable` | densidade padrao |
| `density-spacious` | densidade espacada |
| `row-borders` | bordas horizontais entre linhas |
| `col-borders` | bordas verticais entre colunas |
| `pfx-column-drag-enabled` | habilita layout base de DnD de colunas |
| `pfx-column-drag-indicator` | habilita indicador visual de drag |
| `pfx-column-resize-enabled` | habilita separadores de resize no header |
| `pfx-column-resizing` | estado ativo enquanto uma coluna esta sendo redimensionada |

`appearance.density` seleciona apenas o preset de defaults. `appearance.spacing.*` e defaults globais também alimentam tokens `*-default`. Hosts podem redefinir livremente os tokens finais sem depender de seletores internos, por exemplo `--p-table-row-height`, `--p-table-header-height`, `--p-cell-padding`, `--p-actions-btn-size` e `--p-table-paginator-select-height`. Em virtualização sem `itemHeight` explícito, o runtime deriva a altura da densidade efetiva.

#### DnD classes (globais)
| Classe CSS | Escopo | Efeito |
| --- | --- | --- |
| `pfx-column-drag-preview` | preview gerado pelo CDK (inserido globalmente) | card visual do header durante drag (gradiente, borda, sombra e escala leve) |

#### Horizontal scroll classes
A superficie usa `horizontalScroll` com classes:

- `scroll-auto`
- `scroll-wrap`
- `scroll-none`

Em `scroll-auto`, o viewport e uma regiao focalizavel por teclado para que o scroll horizontal continue acessivel sem mouse, inclusive no Safari. O nome acessivel usa `accessibility.ariaLabels.scrollViewport`, depois `toolbar.title` e, por fim, o fallback localizado do runtime. `scroll-wrap` e `scroll-none` nao introduzem uma parada de tabulacao adicional.

#### Mobile card mode
`appearance.responsive.mobile.cardMode: true` materializa cada linha **não virtualizada** como um card rotulado quando a menor largura entre o viewport e o host da tabela entra em `appearance.responsive.breakpoints.mobile`. Isso inclui widgets redimensionados e painéis estreitos em desktop. Um host ainda sem medida usa o viewport como referência. A tabela continua sendo a fonte semântica e todos os campos permanecem no DOM; cada valor recebe o respectivo cabeçalho como rótulo visual. Até 480 px de área interna, rótulo e valor ficam empilhados. Essa adaptação não altera a política de `horizontalScroll` nem ativa cartões sem `cardMode: true`.

`appearance.responsive.mobile.priorityColumns` é uma lista ordenada de `field`s que aparecem primeiro no card. Campos não prioritários continuam disponíveis abaixo deles; o runtime não oculta dados silenciosamente. Tabelas virtualizadas mantêm o modo de rolagem horizontal, pois um card pode ter altura variável.

#### Row/cell conditional styling
- `rowConditionalStyles` aplica classes/estilo por linha.
- `columns[].conditionalStyles` aplica por celula.
- Para intenções semânticas cobertas pelo catálogo oficial, use `surfacePresetRef`, por exemplo `{ "id": "warning", "catalogVersion": "0.2.0" }`. A versão `0.2.0` oferece `success`, `warning`, `danger` e `highlight` nos escopos de linha e célula.
- Fundo sólido determinístico sem `color` usa foreground acessível derivado no runtime; a cor derivada não é persistida no `TableConfig`.
- `color` explícito continua sendo intenção autorada e deve atingir contraste WCAG AA (`4.5:1`) contra o fundo sólido efetivo.
- O authoring bloqueia pares explícitos abaixo de AA. Para configuração legada ou manual que bypassou esse gate, o runtime substitui apenas o foreground renderizado por um fallback acessível e preserva o documento original para diagnóstico/correção governada.
- Hover e zebra não apagam uma superfície condicional. Seleção possui precedência explícita com seu próprio par `--p-table-row-selected-bg`/`--p-table-row-selected-fg`.
- Alpha, `var(...)`, `cssClass` externa, gradiente e shorthand não determinístico exigem preview contextual e não devem ser declarados acessíveis apenas por validação estrutural. O fundo contextual fica adiado no HTML inicial. Após o render, o runtime aplica fundo e foreground no mesmo frame e emite evidência DOM `derived-contextual` somente quando uma transparência ou variável CSS puder ser composta até uma base opaca e reduzida a uma única cor sólida. Gradientes, imagens e composições sem base opaca permanecem `unresolved-suppressed`, sem pintar o fundo inseguro.
- Em CSP estrito, estilos condicionais inline são desativados e o runtime não faz reparos via CSSOM. Apenas um `surfacePresetRef` válido é convertido na classe privada correspondente; `cssClass` arbitrária falha fechado. Os nomes dessas classes são detalhe interno e não fazem parte do contrato de authoring.
- A observação runtime publica `affordances.visualMaterialization.inlineStyle`, `governedClass` e `surfacePresetCatalog` (ID, versão, tema, modo, escopos e presets instalados), sem expor nonce ou a política CSP bruta. O backend usa essa evidência somente para restringir o preview: estilos inline exigem `inlineStyle=supported`; presets exigem instalação compatível comprovada. Capability ausente, `unknown`, versão/escopo/preset divergente ou modo de tema ainda não certificado falham fechado.
- `muted` não integra o catálogo acessível: opacidade aplicada à linha pode compor com descendentes e invalidar o contraste. O modo `high-contrast` é observado pelo runtime, mas permanece não aplicável pelo authoring até ter evidência visual certificada; o catálogo `0.2.0` está certificado para `light` e `dark`.
- Quando a cor comunicar estado ou classificação de negócio, materialize também uma pista visível independente de cor, como marcador lateral, ícone ou label.

### Examples

### Minimal valid

```json
{
  "appearance": { "density": "compact" },
  "columns": [
    { "field": "asset", "header": "Ativo" },
    { "field": "costPrice", "header": "Custo", "type": "currency", "format": "BRL|symbol|2" },
    { "field": "salePrice", "header": "Venda", "type": "currency", "format": "BRL|symbol|2" },
    {
      "field": "margin",
      "header": "Margem",
      "type": "currency",
      "format": "BRL|symbol|2",
      "computed": { "expression": { "-": [{ "var": "salePrice" }, { "var": "costPrice" }] }, "outputType": "number" }
    }
  ],
  "rowConditionalStyles": [
    { "condition": { "<": [{ "var": "computed.margin" }, 0] }, "cssClass": "row--danger" }
  ]
}
```

### Typical/common

```json
{
  "columns": [
    {
      "field": "contact",
      "header": "Cliente",
      "renderer": {
        "type": "compose",
        "compose": {
          "layout": { "direction": "row", "gap": 8, "align": "center" },
          "items": [
            { "type": "avatar", "avatar": { "srcField": "photoUrl", "initialsField": "name" } },
            { "type": "value", "field": "name" },
            { "type": "badge", "badge": { "textField": "status", "variant": "soft" } }
          ]
        }
      }
    }
  ]
}
```

### Advanced

```json
{
  "actions": {
    "row": {
      "enabled": true,
      "actions": [
        {
          "id": "approve",
          "label": "Aprovar",
          "action": "approve",
          "visibleWhen": { "===": [{ "var": "status" }, "PENDENTE"] }
        }
      ]
    },
    "bulk": {
      "enabled": true,
      "position": "toolbar",
      "actions": [
        {
          "id": "delete",
          "label": "Excluir selecionados",
          "action": "delete",
          "minSelections": 1,
          "requiresConfirmation": true
        }
      ]
    }
  },
  "messages": {
    "actions": {
      "confirmations": {
        "deleteMultiple": "Tem certeza que deseja excluir os itens selecionados?"
      }
    }
  }
}
```

### Enterprise scenario

```json
{
  "columns": [
    {
      "field": "ageDays",
      "header": "Dias em aberto",
      "computed": { "expression": { "daysSince": [{ "var": "createdAt" }] }, "outputType": "number" }
    }
  ],
  "rowConditionalStyles": [
    {
      "condition": {
        "and": [
          { ">": [{ "var": "computed.ageDays" }, 5] },
          { "!==": [{ "var": "status" }, "RESOLVIDO"] }
        ]
      },
      "cssClass": "row--danger text-bold"
    }
  ],
  "rowConditionalRenderers": [
    {
      "condition": {
        "and": [
          { ">": [{ "var": "computed.ageDays" }, 5] },
          { "!==": [{ "var": "status" }, "RESOLVIDO"] }
        ]
      },
      "tooltip": { "text": "SLA violado: acao imediata necessaria", "position": "top" },
      "animation": { "preset": "warning-attention", "repeat": 3 }
    }
  ]
}
```

## Known limitations and mismatches

| Path/Behavior | Observed behavior (runtime) | Desired behavior | Impact | Tracking issue | Target fix |
| --- | --- | --- | --- | --- | --- |
| coverage/mapping | Evidência textual preservada indica itens Partial/Declared-only. | Cobertura confirmada por evidência runtime + schema + editor. | Pode gerar uso de paths não totalmente ligados. | to-be-linked | next-doc-cycle |

## Compatibility and migration notes

- No corte beta que unificou o lifecycle operacional, consumidores que chamavam diretamente os helpers públicos do componente devem migrar `canCancelRemoteLoad()` para `canCancelLoad()` e `cancelRemoteLoad()` para `cancelLoad()`. Não há aliases paralelos.
- Paths e aliases legados continuam aceitos para compatibilidade (`behavior.virtualScroll.*`, chaves legadas de header em `actions.row.*`), mas novos contratos devem usar caminhos canonicos atuais.
- O side-channel de overrides CRUD (`crud-overrides:<componentKeyId>`) nao faz parte do `TableConfig`; mantenha migracao/backup dessa chave separado do payload principal.
- Para regex em regras, a forma canonica persistida e infixa (`field matches value`); `matches(field, value)` permanece como legado suportado.
- O editor manual de regras da tabela autora apenas JSON Logic.
- Se houver comportamento divergente entre schema e runtime, priorize as indicacoes desta pagina em `Known limitations and mismatches` e mantenha `has_known_mismatches=true` no frontmatter enquanto a lacuna existir.

### Source references
- `projects/praxis-table/src/lib/praxis-table.ts`
- `projects/praxis-table/src/lib/praxis-table.html`
- `projects/praxis-table/src/lib/praxis-table.scss`
- `projects/praxis-table/src/lib/praxis-table-toolbar.ts`
- `projects/praxis-table/src/lib/praxis-table-config-editor.ts`
- `projects/praxis-table/src/lib/behavior-config-editor/behavior-config-editor.component.ts`
- `projects/praxis-table/src/lib/header-appearance-editor/header-appearance-editor.component.ts`
- `projects/praxis-table/src/lib/columns-config-editor/columns-config-editor.component.ts`
- `projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts`
- `projects/praxis-table/src/lib/toolbar-actions-editor/toolbar-actions-editor.component.ts`
- `projects/praxis-table/src/lib/filter-settings/filter-settings.component.ts`
- `projects/praxis-table/src/lib/messages-localization-editor/messages-localization-editor.component.ts`
- `projects/praxis-table/src/lib/dialogs/confirm-dialog-appearance-editor.component.ts`
- `projects/praxis-table/src/lib/crud-integration-editor/crud-integration-editor.component.ts`
- `projects/praxis-core/src/lib/models/table-config-v2.model.ts`
- `projects/praxis-table/src/lib/utils/action-utils.ts`
- `projects/praxis-core/src/lib/tokens/global-action.catalog.ts`
- `projects/praxis-core/src/lib/models/global-action.model.ts`
- `projects/praxis-core/src/lib/actions/global-action-ui.ts`

## Appendix: JSON path index

| Path | Type | Required | Default | Status | Notes |
| --- | --- | --- | --- | --- | --- |
| `columns[]` | `TableColumnConfig[]` | Yes | `[]` | Active | Definicao de colunas, renderers e regras de exibicao. |
| `behavior` | `TableBehaviorConfig` | No | defaults do runtime | Partial | Inclui paginacao, filtro, selecao e expansao por blocos. |
| `toolbar.actions[]` | `ToolbarActionConfig[]` | No | `[]` | Partial | Acoes de toolbar com roteamento para `toolbarAction` e `bulkAction`. |
| `toolbar.title` | `string` | No | `undefined` | Active | Titulo renderizado na regiao de identidade da toolbar principal, antes de filtros e acoes. |
| `toolbar.subtitle` | `string` | No | `undefined` | Active | Texto auxiliar renderizado abaixo do titulo quando houver espaco. |
| `toolbar.icon` | `string` | No | `undefined` | Active | Icone semantico renderizado junto ao titulo da toolbar via `PraxisIconDirective`. |
| `toolbar.textAlign` | `'start' \| 'center' \| 'end'` | No | `'start'` | Active | Alinhamento textual do bloco de identidade da toolbar. |
| `toolbar.appearance` | `TableToolbarAppearanceConfig` | No | fallback M3 | Active | Chrome visual governado da toolbar; tokens viram `--p-table-toolbar-*` no runtime. |
| `toolbar.appearance.tokens.titleFg` | `string` | No | fallback M3 | Active | Cor do titulo na identidade da toolbar; use tokens semanticos do host para suportar tema claro/escuro. |
| `toolbar.appearance.tokens.subtitleFg` | `string` | No | fallback M3 | Active | Cor do subtitulo na identidade da toolbar. |
| `toolbar.appearance.tokens.iconFg` | `string` | No | fallback M3 | Active | Cor do icone da identidade; o fundo tonal e derivado dessa cor para manter contraste suave. |
| `toolbar.appearance.tokens.titleFontSize` | `string` | No | `14px` | Active | Tamanho tipografico do titulo da identidade. |
| `toolbar.appearance.tokens.subtitleFontSize` | `string` | No | `11.5px` | Active | Tamanho tipografico do subtitulo da identidade. |
| `toolbar.appearance.tokens.titleFontWeight` | `string` | No | `700` | Active | Peso tipografico do titulo da identidade. |
| `toolbar.appearance.tokens.identityGap` | `string` | No | `8px` | Active | Espaco entre icone e copy da identidade da toolbar. |
| `toolbar.appearance.tokens.identityFilterGap` | `string` | No | `8px` | Active | Respiro vertical entre identidade e filtros/controles quando a identidade ocupa linha propria. |
| `toolbar.appearance.tokens.identityMinHeight` | `string` | No | `30px` | Active | Altura minima do bloco de identidade da toolbar. |
| `toolbar.appearance.tokens.identityMarginBottom` | `string` | No | `2px` | Active | Espacamento inferior complementar da identidade da toolbar. |
| `toolbar.appearance.tokens.identityIconSize` | `string` | No | `28px` | Active | Tamanho do container do icone da identidade. |
| `toolbar.appearance.tokens.identityIconRadius` | `string` | No | `8px` | Active | Raio do container do icone da identidade. |
| `toolbar.columnsVisibility` | `object` | No | habilitado se a toolbar estiver ativa | Active | Controle rápido de visibilidade de colunas no toolbar (dropdown). |
| `toolbar.filters.quickFilters[]` | `ToolbarFilterConfig[]` | No | `[]` | Active | Seletor de escopo governado: no máximo um filtro rápido é combinado com os critérios ativos; acionar o item atual restaura os critérios anteriores. |
| `toolbar.densityToggle` | `object` | No | desabilitado | Active | Seletor governado de densidade com opções `compact`, `comfortable` e `spacious`. |
| `messages` | `TableMessagesConfig` | No | defaults internos | Partial | Overrides de i18n e mensagens operacionais. |
| `data` | `TableDataConfig` | No | modo local/remoto autodetectado | Partial | Integra origem local ou remota conforme `resourcePath`/inputs. |

## Appendix: Events summary

`selectionChange` emits `{ trigger, row?, selectedRows, selectedCount, tableId?, resourceIdentity? }`
for row selection changes initiated by the user and with `trigger: "data-reconcile"`
when a data update removes identities from the effective selection. Rehydrating the
same identities does not emit a new selection event.

Assistant turns can also receive the selected-row digest as context; textual
matching on row values must not decide primary intent.

| Event | Payload | Trigger | Stability |
| --- | --- | --- | --- |
| `rowClick` | `{ row, index }` | clique de linha no corpo da tabela | Partial |
| `rowAction` | `{ action, row, payload?, actionConfig? }` | acao interativa de linha (`_actions`/renderer); `navigation.openRoute` resolve templates de linha antes da execucao e `surface.open` preserva `payload.*` como envelope canonico do evento | Partial |
| `toolbarAction` | `{ action, actionConfig? }` | acao de toolbar fora de fluxo bulk | Partial |
| `exportAction` | `{ format, request?, result?, error?, tableId? }` | exportacao por `PraxisCollectionExportRequest` | Active |
| `bulkAction` | `{ action, rows, actionConfig? }` | acao em lote sobre linhas selecionadas | Partial |
| `loadingStateChange` | `LoadingState` | mudanca de estado (`config/schema/data/render`) | Active |

## Appendix: Styling API summary

| Token/Class | Scope | Purpose | Notes |
| --- | --- | --- | --- |
| `--p-table-header-bg` / `--p-table-header-fg` | css vars | aparencia de cabecalho e contraste | Tokens principais de tema para header. |
| `--p-table-row-*` | css vars | zebra, hover e estado selecionado de linha | Aplicados no runtime de render da tabela. |
| `density-compact` / `density-comfortable` / `density-spacious` | host classes | controle de densidade visual | Derivadas de `appearance.density`. |
| `.pfx-column-drag-enabled` | host class | habilita feedback visual de reordenacao | Ativada quando contrato de reorder esta habilitado. |
| `.pfx-column-drag-indicator` | host class | indicador visual durante drag/drop | Integrada ao runtime de `columnReorder`. |
| `.praxis-header-sort-trigger` | internal header zone | zona dedicada de sort no header | Recebe `mat-sort-header`; reorder por drag continua implicito no header cell. |

### Fallback global de aparencia

Quando o host salva `GlobalConfig.table.appearance`, a tabela usa esses valores como fallback corporativo para:

- `appearance.density`
- `appearance.spacing.cellPadding`
- `appearance.spacing.headerPadding`
- `appearance.typography.fontSize`
- `appearance.typography.headerFontSize`

Precedencia efetiva:

1. `TableConfig` local informado pelo host
2. `GlobalConfig.table.appearance`
3. defaults hardcoded de `createDefaultTableConfig()`

Campos fora de `table.appearance` mantem a semantica anterior de fallback do provider.

## Editor and tooling notes

- Cobertura de editor/tooling foi separada da cobertura de runtime para evitar confusao de suporte.
- Quando nao houver evidencia direta no codigo, o status deve permanecer not yet verified.

## Appendix: Examples summary

### Appendix minimal valid

```json
{
  "columns": []
}
```

### Appendix typical/common

```json
{
  "columns": [
    {
      "field": "name",
      "header": "Nome"
    }
  ],
  "behavior": {
    "pagination": {
      "enabled": true,
      "pageSize": 25
    }
  }
}
```

### Appendix advanced

```json
{
  "columns": [
    {
      "field": "status",
      "header": "Status",
      "renderer": {
        "type": "badge"
      }
    }
  ],
  "toolbar": {
    "actions": [
      {
        "id": "refresh",
        "label": "Atualizar"
      }
    ]
  },
  "behavior": {
    "selection": {
      "mode": "multiple"
    }
  }
}
```

### Appendix enterprise scenario

```json
{
  "columns": [],
  "messages": {
    "emptyState": "Nenhum registro encontrado."
  },
  "behavior": {
    "expansion": {
      "enabled": true
    }
  },
  "data": {
    "mode": "remote",
    "resourcePath": "customers/table"
  }
}
```

Nota: exemplos especificos do componente foram preservados na secao detalhada para evitar perda de cobertura durante esta migracao canonicamente orientada.

## Known limitations and mismatches

| Path/Behavior | Observed behavior (runtime) | Desired behavior | Impact | Tracking issue | Target fix |
| --- | --- | --- | --- | --- | --- |
| coverage/mapping | Documento anterior indica cobertura parcial ou declared-only. | Cobertura totalmente rastreada por superficie. | Pode haver diferenca entre schema e runtime/editor. | to-be-linked | next-doc-cycle |

## Compatibility and migration notes

| Concern | Affected versions | Migration action | Deadline | Notes |
| --- | --- | --- | --- | --- |
| legacy aliases and mixed status vocabulary | pre-canonical docs | unificar para taxonomia canonica (Active/Partial/Declared-only/...) | next-doc-cycle | manter backward compatibility documentada |

## Governed embeds

- `behavior.expansion.detail.schemaContract.allowedNodes` agora tambem pode incluir `formRef`, `tableRef`, `chartRef`, `templateRef` e `diagramEmbed`.
- Esses nodes continuam host-mediated:
  - o host resolve discovery, registry, abertura e policy
  - a tabela padroniza o shell, os metadados e a CTA do embed
  - o miolo visual continua delegado para `PraxisRichContent`
- `diagramEmbed` adiciona `provider`, `source` ou `sourceField` para preview governado de diagrama, sem abrir uma segunda DSL de detail row.

```ts
type DetailEmbedNode = {
  type: 'formRef' | 'tableRef' | 'chartRef' | 'templateRef';
  title?: string;
  subtitle?: string;
  description?: string;
  caption?: string;
  emptyText?: string;
  schemaId?: string;
  templateId?: string;
  inputs?: Record<string, unknown>;
  presetRef?: CorePresetRef;
  action?: {
    actionId: string;
    label: string;
    icon?: string;
    payloadExpr?: string;
    visibleWhen?: JsonLogicExpression | null;
    disabledWhen?: JsonLogicExpression | null;
  };
};

type DiagramEmbedNode = {
  type: 'diagramEmbed';
  title?: string;
  subtitle?: string;
  description?: string;
  caption?: string;
  emptyText?: string;
  provider: 'mermaid' | 'bpmn' | 'custom';
  source?: string;
  sourceField?: string;
  inputs?: Record<string, unknown>;
  presetRef?: CorePresetRef;
  action?: {
    actionId: string;
    label: string;
    icon?: string;
    payloadExpr?: string;
    visibleWhen?: JsonLogicExpression | null;
    disabledWhen?: JsonLogicExpression | null;
  };
};
```
