@praxisui/dynamic-fields 9.0.0-beta.8 → 9.0.0-beta.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/README.md +10 -2
  2. package/ai/component-registry.json +273462 -0
  3. package/docs/date-range-rust-host-integration.md +474 -0
  4. package/docs/dynamic-fields-field-catalog.md +3 -4
  5. package/docs/dynamic-fields-field-selection-guide.md +27 -3
  6. package/docs/dynamic-fields-inline-components-guide.md +30 -7
  7. package/docs/dynamic-fields-inline-filter-catalog.md +18 -1
  8. package/docs/dynamic-fields-inline-filter-runtime-contract.md +11 -0
  9. package/fesm2022/praxisui-dynamic-fields.mjs +2776 -983
  10. package/package.json +8 -4
  11. package/src/lib/base/pdx-base-input-runtime-contract.json-api.md +16 -0
  12. package/src/lib/components/field-shell/praxis-field-shell.json-api.md +33 -3
  13. package/src/lib/components/inline-date/pdx-inline-date.json-api.md +1 -1
  14. package/src/lib/components/inline-date-range/pdx-inline-date-range.json-api.md +30 -9
  15. package/src/lib/components/inline-entity-lookup/pdx-inline-entity-lookup.json-api.md +1 -0
  16. package/src/lib/components/inline-number/pdx-inline-number.json-api.md +1 -0
  17. package/src/lib/components/inline-rating/pdx-inline-rating.json-api.md +2 -0
  18. package/src/lib/components/inline-relative-period/pdx-inline-relative-period.json-api.md +2 -2
  19. package/src/lib/components/inline-time-range/pdx-inline-time-range.json-api.md +2 -2
  20. package/src/lib/components/material-async-select/pdx-material-async-select.json-api.md +13 -4
  21. package/src/lib/components/material-checkbox-group/pdx-material-checkbox-group.json-api.md +5 -3
  22. package/src/lib/components/material-date-range/pdx-material-date-range.json-api.md +20 -2
  23. package/src/lib/components/material-file-upload/pdx-material-file-upload.json-api.md +58 -27
  24. package/src/lib/components/material-searchable-select/pdx-material-searchable-select.json-api.md +10 -3
  25. package/src/lib/components/material-textarea/pdx-material-textarea.json-api.md +1 -1
  26. package/types/praxisui-dynamic-fields.d.ts +160 -11
@@ -0,0 +1,474 @@
1
+ ---
2
+ title: "Date Range Rust Host Integration"
3
+ slug: "date-range-rust-host-integration"
4
+ description: "Guia para hosts Rust publicarem atalhos corporativos de date range como metadata JSON resolvida, sem executar regras de negocio no frontend."
5
+ doc_type: "guide"
6
+ document_kind: "host-guide"
7
+ component: "dynamic-fields"
8
+ category: "integration"
9
+ audience:
10
+ - "backend"
11
+ - "host"
12
+ - "frontend"
13
+ - "architect"
14
+ level: "enterprise"
15
+ status: "active"
16
+ owner: "praxis-ui"
17
+ tags:
18
+ - "dynamic-fields"
19
+ - "date-range"
20
+ - "rust"
21
+ - "metadata"
22
+ - "business-periods"
23
+ order: 45
24
+ icon: "calendar_month"
25
+ toc: true
26
+ sidebar: true
27
+ search_boost: 1.2
28
+ reading_time: 24
29
+ estimated_setup_time: 35
30
+ version: "1.0"
31
+ related_docs:
32
+ - "pdx-material-date-range-json-api"
33
+ - "pdx-inline-date-range-json-api"
34
+ - "dynamic-fields-inline-filter-runtime-contract"
35
+ - "date-range-business-shortcuts-evolution-plan"
36
+ keywords:
37
+ - "StaticDateRangePreset"
38
+ - "serde"
39
+ - "inlineQuickPresets.position"
40
+ - "startDate"
41
+ - "endDate"
42
+ - "calculateRange"
43
+ last_updated: "2026-07-11"
44
+ ---
45
+
46
+ # Date Range Rust Host Integration
47
+
48
+ ## Objetivo
49
+
50
+ Orientar hosts Rust que publicam metadata Praxis para `pdx-material-date-range`
51
+ e `pdx-inline-date-range` com atalhos corporativos resolvidos pelo dominio.
52
+
53
+ O contrato de runtime Angular aceita built-ins, presets programaticos
54
+ TypeScript e presets estaticos serializaveis. Hosts Rust devem publicar apenas
55
+ os built-ins e os presets estaticos. Funcoes JavaScript como `calculateRange`
56
+ nao pertencem ao JSON publicado pelo backend.
57
+
58
+ ## Pre-requisitos
59
+
60
+ - Host Rust responsavel por publicar metadata Praxis para schema, recurso ou
61
+ endpoint equivalente.
62
+ - Dominio capaz de resolver periodos de negocio antes da serializacao JSON.
63
+ - Conhecimento do contrato `pdx-material-date-range` ou
64
+ `pdx-inline-date-range`.
65
+ - Pipeline de testes que consiga validar serializacao Rust e consumir a
66
+ metadata em uma superficie Praxis oficial.
67
+
68
+ ## Responsabilidades
69
+
70
+ | Camada | Responsabilidade |
71
+ | --- | --- |
72
+ | Rust/backend | Calcular regras eleitorais, legais, fiscais, contratuais, feriados, dias contaveis, autorizacao, confidencialidade e vigencia antes de publicar metadata. |
73
+ | Metadata publicada | Transportar somente intervalos resolvidos, labels, descricoes, icones semanticos, tons semanticos e configuracao de layout. |
74
+ | Angular/Praxis UI | Materializar o catalogo recebido, preservar constraints do campo, teclado, foco, RTL, tema e payload canonico. |
75
+ | Auditoria de negocio | Permanecer no backend/dominio; `shortcutId`/`id` pode apoiar observabilidade de UI, mas nunca substitui as datas. |
76
+
77
+ O frontend nao executa regras fiscais, eleitorais, juridicas ou de dias uteis
78
+ recebidas por JSON. Se a regra muda por calendario, jurisdicao, tenant,
79
+ permissao ou feriado, o Rust publica um novo intervalo ja resolvido.
80
+
81
+ ## Contrato JSON
82
+
83
+ ### Built-in
84
+
85
+ ```json
86
+ {
87
+ "controlType": "dateRange",
88
+ "shortcuts": ["today", "thisWeek", "thisMonth"]
89
+ }
90
+ ```
91
+
92
+ Built-ins sao identificadores conhecidos pelo runtime. Use-os apenas quando a
93
+ semantica relativa for aceitavel para o campo.
94
+
95
+ ### Preset estatico
96
+
97
+ ```json
98
+ {
99
+ "id": "periodo-votacao-2026",
100
+ "label": "Periodo de votacao 2026",
101
+ "description": "Janela oficial resolvida pelo dominio eleitoral.",
102
+ "startDate": "2026-07-06",
103
+ "endDate": "2026-10-04",
104
+ "timeZone": "America/Sao_Paulo",
105
+ "icon": "how_to_vote",
106
+ "tone": "info",
107
+ "effectiveFrom": "2026-06-01",
108
+ "effectiveTo": "2026-10-04"
109
+ }
110
+ ```
111
+
112
+ Campos suportados:
113
+
114
+ | Campo | Obrigatorio | Semantica |
115
+ | --- | --- | --- |
116
+ | `id` | Sim | Identificador estavel do atalho para estado ativo e observabilidade. |
117
+ | `label` | Sim | Texto publicado pelo dominio ou por i18n governado do host. |
118
+ | `startDate` | Sim | Inicio inclusivo do intervalo resolvido. |
119
+ | `endDate` | Sim | Fim inclusivo do intervalo resolvido. |
120
+ | `timeZone` | Nao | Timezone IANA usado pelo dominio ao resolver o periodo. |
121
+ | `icon` | Nao | Nome de icone semantico suportado pelo host/Praxis. |
122
+ | `description` | Nao | Explicacao operacional do periodo. |
123
+ | `tone` | Nao | `neutral`, `info`, `success` ou `warning`; nunca cor arbitraria. |
124
+ | `effectiveFrom` | Nao | Inicio da vigencia da metadata do atalho. |
125
+ | `effectiveTo` | Nao | Fim da vigencia da metadata do atalho. |
126
+
127
+ ### Lista mista e composicao inline
128
+
129
+ ```json
130
+ {
131
+ "controlType": "inlineDateRange",
132
+ "label": "Periodo",
133
+ "shortcuts": [
134
+ "today",
135
+ {
136
+ "id": "competencia-fiscal-2026-03",
137
+ "label": "Competencia fiscal 03/2026",
138
+ "description": "Periodo fiscal fechado pelo dominio tributario.",
139
+ "startDate": "2026-03-01",
140
+ "endDate": "2026-03-31",
141
+ "timeZone": "America/Sao_Paulo",
142
+ "icon": "account_balance",
143
+ "tone": "success"
144
+ }
145
+ ],
146
+ "inlineQuickPresets": {
147
+ "enabled": true,
148
+ "maxVisible": 4,
149
+ "position": "start"
150
+ },
151
+ "inlineOverlay": {
152
+ "applyMode": "explicit",
153
+ "actions": {
154
+ "apply": { "label": "Aplicar", "appearance": "filled", "colorRole": "primary" },
155
+ "cancel": { "label": "Cancelar", "appearance": "text", "colorRole": "neutral" }
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ `inlineQuickPresets.position` aceita:
162
+
163
+ | Valor | Uso |
164
+ | --- | --- |
165
+ | `footer` | Atalhos no rodape, antes de Cancelar/Aplicar. |
166
+ | `start` | Rail logica antes do calendario; esquerda em LTR e direita em RTL. |
167
+ | `end` | Rail logica depois do calendario; direita em LTR e esquerda em RTL. |
168
+ | `auto` | Runtime escolhe rail ou rodape conforme espaco, touch e viewport. |
169
+
170
+ Em viewport estreito, por exemplo 390 px, `auto`, `start` e `end` podem cair
171
+ para `footer` para preservar legibilidade, foco e ordem de tabulacao.
172
+
173
+ ## Datas, timezone e payload
174
+
175
+ Use `YYYY-MM-DD` para data civil quando o periodo e contado em dias. O runtime
176
+ trata date-only como data local civil e preserva a semantica de intervalo
177
+ inclusivo de inicio/fim.
178
+
179
+ Use datetime somente se o contrato do recurso exigir instantes com hora. Para
180
+ filtros de periodo civil, prefira date-only e deixe o backend traduzir para
181
+ limites de query conforme timezone, banco e regra do dominio.
182
+
183
+ O payload final do filtro continua canonico:
184
+
185
+ ```json
186
+ {
187
+ "startDate": "2026-03-01",
188
+ "endDate": "2026-03-31"
189
+ }
190
+ ```
191
+
192
+ O `id` do preset pode aparecer em estado interno, destaque visual ou telemetria
193
+ opcional. Ele nao substitui `startDate` e `endDate` no contrato de filtro.
194
+
195
+ ## Exemplo Rust reproduzivel
196
+
197
+ Dependencias sugeridas:
198
+
199
+ ```toml
200
+ [dependencies]
201
+ chrono = { version = "0.4", features = ["serde"] }
202
+ chrono-tz = "0.10"
203
+ serde = { version = "1", features = ["derive"] }
204
+ serde_json = "1"
205
+ thiserror = "2"
206
+ ```
207
+
208
+ DTOs serializaveis:
209
+
210
+ ```rust
211
+ use chrono::NaiveDate;
212
+ use chrono_tz::Tz;
213
+ use serde::Serialize;
214
+ use thiserror::Error;
215
+
216
+ #[derive(Debug, Clone, Serialize)]
217
+ #[serde(rename_all = "camelCase")]
218
+ pub struct StaticDateRangePresetDto {
219
+ pub id: String,
220
+ pub label: String,
221
+ pub start_date: String,
222
+ pub end_date: String,
223
+ #[serde(skip_serializing_if = "Option::is_none")]
224
+ pub time_zone: Option<String>,
225
+ #[serde(skip_serializing_if = "Option::is_none")]
226
+ pub icon: Option<String>,
227
+ #[serde(skip_serializing_if = "Option::is_none")]
228
+ pub description: Option<String>,
229
+ #[serde(skip_serializing_if = "Option::is_none")]
230
+ pub tone: Option<StaticDateRangePresetToneDto>,
231
+ #[serde(skip_serializing_if = "Option::is_none")]
232
+ pub effective_from: Option<String>,
233
+ #[serde(skip_serializing_if = "Option::is_none")]
234
+ pub effective_to: Option<String>,
235
+ }
236
+
237
+ #[derive(Debug, Clone, Serialize)]
238
+ #[serde(rename_all = "camelCase")]
239
+ pub enum StaticDateRangePresetToneDto {
240
+ Neutral,
241
+ Info,
242
+ Success,
243
+ Warning,
244
+ }
245
+
246
+ #[derive(Debug, Clone, Serialize)]
247
+ #[serde(untagged)]
248
+ pub enum DateRangeShortcutDto {
249
+ BuiltIn(String),
250
+ Static(StaticDateRangePresetDto),
251
+ }
252
+
253
+ #[derive(Debug, Clone, Serialize)]
254
+ #[serde(rename_all = "camelCase")]
255
+ pub struct InlineQuickPresetsDto {
256
+ pub enabled: bool,
257
+ pub max_visible: Option<u8>,
258
+ pub position: InlineQuickPresetsPositionDto,
259
+ }
260
+
261
+ #[derive(Debug, Clone, Serialize)]
262
+ #[serde(rename_all = "camelCase")]
263
+ pub enum InlineQuickPresetsPositionDto {
264
+ Auto,
265
+ Footer,
266
+ Start,
267
+ End,
268
+ }
269
+
270
+ #[derive(Debug, Clone, Serialize)]
271
+ #[serde(rename_all = "camelCase")]
272
+ pub struct DateRangeFieldMetadataDto {
273
+ pub control_type: String,
274
+ pub label: String,
275
+ pub shortcuts: Vec<DateRangeShortcutDto>,
276
+ pub inline_quick_presets: InlineQuickPresetsDto,
277
+ }
278
+
279
+ #[derive(Debug, Error)]
280
+ pub enum DateRangeMetadataError {
281
+ #[error("invalid date {value}; expected YYYY-MM-DD")]
282
+ InvalidDate { value: String },
283
+ #[error("startDate must be before or equal to endDate")]
284
+ InvertedInterval,
285
+ #[error("invalid IANA timezone {value}")]
286
+ InvalidTimeZone { value: String },
287
+ }
288
+
289
+ fn parse_date(value: &str) -> Result<NaiveDate, DateRangeMetadataError> {
290
+ NaiveDate::parse_from_str(value, "%Y-%m-%d")
291
+ .map_err(|_| DateRangeMetadataError::InvalidDate { value: value.to_owned() })
292
+ }
293
+
294
+ pub fn validate_static_preset(
295
+ preset: &StaticDateRangePresetDto,
296
+ ) -> Result<(), DateRangeMetadataError> {
297
+ let start = parse_date(&preset.start_date)?;
298
+ let end = parse_date(&preset.end_date)?;
299
+ if start > end {
300
+ return Err(DateRangeMetadataError::InvertedInterval);
301
+ }
302
+ if let Some(zone) = &preset.time_zone {
303
+ zone.parse::<Tz>()
304
+ .map_err(|_| DateRangeMetadataError::InvalidTimeZone { value: zone.clone() })?;
305
+ }
306
+ Ok(())
307
+ }
308
+ ```
309
+
310
+ Periodo de negocio resolvido pelo backend:
311
+
312
+ ```rust
313
+ pub fn voting_period_metadata() -> Result<DateRangeFieldMetadataDto, DateRangeMetadataError> {
314
+ let voting_period = StaticDateRangePresetDto {
315
+ id: "periodo-votacao-2026".into(),
316
+ label: "Periodo de votacao 2026".into(),
317
+ description: Some("Janela oficial resolvida pelo dominio eleitoral.".into()),
318
+ start_date: "2026-07-06".into(),
319
+ end_date: "2026-10-04".into(),
320
+ time_zone: Some("America/Sao_Paulo".into()),
321
+ icon: Some("how_to_vote".into()),
322
+ tone: Some(StaticDateRangePresetToneDto::Info),
323
+ effective_from: Some("2026-06-01".into()),
324
+ effective_to: Some("2026-10-04".into()),
325
+ };
326
+
327
+ validate_static_preset(&voting_period)?;
328
+
329
+ Ok(DateRangeFieldMetadataDto {
330
+ control_type: "inlineDateRange".into(),
331
+ label: "Periodo".into(),
332
+ shortcuts: vec![
333
+ DateRangeShortcutDto::BuiltIn("today".into()),
334
+ DateRangeShortcutDto::Static(voting_period),
335
+ ],
336
+ inline_quick_presets: InlineQuickPresetsDto {
337
+ enabled: true,
338
+ max_visible: Some(4),
339
+ position: InlineQuickPresetsPositionDto::Auto,
340
+ },
341
+ })
342
+ }
343
+ ```
344
+
345
+ Teste de serializacao:
346
+
347
+ ```rust
348
+ #[test]
349
+ fn serializes_resolved_business_period_metadata() {
350
+ let metadata = voting_period_metadata().expect("valid metadata");
351
+ let json = serde_json::to_value(metadata).expect("serializable");
352
+
353
+ assert_eq!(json["controlType"], "inlineDateRange");
354
+ assert_eq!(json["shortcuts"][0], "today");
355
+ assert_eq!(json["shortcuts"][1]["id"], "periodo-votacao-2026");
356
+ assert_eq!(json["shortcuts"][1]["startDate"], "2026-07-06");
357
+ assert_eq!(json["shortcuts"][1]["endDate"], "2026-10-04");
358
+ assert!(json["shortcuts"][1].get("calculateRange").is_none());
359
+ }
360
+
361
+ #[test]
362
+ fn rejects_inverted_interval() {
363
+ let preset = StaticDateRangePresetDto {
364
+ id: "invalid".into(),
365
+ label: "Invalid".into(),
366
+ start_date: "2026-10-04".into(),
367
+ end_date: "2026-07-06".into(),
368
+ time_zone: Some("America/Sao_Paulo".into()),
369
+ icon: None,
370
+ description: None,
371
+ tone: None,
372
+ effective_from: None,
373
+ effective_to: None,
374
+ };
375
+
376
+ assert!(matches!(
377
+ validate_static_preset(&preset),
378
+ Err(DateRangeMetadataError::InvertedInterval)
379
+ ));
380
+ }
381
+
382
+ #[test]
383
+ fn rejects_invalid_timezone() {
384
+ let preset = StaticDateRangePresetDto {
385
+ id: "invalid-zone".into(),
386
+ label: "Invalid zone".into(),
387
+ start_date: "2026-07-06".into(),
388
+ end_date: "2026-10-04".into(),
389
+ time_zone: Some("America/Sao_Paulo/BRT".into()),
390
+ icon: None,
391
+ description: None,
392
+ tone: None,
393
+ effective_from: None,
394
+ effective_to: None,
395
+ };
396
+
397
+ assert!(matches!(
398
+ validate_static_preset(&preset),
399
+ Err(DateRangeMetadataError::InvalidTimeZone { .. })
400
+ ));
401
+ }
402
+ ```
403
+
404
+ ## Governanca e seguranca
405
+
406
+ - Decida permissao e confidencialidade antes de publicar metadata. Se revelar
407
+ a existencia do periodo ja for sensivel, omita o atalho.
408
+ - O contrato atual de preset estatico nao possui campo publico `disabled`.
409
+ Quando o usuario nao puder usar o periodo, prefira omitir. Publique um item
410
+ indisponivel somente quando existir contrato governado para isso e quando a
411
+ propria existencia do periodo puder ser exibida.
412
+ - Registre no backend a origem do periodo resolvido: calendario, norma,
413
+ tenant, versao de regra, usuario/role e instante de publicacao.
414
+ - Quando a metadata expirar, publique novo snapshot ou remova o atalho. Nao
415
+ conte com o frontend para recalcular vigencia.
416
+ - `tone` e semantico. Use tokens Praxis/host no frontend; nao envie cores
417
+ arbitrarias como parte do preset.
418
+ - `icon`, `label` e `description` devem vir de catalogo governado ou i18n do
419
+ host. Nao use labels como mecanismo primario de roteamento de intencao.
420
+ - Nunca envie callbacks, expressoes JavaScript, snippets, URLs executaveis ou
421
+ `calculateRange` em JSON. Rust publica dados, nao codigo.
422
+
423
+ ## Operacao e testes
424
+
425
+ Contrato minimo entre backend e frontend:
426
+
427
+ 1. backend publica `shortcuts` como lista ordenada de built-ins e presets
428
+ estaticos;
429
+ 2. backend valida datas, timezone, autorizacao, confidencialidade e vigencia;
430
+ 3. frontend materializa o catalogo e preserva `minDate`, `maxDate`,
431
+ `dateFilter`, ordem inicio/fim, RTL, teclado, foco e tema;
432
+ 4. submit/filtro envia `{ startDate, endDate }`.
433
+
434
+ Testes recomendados:
435
+
436
+ - teste Rust de serializacao com `serde_json`;
437
+ - teste Rust de rejeicao de datas invalidas, intervalos invertidos e timezone
438
+ invalido;
439
+ - spec Angular focal de `@praxisui/core` para normalizacao de presets;
440
+ - spec Angular focal de `@praxisui/dynamic-fields` para materializacao em
441
+ `pdx-material-date-range` e `pdx-inline-date-range`;
442
+ - E2E de consumidor na superficie oficial
443
+ `src/app/features/filter-demo/praxis-filter-e2e-inventory.component.ts`,
444
+ rota `http://localhost:4003/filter-demo-e2e-inventory`, cobrindo built-in,
445
+ periodo corporativo estatico, `footer`, `start`, `end`, fallback `auto`,
446
+ tema claro/escuro, desktop, 390 px, teclado, foco, Cancelar/Aplicar, payload
447
+ e RTL quando houver composicao lateral.
448
+
449
+ ## Checklist de publicacao
450
+
451
+ - [ ] O Rust calculou o periodo antes da serializacao.
452
+ - [ ] O JSON nao contem `calculateRange`, funcoes, snippets ou expressoes.
453
+ - [ ] Cada preset estatico tem `id`, `label`, `startDate` e `endDate`.
454
+ - [ ] Datas seguem `YYYY-MM-DD` quando representam periodo civil.
455
+ - [ ] `startDate <= endDate`.
456
+ - [ ] `timeZone`, quando presente, e IANA valido.
457
+ - [ ] Permissao e confidencialidade foram decididas antes de publicar.
458
+ - [ ] O payload observado no consumidor permanece `{ startDate, endDate }`.
459
+ - [ ] `inlineQuickPresets.position` foi validado em `footer`, `start`, `end`
460
+ ou `auto` conforme a superficie usada.
461
+
462
+ ## Criterio sobre skill dedicada
463
+
464
+ Esta documentacao nao cria uma skill nova. A evidencia atual mostra um contrato
465
+ publico estabilizado para atalhos estaticos, mas o fluxo Rust ainda e um guia
466
+ de integracao de host, nao uma rotina transversal repetida em multiplos hosts
467
+ Rust versionados no workspace.
468
+
469
+ Criar uma skill canonica somente quando houver evidencia concreta de repeticao:
470
+ mais de um host Rust publicando a mesma familia de metadata, erros recorrentes
471
+ de validacao/serializacao, manifestos em `praxis-codex-skills` atualizados e
472
+ sincronizacao oficial. A eventual skill deve orientar publicacao de metadata
473
+ resolvida pelo backend, sem duplicar a skill de Dynamic Fields nem mover regra
474
+ de negocio para Angular.
@@ -27,7 +27,6 @@ reading_time: 24
27
27
  estimated_setup_time: 30
28
28
  version: "1.0"
29
29
  related_docs:
30
- - "dynamic-fields-overview"
31
30
  - "dynamic-fields-inventory"
32
31
  - "dynamic-fields-field-selection-guide"
33
32
  - "dynamic-fields-host-custom-field-guide"
@@ -144,7 +143,7 @@ Use `stateInitialValues` apenas quando o valor do preset precisa continuar coere
144
143
  | -------------- | ----------------------------------------------- | ----------------------------- | ----------------------------------------------- | ----------------------- | ------------------------------------------------------- | -------------------------------------- |
145
144
  | Date input | <span id="dateinput"></span>`dateInput` | integracao com input nativo | quando o host precisa UX Material forte | `string \| Date` | `{ name: 'birthDate', controlType: 'dateInput' }` | `pdx-date-input.json-api.md` |
146
145
  | Date picker | <span id="date"></span>`date` | selecao de data no formulario | se o fluxo pede intervalo | `Date \| string` | `{ name: 'startDate', controlType: 'date' }` | `pdx-material-datepicker.json-api.md` |
147
- | Date range | <span id="daterange"></span>`dateRange` | intervalo de datas | data unica | `{ startDate,endDate }` | `{ name: 'period', controlType: 'dateRange' }` | `pdx-material-date-range.json-api.md` |
146
+ | Date range | <span id="daterange"></span>`dateRange` | intervalo de datas, incluindo periodos corporativos estaticos publicados por metadata | data unica | `{ startDate,endDate }` | `{ name: 'period', controlType: 'dateRange', shortcuts: ['today'] }` | `pdx-material-date-range.json-api.md` |
148
147
  | Datetime local | <span id="datetimelocal"></span>`dateTimeLocal` | data + hora local em um campo | quando o fluxo precisa seletor dedicado de hora | `string` | `{ name: 'appointment', controlType: 'dateTimeLocal' }` | `pdx-datetime-local-input.json-api.md` |
149
148
  | Month input | <span id="month"></span>`month` | mes/ano | datas completas | `string` | `{ name: 'competence', controlType: 'month' }` | `pdx-month-input.json-api.md` |
150
149
  | Time input | <span id="time"></span>`time` | hora simples | intervalo de horario | `string` | `{ name: 'startAt', controlType: 'time' }` | `pdx-time-input.json-api.md` |
@@ -180,7 +179,7 @@ Use `stateInitialValues` apenas quando o valor do preset precisa continuar coere
180
179
 
181
180
  | Field | controlType | Quando usar | Quando evitar | Valor esperado | Snippet | Detail doc |
182
181
  | ------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------- |
183
- | Checkbox | <span id="checkbox"></span>`checkbox` | booleano simples com `selectionMode: 'boolean'` ou multiplas escolhas com `selectionMode: 'multiple'` | contrato novo sem `selectionMode`; escolha unica | `boolean \| unknown[]` | `{ name: 'privacyConsent', controlType: 'checkbox', selectionMode: 'boolean' }` | `pdx-material-checkbox-group.json-api.md` |
182
+ | Checkbox | <span id="checkbox"></span>`checkbox` | booleano simples com `selectionMode: 'boolean'` ou múltiplas escolhas com `selectionMode: 'multiple'`; em migrações, flags `S`/`N` e `1`/`0` são normalizadas no modo booleano | contrato novo sem `selectionMode`; escolha única | `boolean \| unknown[]` | `{ name: 'privacyConsent', controlType: 'checkbox', selectionMode: 'boolean' }` | `pdx-material-checkbox-group.json-api.md` |
184
183
  | Radio group | <span id="radio"></span>`radio` | escolha unica explicita com `selectionMode: 'single'` | muitas opcoes/espaco restrito | `string \| number \| boolean` | `{ name: 'priority', controlType: 'radio', selectionMode: 'single' }` | `pdx-material-radio-group.json-api.md` |
185
184
  | Toggle | <span id="toggle"></span>`toggle` | booleano binario | multiplos estados | `boolean` | `{ name: 'active', controlType: 'toggle' }` | `pdx-material-slide-toggle.json-api.md` |
186
185
  | Button toggle | <span id="buttontoggle"></span>`buttonToggle` | escolha segmentada curta | listas longas | `string \| number` | `{ name: 'mode', controlType: 'buttonToggle' }` | `pdx-material-button-toggle.json-api.md` |
@@ -189,7 +188,7 @@ Use `stateInitialValues` apenas quando o valor do preset precisa continuar coere
189
188
 
190
189
  | Field | controlType | Quando usar | Quando evitar | Valor esperado | Snippet | Detail doc |
191
190
  | ----------- | --------------------------------- | ------------------- | -------------------------------- | ---------------------------- | ----------------------------------------------- | -------------------------------------- |
192
- | File upload | <span id="upload"></span>`upload` | anexos e documentos | quando o fluxo nao exige arquivo | `File \| File[] \| metadata` | `{ name: 'attachment', controlType: 'upload' }` | `pdx-material-file-upload.json-api.md` |
191
+ | File upload | <span id="upload"></span>`upload` | anexos, documentos e escolha local de imagem com preview | quando o fluxo nao exige arquivo ou exige persistencia operacional completa sem `@praxisui/files-upload` | `File \| File[] \| metadata` | `{ name: 'attachment', controlType: 'upload', accept: 'image/*', imagePreview: true }` | `pdx-material-file-upload.json-api.md` |
193
192
 
194
193
  ## Cor
195
194
 
@@ -37,7 +37,7 @@ keywords:
37
37
  - "select vs autocomplete"
38
38
  - "custom host field"
39
39
  - "inline filter"
40
- last_updated: "2026-06-01"
40
+ last_updated: "2026-06-25"
41
41
  ---
42
42
 
43
43
  # Dynamic Fields Field Selection Guide
@@ -187,7 +187,29 @@ Se o caso e filtro corporativo compacto, consulte:
187
187
  - [Dynamic Fields Inline Filter Catalog](./dynamic-fields-inline-filter-catalog.md)
188
188
  - [Dynamic Fields Inline Components Guide](./dynamic-fields-inline-components-guide.md)
189
189
 
190
- ## 6. Decision table
190
+ ## 6. Presentation mode vs chart widget
191
+
192
+ `presentation.presenter = 'microVisualization'` nao e um `controlType`. Use esse presenter quando o campo ja tem valor no `FormControl`, mas a surface readonly precisa mostrar um indicador compacto e escaneavel.
193
+
194
+ Use `microVisualization` quando:
195
+
196
+ - a surface e `form-presentation`, `table-cell`, `list-item`, `object-header` ou `card-summary`;
197
+ - a leitura precisa caber em celula, linha, drawer ou detalhe compacto;
198
+ - o indicador e pequeno, como `comparison`, `stackedBar`, `bullet` ou `delta`;
199
+ - a mesma semantica deve ser dirigida por `presentationRules` e Json Logic sem mutar o valor do campo.
200
+
201
+ Use `@praxisui/charts` quando:
202
+
203
+ - o usuario precisa interagir com grafico, legenda, tooltip analitico ou drilldown;
204
+ - o grafico ocupa card, dashboard, cockpit ou modal dedicado;
205
+ - a visualizacao depende de series maiores, eixos, zoom ou agregacoes vindas de endpoint analitico.
206
+
207
+ Use `rich-content` quando:
208
+
209
+ - o bloco mistura timeline, record summary, property sheet, progresso, badges e textos;
210
+ - a surface de detalhe precisa composicao editorial, nao apenas um valor de campo.
211
+
212
+ ## 7. Decision table
191
213
 
192
214
  | Question | Prefer |
193
215
  | --- | --- |
@@ -211,12 +233,14 @@ Se o caso e filtro corporativo compacto, consulte:
211
233
  | ha uma colecao repetivel de objetos? | `array` |
212
234
  | ha anexos? | `upload` |
213
235
  | o controle e acao, nao dado? | `button` |
236
+ | o valor readonly precisa de indicador compacto em celula/lista/formulario? | `presentation.presenter = "microVisualization"` |
214
237
  | nada do catalogo resolve sem gambiarra? | field custom do host |
215
238
 
216
- ## 7. Enterprise recommendations
239
+ ## 8. Enterprise recommendations
217
240
 
218
241
  - prefira nomes canonicos de `controlType`; deixe aliases apenas para compatibilidade;
219
242
  - nao use inline filter controls em formularios normais para “economizar espaco”;
243
+ - nao crie `controlType` local para indicadores readonly; use `presentation.presenter` e `presentation.visualization` quando a semantica for de apresentacao;
220
244
  - para campos remotos, explicite origem de dados e comportamento de busca;
221
245
  - para entidades de negocio, use `entityLookup` com `optionSource.type = RESOURCE_ENTITY`, `byIds`, `dependsOn`, `dependencyFilterMap` e `selectionPolicy` quando a selecao depender de status, permissao ou contexto;
222
246
  - para colecoes repetiveis, use `array` com `array.itemSchema.fields` em vez de criar campos numerados como `item1`, `item2`, `item3`;