@praxisui/dynamic-fields 9.0.0-rc.3 → 9.0.0-rc.5

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-07-25T01:22:20.531Z",
3
+ "generatedAt": "2026-07-26T09:12:02.628Z",
4
4
  "packageName": "@praxisui/dynamic-fields",
5
- "packageVersion": "9.0.0-rc.3",
5
+ "packageVersion": "9.0.0-rc.5",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 76,
@@ -149,6 +149,8 @@ Checklist minimo para promocao:
149
149
  - o recurso oferece busca paginada e reidratacao por ids (`filter` e `byIds`) para valores salvos;
150
150
  - `selectionPolicy` documenta status, elegibilidade e preservacao de valor historico quando aplicavel;
151
151
  - dependencias entre entidades usam `dependsOn` e `dependencyFilterMap`, sem inferencia por nome de campo no Angular;
152
+ - ao mudar uma dependencia canonica, o runtime limpa por padrao a selecao dependente, emite a alteracao para continuar a cascata e preserva apenas o valor hidratado na montagem inicial;
153
+ - use `selectionPolicy.allowRetainInvalidExistingValue=true` somente quando o dominio permitir manter explicitamente uma selecao historica fora do novo conjunto de opcoes;
152
154
  - surfaces de detalhe sao publicadas pelo recurso quando `navigateToDetail` estiver habilitado;
153
155
  - existe demo jogavel cobrindo campo de formulario e, quando o uso for filtro, `inlineEntityLookup`;
154
156
  - existe teste focal ou e2e cobrindo busca, selecao, reidratacao e estado bloqueado/historico;
@@ -4340,15 +4340,21 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
4340
4340
  const debounceMs = Number(meta.dependencyDebounceMs ?? this.global.getDynamicFields()?.cascade?.debounceMs ?? 150);
4341
4341
  const mergeStrategy = meta.dependencyMergeStrategy ?? 'merge';
4342
4342
  const loadOnChange = meta.dependencyLoadOnChange ?? this.global.getDynamicFields()?.cascade?.loadOnChange ?? 'respectLoadOn';
4343
+ let dependencySnapshotInitialized = false;
4343
4344
  // Subscribe to combined changes
4344
4345
  this.dependencySub = combineLatest(streams)
4345
4346
  .pipe(debounceTime(debounceMs))
4346
4347
  .subscribe((values) => {
4347
4348
  const availableControls = controls.filter((entry) => !!entry.control);
4348
4349
  const fragment = this.applyDependencyValues(meta, availableControls, values);
4349
- // Reset value when configured
4350
- if (meta.resetOnDependentChange) {
4351
- this.setValue(null, { emitEvent: false });
4350
+ const isInitialDependencySnapshot = !dependencySnapshotInitialized;
4351
+ dependencySnapshotInitialized = true;
4352
+ if (!isInitialDependencySnapshot &&
4353
+ this.shouldResetOnDependencyChange(meta) &&
4354
+ this.hasMeaningfulSelectValue(this.control().value)) {
4355
+ const emptyValue = this.multiple() ? [] : null;
4356
+ this.setValue(emptyValue, { emitEvent: true });
4357
+ this.control().markAsDirty();
4352
4358
  }
4353
4359
  // Trigger reload according to strategy
4354
4360
  if (!this.resourcePath())
@@ -4375,6 +4381,21 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
4375
4381
  });
4376
4382
  });
4377
4383
  }
4384
+ shouldResetOnDependencyChange(meta) {
4385
+ if (meta.resetOnDependentChange !== undefined) {
4386
+ return meta.resetOnDependentChange === true;
4387
+ }
4388
+ const hasCanonicalDependencies = Array.isArray(meta.optionSource?.dependsOn) &&
4389
+ meta.optionSource.dependsOn.length > 0;
4390
+ const retainsInvalidExistingValue = meta.optionSource?.selectionPolicy?.allowRetainInvalidExistingValue === true;
4391
+ return hasCanonicalDependencies && !retainsInvalidExistingValue;
4392
+ }
4393
+ hasMeaningfulSelectValue(value) {
4394
+ if (Array.isArray(value)) {
4395
+ return value.length > 0;
4396
+ }
4397
+ return value !== null && value !== undefined && value !== '';
4398
+ }
4378
4399
  extractDependencyValue(raw, path) {
4379
4400
  if (raw == null)
4380
4401
  return raw;
@@ -25336,6 +25357,20 @@ class MaterialCpfCnpjInputComponent extends SimpleBaseInputComponent {
25336
25357
  const formatted = this.formatValue(stringValue);
25337
25358
  super.writeValue(formatted);
25338
25359
  }
25360
+ applyNativeDisplayMask(value = this.control().value) {
25361
+ const input = this.nativeElement;
25362
+ if (!input || input.tagName.toLowerCase() !== 'input') {
25363
+ return;
25364
+ }
25365
+ const formatted = this.formatValue(typeof value === 'string'
25366
+ ? value
25367
+ : value == null
25368
+ ? null
25369
+ : String(value));
25370
+ if (input.value !== formatted) {
25371
+ input.value = formatted;
25372
+ }
25373
+ }
25339
25374
  handleInput(event) {
25340
25375
  const input = event.target;
25341
25376
  const value = input.value;
@@ -64029,6 +64064,7 @@ const DYNAMIC_FIELDS_PLAYGROUND_CATALOG = [
64029
64064
  metadataPatch: {
64030
64065
  documentType: 'cpf',
64031
64066
  version: 'legacy',
64067
+ validators: { cpfCnpj: true },
64032
64068
  },
64033
64069
  initialValue: '529.982.247-25',
64034
64070
  },
@@ -64039,6 +64075,7 @@ const DYNAMIC_FIELDS_PLAYGROUND_CATALOG = [
64039
64075
  metadataPatch: {
64040
64076
  documentType: 'cnpj',
64041
64077
  version: 'legacy',
64078
+ validators: { cpfCnpj: true },
64042
64079
  },
64043
64080
  initialValue: '11.444.777/0001-61',
64044
64081
  },
@@ -64049,6 +64086,7 @@ const DYNAMIC_FIELDS_PLAYGROUND_CATALOG = [
64049
64086
  metadataPatch: {
64050
64087
  documentType: 'cnpj',
64051
64088
  version: 'alpha',
64089
+ validators: { cpfCnpj: true },
64052
64090
  },
64053
64091
  initialValue: '12.ABC.345/01DE-35',
64054
64092
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/dynamic-fields",
3
- "version": "9.0.0-rc.3",
3
+ "version": "9.0.0-rc.5",
4
4
  "description": "Angular Material-based dynamic form fields for Praxis UI with lazy loading and metadata-driven rendering.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
@@ -11,8 +11,8 @@
11
11
  "@angular/platform-browser": "^21.0.0",
12
12
  "@angular/router": "^21.0.0",
13
13
  "rxjs": "^7.8.0",
14
- "@praxisui/core": "^9.0.0-rc.3",
15
- "@praxisui/cron-builder": "^9.0.0-rc.3"
14
+ "@praxisui/core": "^9.0.0-rc.5",
15
+ "@praxisui/cron-builder": "^9.0.0-rc.5"
16
16
  },
17
17
  "dependencies": {
18
18
  "libphonenumber-js": "^1.12.41",
@@ -416,6 +416,8 @@ Notas de runtime:
416
416
  - em `optionSource`, o filtro envia `includeIds` somente quando `optionSource.includeIds=true` e nao ha termo de busca ativo; quando ausente, `false` ou durante busca digitada, valores selecionados sao reidratados por `/option-sources/{sourceKey}/options/by-ids`.
417
417
  - durante busca digitada, a lista visivel usa apenas os itens da pagina remota filtrada. Opcoes reidratadas por ID preservam o display fechado, mas nao podem substituir ou inflar o resultado da busca.
418
418
  - em `optionSource`, dependencias declaradas por `dependsOn` e `dependencyFilterMap` sao materializadas como filtros estruturados `equals` no envelope canonico de opcoes.
419
+ - depois da montagem inicial, a mudanca de qualquer dependencia canonica limpa o valor selecionado e o texto exibido antes de recarregar as opcoes. A limpeza emite `valueChanges` para invalidar dependentes posteriores na mesma cadeia.
420
+ - `optionSource.selectionPolicy.allowRetainInvalidExistingValue=true` permite reter explicitamente um valor historico; `resetOnDependentChange=false` permanece como opt-out de compatibilidade para metadata legado.
419
421
  - `onSearch` limpa estado local e reinicia pagina para novo termo.
420
422
  - `loadMore` nao inicia a primeira carga remota; a primeira pagina respeita `loadOn`, abertura do painel, reload explicito ou mudanca de dependencia.
421
423
  - `loadMore` incrementa pagina somente quando ja existe pagina remota carregada e `endReached=false`.
@@ -1283,6 +1283,8 @@ declare abstract class SimpleBaseSelectComponent<T = any> extends SimpleBaseInpu
1283
1283
  private ensureCurrentValueLoaded;
1284
1284
  /** (Re)configure dependency observers based on metadata and current FormGroup */
1285
1285
  protected setupDependencies(): void;
1286
+ private shouldResetOnDependencyChange;
1287
+ private hasMeaningfulSelectValue;
1286
1288
  protected extractDependencyValue(raw: any, path?: string): any;
1287
1289
  protected applyDependencyCriteria(fragment: Record<string, any>, strategy?: 'merge' | 'replace'): void;
1288
1290
  protected onDependenciesChanged(): void;
@@ -2353,6 +2355,7 @@ declare class MaterialCpfCnpjInputComponent extends SimpleBaseInputComponent {
2353
2355
  private shouldApplySemanticDocumentValidator;
2354
2356
  isReadonlyEffective(): boolean;
2355
2357
  writeValue(value: unknown): void;
2358
+ protected applyNativeDisplayMask(value?: unknown): void;
2356
2359
  handleInput(event: Event): void;
2357
2360
  private cleanValue;
2358
2361
  private formatValue;