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, unified filter region, and density

  • Região única de filtros e dono explícito da consulta: Em telas de coleção com praxis-table, a própria tabela é a dona canônica dos filtros editáveis pelo usuário. Quando um campo (ex.: ativo / status) é governado por config.toolbar.filters.quickFilters[], evite duplicá-lo em alwaysVisibleFields (mantenha-o apenas nos escopos rápidos e opcionalmente na gaveta avançada selectedFieldIds).
  • config.toolbar.filters.quickFilters[] materializa um seletor de escopo governado na toolbar. Cada item declara id, label, filter e icon opcional.
    • Um item com filter: {} representa o escopo "Todos" (sem restrição editável): acioná-lo limpa critérios editáveis anteriores em filterCriteria e em queryContext.filters não estruturais sem exigir reload da página.
    • Critérios booleanos explícitos false (ex.: { ativo: false }) são preservados integralmente na serialização remota e na avaliação local.
  • Reconciliação de atalhos externos (queryContext.filters) vs. filtros estruturais (queryContext.meta):
    • Quando cards de KPI ou widgets externos aplicam um filtro editável via queryContext.filters (ex.: { ativo: true }), a tabela sincroniza advancedFilterValue, activeCrossFilters e activeQuickFilterId correspondente.
    • Se o operador alterar o escopo rápido (onQuickFilterChange), submeter/limpar os filtros da tabela (onAdvancedFilterSubmit / onAdvancedFilterClear) ou remover chips (onClearCrossFilter / onClearAllCrossFilters), a tabela reconcilia as chaves editáveis em queryContext.filters e emite queryContextChange e queryContextClear, impedindo que queryContext.filters órfãos continuem sobrescrevendo filterCriteria.
    • Filtros estruturais de contexto (queryContext.meta.relatedResource === true + parentFilterField, queryContext.meta.structuralFields, queryContext.meta.immutableFields ou queryContext.meta.structural === true) permanecem protegidos e nunca são limpos por ações de filtro do usuário.
  • 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

  • richContent incorpora um documento canônico praxis.rich-content@1.0.0 no corpo do registro selecionado. Use-o para callout, cartões semânticos, ícones, hierarquia tipográfica e ações sem duplicar essa taxonomia dentro de Table.

  • O documento é validado integralmente antes do render. Cada actionId do conteúdo rico precisa existir em actions.row.actions[]; referências não declaradas ficam indisponíveis e não são despachadas. Ações declaradas são mediadas pelo host e seguem onRowAction; confirmação, capabilities e autorização continuam governadas pela Table e pelo backend.

  • O editor visual de Detalhes delega richContent.document ao PraxisRichContentConfigEditor, incluindo tons neutral|info|success|warning|danger, bindings como row.note, mídia e botões. Tokens semânticos são o caminho recomendado; gradientes são estilo avançado e exigem prova de contraste nos temas suportados.

  • 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.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:

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:
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:
type MediaBlockNode = {
  type: 'mediaBlock';
  avatar?: RichAvatarNode;
  title?: RichTextNode;
  subtitle?: RichTextNode;
  meta?: RichComposeNode;
  trailing?: RichBlockNode[];
};
  • O contrato alvo do quarto corte cronologico e:
type TimelineNode = {
  type: 'timeline';
  title?: string;
  field?: string;
  items?: unknown[];
  emptyText?: string;
  itemSchema?: {
    titleField?: string;
    subtitleField?: string;
    metaField?: string;
    iconField?: string;
    badgeField?: string;
  };
};
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

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.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.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.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.detail, contrato inválido aplica fail-closed para detail row.
  • behavior.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.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.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.detail.source.resourcePath policy canonical URL + same-origin pathname allowlist fail-closed praxis-table:expansion:detail:resource-path-policy-blocked:* Bloqueia URL absoluta, origem divergente, traversal/representações ambíguas, path efetivo fora da allowlist e redirects. Usa credenciais same-origin e EnterpriseRuntimeContextService.effectiveRequestHeaders(). A allowlist protege o documento; autorização GET/POST continua no backend. Hosts dependentes de interceptors Angular devem usar o resolver governado de source.mode=resource ou configurar os headers canônicos.
behavior.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

{
  "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)

{
  "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)

{
  "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.

{
  "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)

{
  "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 declaração explícita de columns é opcional. A lista estrutural de colunas é materializada em tempo de execução a partir de /schemas/filtered; a configuração declara apenas a seleção ordenada em columnProjection.include e as decisões editoriais pontuais em columnProjection.overrides, indexadas pelo nome canônico do campo:

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

Quando consumido dentro de <praxis-crud>, o contrato também auto-infere a schemaUrl de behavior.filtering.advancedFilters a partir de resource.schemaPath ou resource.path (normalizado para /schemas/filtered?path=/api/.../filter&operation=post&schemaType=request), eliminando URLs estáticas duplicadas nos arquivos de configuração.

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 fields 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

{
  "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

{
  "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

{
  "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

{
  "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

{
  "columns": []
}

Appendix typical/common

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

Appendix advanced

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

Appendix enterprise scenario

{
  "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

Contextual detail presentation

behavior.detail owns the shared schema, source, rendering, height and lazy-load configuration. presentation.placement selects row (the default) or bottom; presentation.initiallyCollapsed sets the initial disclosure state. For bottom presentation, presentation.bottomStackPosition selects afterControls (the default) or beforeControls, and presentation.emptyBehavior selects an instructional message (the default) or hide. A missing height defaults to dynamic sizing. height.mode accepts explicit dynamic or fixed; fixed mode requires a positive px. behavior.expansion owns row interaction only. Do not store detail inside expansion: the finite migration moves that branch and rejects differing old/new definitions. Runtime does not read the old path.

Bottom detail uses the existing selection model. Exactly one visible record with a stable identity may provide the body. Zero or multiple selections retain an explicit empty/status region; a retained selection outside the current page never reads a detail body. Refreshing the same ID refreshes its context. Selection never executes a business action.

Use detail.presentation.configure to choose bottom: it disables row expansion and enables single selection when selection is disabled, preserving an already enabled multiple-selection policy. Choosing row enables row expansion; disabling detail disables expansion. Conflicting hand-authored configurations fail closed. detail.configure and expansion.configure apply their declared activation semantics. detail.source.configure changes only the source; extension properties inside that source never act as presentation commands. Unknown extensions remain preserved, while malformed known groups, booleans and source modes block Apply. An existing dynamic height requires an explicit positive fixed-height adjustment before choosing bottom.

The Details section edits the authored tree and preserves field expressions, unknown nodes and provider references. Its local preview does not perform remote reads or persist sample values. Invalid advanced JSON blocks Apply/Save. Discard restores detail edits; global defaults retain their existing reset semantics.

The bottom body defaults to dynamic height with a small-viewport CSS limit. Fixed mode starts at 192px in the editor and provides vertical scrolling. It is outside the virtual viewport and defaults to after the footer controls, preserving the collection stack. Explicit collapse persists across selection changes. Inline charts require the Charts provider; unresolved references remain explained placeholders.

  • behavior.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.
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;
  };
};

Filter presentation

FilterPresentationConfig is owned by Core. Tables author it at behavior.filtering.advancedFilters.settings.presentation; standalone filters use FilterConfig.presentation, projected directly to the runtime presentation input. It changes presentation only, never the filter DTO or query semantics.

With filter persistence enabled, an acknowledged persisted FilterConfig.presentation overrides the authored input for the same component identity on reload. Apply remains a preview-only operation. Hosts that require input-only materialization set disablePersistence, which prevents preference loading and saving.

The guided preferences editor roundtrips the complete effective FilterConfig; changing presentation or another managed section preserves unmanaged siblings such as selectedFieldIds and field metadata overrides.

{
  "header": { "visible": true, "text": "Filtros", "position": "above", "size": "medium" },
  "advancedAction": { "display": "icon-text", "text": "Mais filtros", "icon": "filter_list", "size": "compact", "position": "end" }
}
Region Optional properties
header visible: boolean, text: string, icon: string, position: above | inline, size: small | medium | large
advancedAction display: icon | text | icon-text, text: string, icon: string, size: compact | standard, position: start | end
tokens String values for gap, headerGap, headerColor, headerFontSize, headerFontWeight, iconSize, actionGap, actionFontSize, actionFontWeight

Absent presentation preserves the existing icon action and hidden heading. header.visible explicitly enables the heading. An empty icon removes that icon. If the advanced action uses icon-only display with an empty icon, it falls back to its localized/authored text so the action remains discoverable. Text-only display never renders an icon. Nonempty authored text takes precedence over localized copy and the default catalog label. Empty or whitespace-only header/action text inherits the localized label, so it cannot create an unnamed action. Action position applies inside the auxiliary controls group, not the page. Existing showAdvancedButton controls whether the advanced action is available; presentation introduces no second visibility switch.

The embedded table supplies the heading, advanced-action label, dialog title and opening/unavailable feedback from the praxisTableRuntime catalog through the existing filter i18n input. Host locale changes and external translator overrides apply without modifying the filter query. Explicit presentation text still wins; clearing it restores catalog resolution. Standalone filters keep their explicit i18n input. Other legacy filter-manager copy is outside this localized projection.

Tokens project to CSS custom properties --pfx-filter-gap, --pfx-filter-header-gap, --pfx-filter-header-color, --pfx-filter-header-font-size, --pfx-filter-header-font-weight, --pfx-filter-icon-size, --pfx-filter-action-gap, --pfx-filter-action-font-size, and --pfx-filter-action-font-weight. Prefer the semantic size/position controls for ordinary authoring; tokens are for deliberate theme customization.

AI authoring extends existing operations: filter.advanced.configure receives settings.presentation for tables; filter.settings.configure receives presentation for standalone filters. Neither operation authors a query through this object. Corporate context changes use the existing EnterpriseRuntimeContextService: Table invalidates rows, selection, discovery and pending data/detail responses before a new remote load. Local hosts must replace data for the effective context and discard their own obsolete asynchronous deliveries. This is runtime state isolation, not backend authorization. initiallyCollapsed is reapplied after persisted hydration and configuration Apply.