---
title: "Dynamic Fields Inline Filter Runtime Contract"
slug: "dynamic-fields-inline-filter-runtime-contract"
description: "Contrato runtime-first dos inline filters, cobrindo schema, promocao no praxis-filter, shape de valor, ranges e alinhamento com backend."
doc_type: "reference"
document_kind: "host-guide"
component: "dynamic-fields"
category: "integration"
audience:
  - "frontend"
  - "host"
  - "backend"
  - "architect"
level: "advanced"
status: "active"
owner: "praxis-ui"
tags:
  - "dynamic-fields"
  - "dynamic-filter"
  - "runtime"
  - "payload"
  - "contract"
order: 44
icon: "account_tree"
toc: true
sidebar: true
search_boost: 1.2
reading_time: 22
estimated_setup_time: 25
version: "1.0"
related_docs:
  - "dynamic-fields-inline-filter-inventory"
  - "dynamic-fields-inline-filter-catalog"
  - "dynamic-filter-payload-contract"
  - "dynamic-filter-range-filters-guide"
  - "dynamic-filter-backend-contract-cheatsheet"
keywords:
  - "controlType"
  - "inlinePhone"
  - "range payload"
  - "praxis-filter"
  - "metadata-starter"
last_updated: "2026-05-26"
---

# Dynamic Fields Inline Filter Runtime Contract

## Objetivo

Explicar como um inline filter component participa da pipeline completa:

- schema e metadata
- resolucao de `controlType`
- runtime do `praxis-filter`
- valor emitido pelo front
- integracao com backend

## Pre-requisitos

- Conhecimento basico de `PraxisFilter`, `GenericFilterDTO` e serializacao do host
- Leitura recomendada dos guias de payload e range da trilha de `table`

## Pipeline completa

1. schema define `controlType` e metadata do campo
2. `praxis-filter` decide se o campo vai para toolbar compacta
3. `praxis-filter` pode promover um control generico para variante inline
4. `DynamicFieldLoader` pede o componente ao `ComponentRegistryService`
5. componente inline produz o valor no `FormGroup`
6. `PraxisFilter` emite `change` e `submit`
7. host envia DTO ao backend
8. starter normaliza ranges quando aplicavel

```mermaid
sequenceDiagram
  participant Schema
  participant Filter as praxis-filter
  participant Loader as DynamicFieldLoader
  participant Inline as inline component
  participant Host
  participant Backend as metadata-starter

  Schema->>Filter: controlType and metadata
  Filter->>Loader: resolve inline variant
  Loader->>Inline: instantiate component
  Inline-->>Filter: form value
  Filter-->>Host: change / submit
  Host->>Backend: send DTO
  Backend-->>Host: normalize ranges and process payload
```

## Camada 1. `controlType` canonico

Para novos contratos, o canone e:

- `inline*`

Fonte de verdade:

- `projects/praxis-core/src/lib/utils/inline-filter-controls.util.ts`

## Camada 2. contrato publicado

O contrato publicado do runtime usa apenas `controlType` canônico `inline*`.

Regra:

- novos schemas persistem somente o nome canônico `inline*`
- documentacao, exemplos, testes e hosts devem usar apenas o nome canônico

## Camada 3. fallback quando o schema nao vem com inline explicito

O `PraxisFilter` consegue promover alguns controls genericos para inline.

Exemplos:

- `select` -> `inlineSelect`
- `phone`/`tel` -> `inlinePhone`; preserva `type="tel"`, mascara de telefone e valor cru em digitos quando a metadata carregar semantica telefonica
- `searchable-select` -> `inlineSearchableSelect` por padrao; use `useInlineSearchableSelectVariant = false` para opt-out
- `async-select` -> `inlineAsyncSelect` por padrao; use a mesma flag em `false` para opt-out
- `dateRange` -> `inlineDateRange` por padrao; use `useInlineDateRangeVariant = false` para opt-out
- `year + mode=range` -> `inlinePeriodRange` com `granularity: "year"` por padrao; use `controlType` explicito quando quiser garantir o comportamento
- `month + mode=range` -> `inlinePeriodRange` com `granularity: "month"` por padrao; use `controlType` explicito quando quiser garantir o comportamento

Conclusao importante:

- `dynamic-fields` publica todos os componentes
- `table` decide quando cada um entra na jornada do filtro

## Camada 4. shape do valor no front

### 4.1. commit de overlay inline

`inlineOverlay` é o contrato compartilhado para painéis inline que precisam separar rascunho visual de valor aplicado. O vocabulário público de `inlineOverlay.applyMode` é:

- `auto`: cada interação conclusiva aplica imediatamente o valor no `FormGroup`; `Esc` e clique externo apenas fecham o painel.
- `explicit`: alterações ficam em rascunho no painel; `Aplicar` comita o valor; `Cancelar`, `Esc` e fechamento externo restauram o valor confirmado anterior.

Não criar contratos locais como `confirm`, `commitPolicy` ou botões hardcoded por componente. Labels, `ariaLabel`, `appearance`, `colorRole`, ícones e visibilidade de ações pertencem a `inlineOverlay.actions.apply`, `inlineOverlay.actions.cancel` e `inlineOverlay.actions.clear`.

`Limpar` não é `Cancelar`: no trigger/pill é uma ação direta de remover o valor aplicado; dentro de um overlay `explicit`, deve limpar o rascunho e aguardar `Aplicar`, salvo contrato específico documentado pelo componente.

### Valores simples

- texto: `string`
- telefone inline: `string` com valor cru preservado, normalmente digitos; a mascara visual nao deve alterar o valor emitido
- numero/moeda: `number`
- toggle: `boolean | null`
- time: **canonico recomendado** `HH:mm`; o runtime tambem aceita `HH:mm:ss` e `Date`
- presets relativos: `string`

### Valores de selecao

- select simples: valor simples
- variantes remotas: valor simples ou option object, conforme metadata e source
- multiselect: array

### Valores de range

- range generico em modo simples: `number`
- range generico em `mode: "range"`: `{ start?, end? }`
- year range inline: `[startYear, endYear]` ou `{ start?, end? }`, mantendo valores numericos
- month range inline: `[startMonth, endMonth]` ou `{ start?, end? }`, com meses numericos de `1..12`
- currency range: `{ minPrice?, maxPrice?, currency? }`
- date range: `{ startDate?, endDate? }`
- time range: **canonico recomendado** `{ start?, end? }` com strings `HH:mm`; o runtime tambem aceita segundos e numeros em minutos para compatibilidade interna

## Normalizacao de range

O componente inline nao normaliza para o formato final do backend sozinho.

Ele apenas produz um shape coerente para o form.

Depois:

- o host envia o DTO
- `FilterRequestBodyAdvice` intercepta
- `RangePayloadNormalizer` canonicaliza quando preciso

Por isso:

- nao documente o valor interno do componente como se fosse o contrato HTTP final
- alinhe sempre com `dynamic-filter-range-filters-guide.md`
- para operacoes Java de range, payload escalar nao e contrato valido; use objeto/lista canonica publicada pelo backend

## Compatibilidade com backend

### O que precisa bater

- nome do campo do DTO
- tipo esperado pelo backend
- shape de ranges
- serializacao de data/hora

### O que nao vai para o backend

- `clearButton`
- `inlineAutoSize`
- `materialDesign.*`
- `tooltip`
- `aria*`

Esses campos sao de renderizacao.

### Politica de `materialDesign` em filtros

Filtros inline e filtros avancados frequentemente usam icones de prefixo,
sufixos funcionais, `clearButton`, datepicker toggle ou simbolos de unidade. Em
campos Material `fill`/`outline`, esses adornos podem conflitar com o label
quando `floatLabel` fica em `auto`.

A politica recomendada para metadata de filtro e:

```json
{
  "materialDesign": {
    "floatLabel": "always",
    "subscriptSizing": "dynamic"
  }
}
```

O `praxis-filter` aplica essa politica aos campos promovidos para a barra
compacta e ao `FormConfig` do formulario avancado. Hosts que fornecem metadata
propria ou overrides devem preservar essa regra globalmente na metadata de
filtro, especialmente quando o schema publica `prefixIcon`, `suffixIcon`,
`clearButton`, campos de data, moeda ou cor.

## Estados de interacao

Regra canonica da plataforma:

- `FormControl.disabled` continua sendo a fonte de verdade do estado `disabled` no DOM do controle nativo/Material
- `disabledMode` e `readonlyMode` bloqueiam interacao no `FieldShell`, sem obrigar o runtime a injetar `disabled` diretamente em componentes como `mat-select`
- `presentationMode` vence os dois estados acima e remove overlays de bloqueio

Implicacao pratica:

- nao use binding local de `[disabled]` como substituto para `disabledMode`
- componentes inline e nao-inline devem deixar o shell controlar bloqueio visual/interativo e deixar o `FormControl` controlar o estado semantico nativo

## Fallback quando o schema chega sem `controlType`

Nao existe fallback magico para inline especializado sem pista suficiente.

O que existe:

- promocao de controls genericos conhecida pelo `praxis-filter`
- defaults do editor/settings do filtro

Para specialized controls como:

- `inlineRating`
- `inlineDistanceRadius`
- `inlinePipelineStatus`
- `inlineRelativePeriod`
- `inlineSentiment`
- `inlineColorLabel`
- `inlinePeriodRange`
- `inlineYearRange` (alias compativel)
- `inlineMonthRange` (alias compativel)

use `controlType` explicito.

Regra adicional de produto/plataforma:

- `inlinePipelineStatus`, `inlineRelativePeriod`, `inlineRating`, `inlineDistanceRadius`,
  `inlineScorePriority`, `inlineSentiment` e `inlineColorLabel` pertencem a trilha `graphic specialized`
- esses componentes sao `opt-in` explicito
- eles nao devem ser inferidos ou promovidos automaticamente a partir de `select`, `enum`, `status` ou outros controles genericos

## Relacao com `metadata-starter`

`metadata-starter` nao conhece a UX do componente.
Ele conhece o DTO e a normalizacao de payload.

Portanto:

- `dynamic-fields` define como o controle funciona
- `table` define como ele entra na jornada do filtro
- `metadata-starter` define como o payload eh tratado no backend

## Exemplos curtos

### Select remoto inline

```json
{
  "name": "departmentId",
  "controlType": "inlineSearchableSelect",
  "resourcePath": "/departments/options",
  "optionLabelKey": "label",
  "optionValueKey": "id"
}
```

### Range monetario inline

```json
{
  "name": "salaryRange",
  "controlType": "inlineCurrencyRange",
  "currency": "BRL"
}
```

### Range numerico inline

```json
{
  "name": "scoreRange",
  "controlType": "inlineRange",
  "min": 0,
  "max": 100,
  "mode": "range"
}
```

Valor do form:

```json
{
  "scoreRange": {
    "start": 10,
    "end": 80
  }
}
```

Na trilha Java canonica, o backend publica `mode: "range"` para ranges numericos e canonicaliza esse objeto para a lista esperada pelo `GenericFilterDTO`.

### Faixa anual inline

```json
{
  "name": "anoBetween",
  "controlType": "inlinePeriodRange",
  "granularity": "year",
  "min": 2020,
  "max": 2026,
  "mode": "range"
}
```

### Faixa mensal inline

```json
{
  "name": "mesBetween",
  "controlType": "inlinePeriodRange",
  "granularity": "month",
  "mode": "range"
}
```

Valor do form:

```json
{
  "salaryRange": {
    "minPrice": 6500,
    "maxPrice": 15000,
    "currency": "BRL"
  }
}
```

### Periodo relativo

```json
{
  "name": "periodPreset",
  "controlType": "inlineRelativePeriod"
}
```

Valor do form:

```json
{
  "periodPreset": "last7"
}
```

Na trilha canonica com `praxis-metadata-starter`, esse preset e normalizado automaticamente antes da desserializacao do DTO para um dos contratos primitivos ja suportados pelo backend:

- `today` e `yesterday` -> `onDate`
- `last7` e `last30` -> `lastDays`
- `thisMonth`, `lastMonth`, `thisQuarter`, `thisYear` -> `between`

Timezone de referencia:

- por padrao, o starter usa `UTC`
- a API pode sobrescrever isso com `praxis.filter.relative-period.zone-id`

Se a API nao usa essa trilha canonica, o host/backend precisa fornecer semantica equivalente antes de tratar o valor como contrato HTTP final.

## Regras operacionais

1. Nao invente `controlType`.
2. Use sempre o `controlType` canônico `inline*`.
3. Distinga `shape canonico recomendado` de ajustes internos de runtime.
4. Nao trate valor do componente como contrato HTTP final sem passar pela trilha de `table`.
5. Se o filtro for de range, valide o shape no backend cheatsheet.
6. Se o controle depende de lista remota, valide `resourcePath`, auth e latencia como parte da feature.
