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

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-26T03:19:30.955Z",
4
4
  "packageName": "@praxisui/dynamic-fields",
5
- "packageVersion": "9.0.0-rc.3",
5
+ "packageVersion": "9.0.0-rc.4",
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;
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.4",
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.4",
15
+ "@praxisui/cron-builder": "^9.0.0-rc.4"
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;