@ng-forge/dynamic-forms 0.10.0-next.4 → 1.0.0-rc.1

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 (36) hide show
  1. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-BfRH3TBm.mjs → ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs} +47 -26
  2. package/fesm2022/ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs.map +1 -0
  3. package/fesm2022/ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs +2347 -0
  4. package/fesm2022/ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs.map +1 -0
  5. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-bA-8ICHF.mjs → ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs} +22 -14
  6. package/fesm2022/ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs.map +1 -0
  7. package/fesm2022/{ng-forge-dynamic-forms-container-utils-BvXn8T_i.mjs → ng-forge-dynamic-forms-container-utils-BZFz6ztF.mjs} +3 -2
  8. package/fesm2022/ng-forge-dynamic-forms-container-utils-BZFz6ztF.mjs.map +1 -0
  9. package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-DjhcONFh.mjs → ng-forge-dynamic-forms-css-wrapper.component-AScQAJTQ.mjs} +8 -6
  10. package/fesm2022/ng-forge-dynamic-forms-css-wrapper.component-AScQAJTQ.mjs.map +1 -0
  11. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-D0_nmXf2.mjs → ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs} +42 -24
  12. package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs.map +1 -0
  13. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +116 -75
  14. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  15. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +16 -14
  16. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  17. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-CNc4a_Xv.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs} +492 -2691
  18. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs.map +1 -0
  19. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-BJRNnoz-.mjs → ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs} +26 -16
  20. package/fesm2022/ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs.map +1 -0
  21. package/fesm2022/{ng-forge-dynamic-forms-row-wrapper.component-CwkYn5yl.mjs → ng-forge-dynamic-forms-row-wrapper.component-BlVa801t.mjs} +6 -5
  22. package/fesm2022/ng-forge-dynamic-forms-row-wrapper.component-BlVa801t.mjs.map +1 -0
  23. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DABkT0O7.mjs → ng-forge-dynamic-forms-text-field.component-CNCpmf5_.mjs} +18 -11
  24. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DABkT0O7.mjs.map → ng-forge-dynamic-forms-text-field.component-CNCpmf5_.mjs.map} +1 -1
  25. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  26. package/package.json +4 -4
  27. package/types/ng-forge-dynamic-forms-internal.d.ts +2 -2
  28. package/types/ng-forge-dynamic-forms.d.ts +2 -1
  29. package/fesm2022/ng-forge-dynamic-forms-array-field.component-BfRH3TBm.mjs.map +0 -1
  30. package/fesm2022/ng-forge-dynamic-forms-container-field.component-bA-8ICHF.mjs.map +0 -1
  31. package/fesm2022/ng-forge-dynamic-forms-container-utils-BvXn8T_i.mjs.map +0 -1
  32. package/fesm2022/ng-forge-dynamic-forms-css-wrapper.component-DjhcONFh.mjs.map +0 -1
  33. package/fesm2022/ng-forge-dynamic-forms-group-field.component-D0_nmXf2.mjs.map +0 -1
  34. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-CNc4a_Xv.mjs.map +0 -1
  35. package/fesm2022/ng-forge-dynamic-forms-page-field.component-BJRNnoz-.mjs.map +0 -1
  36. package/fesm2022/ng-forge-dynamic-forms-row-wrapper.component-CwkYn5yl.mjs.map +0 -1
@@ -1,14 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { reflectComponentType, Injector, inject, EnvironmentInjector, DestroyRef, computed, signal, input, ViewContainerRef, Directive, linkedSignal, ChangeDetectionStrategy, Component, InjectionToken, Injectable, isSignal, runInInjectionContext, afterNextRender, untracked, ElementRef, PLATFORM_ID, isDevMode, isWritableSignal, TemplateRef, model, contentChildren, makeEnvironmentProviders } from '@angular/core';
2
+ import { reflectComponentType, Injector, inject, EnvironmentInjector, DestroyRef, computed, signal, input, ViewContainerRef, Directive, linkedSignal, ChangeDetectionStrategy, Component, Injectable, InjectionToken, isSignal, runInInjectionContext, afterNextRender, untracked, PendingTasks, ElementRef, PLATFORM_ID, isDevMode, TemplateRef, model, contentChildren, makeEnvironmentProviders } from '@angular/core';
3
3
  import { explicitEffect } from 'ngxtension/explicit-effect';
4
- import { DynamicFormLogger, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, toReadonlyFieldTreeCached, writeToFieldValue, WRAPPER_AUTO_ASSOCIATIONS, DEFAULT_WRAPPERS, READONLY_FIELD_TREE_CACHE, EventBus, FieldContextRegistryService, FunctionRegistryService, FORM_OPTIONS, evaluateCondition, FIELD_SIGNAL_CONTEXT, isRowField, isContainerField, isArrayField, hasChildFields, isSimplifiedArrayField, DynamicFormError, isStateLogicConfig, isDerivationLogicConfig, createDebouncedLogicFunction, createLogicFunction, ExpressionParser, applyValidator, isPageField, isContainerTypedField, isGroupField, getFieldValueHandling, normalizeFieldsArray, getNestedValue, isCrossFieldValidator, extractStringDependencies, isCrossFieldBuiltInValidator, hasCrossFieldWhenCondition, extractExpressionDependencies, isCrossFieldStateLogic, isCrossFieldSchema, keyBy, mapValues, isEqual, hasTargetProperty, ARRAY_CONTEXT, GROUP_CONTEXT, FORM_ID_PREFIX, baseFieldMapper, detectFormMode, validatePageNesting, FIELD_REGISTRY, assertNever, ADDON_KIND_REGISTRY, deepMergeDefaults, derivedFromDeferred, createWarningTracker, createFormFieldStateMap, readFieldStateInfo, getChangedKeys, resolveHttpRequest, createDefaultDerivationLogConfig, shouldLog, NoopLogger, RootFormRegistryService, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, EXTERNAL_DATA, DEPRECATION_WARNING_TRACKER, HttpConditionCache, HTTP_CONDITION_CACHE, HttpConditionFunctionCacheService, AsyncConditionFunctionCacheService, DynamicValueFunctionCacheService, LogicFunctionCacheService, setupInitializationTracking, ComponentInitializedEvent, DF_FIELD_TEMPLATES, rowFieldMapper, groupFieldMapper, arrayFieldMapper, pageFieldMapper, textFieldMapper, containerFieldMapper, isWrapperTypeDefinition, EMIT_FORM_VALUE_ON_EVENTS, resolveDynamicValue, DynamicTextPipe } from '@ng-forge/dynamic-forms/internal';
4
+ import { DynamicFormLogger, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, toReadonlyFieldTreeCached, writeToFieldValue, WRAPPER_AUTO_ASSOCIATIONS, DEFAULT_WRAPPERS, READONLY_FIELD_TREE_CACHE, EventBus, FieldContextRegistryService, FunctionRegistryService, FORM_OPTIONS, evaluateCondition, FIELD_SIGNAL_CONTEXT, isRowField, isContainerField, isArrayField, hasChildFields, isSimplifiedArrayField, DynamicFormError, isStateLogicConfig, isDerivationLogicConfig, createDebouncedLogicFunction, createLogicFunction, ExpressionParser, applyValidator, isPageField, isContainerTypedField, isGroupField, getFieldValueHandling, normalizeFieldsArray, getNestedValue, isCrossFieldValidator, extractStringDependencies, isCrossFieldBuiltInValidator, hasCrossFieldWhenCondition, extractExpressionDependencies, isCrossFieldStateLogic, isCrossFieldSchema, keyBy, mapValues, isEqual, hasTargetProperty, ARRAY_CONTEXT, GROUP_CONTEXT, FORM_ID_PREFIX, baseFieldMapper, detectFormMode, validatePageNesting, FIELD_REGISTRY, assertNever, ADDON_KIND_REGISTRY, deepMergeDefaults, derivedFromDeferred, createWarningTracker, RootFormRegistryService, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, EXTERNAL_DATA, DEPRECATION_WARNING_TRACKER, HttpConditionCache, HTTP_CONDITION_CACHE, HttpConditionFunctionCacheService, AsyncConditionFunctionCacheService, DynamicValueFunctionCacheService, LogicFunctionCacheService, setupInitializationTracking, ComponentInitializedEvent, DF_FIELD_TEMPLATES, rowFieldMapper, groupFieldMapper, arrayFieldMapper, pageFieldMapper, textFieldMapper, containerFieldMapper, isWrapperTypeDefinition, createDefaultDerivationLogConfig, NoopLogger, EMIT_FORM_VALUE_ON_EVENTS, resolveDynamicValue, DynamicTextPipe } from '@ng-forge/dynamic-forms/internal';
5
5
  import { takeUntilDestroyed, toObservable, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
6
- import { of, forkJoin, from, catchError, map, switchMap, isObservable, firstValueFrom, exhaustMap, EMPTY, debounceTime, distinctUntilChanged, tap, pipe, scan, Observable, Subject, concatMap, filter, take, startWith, pairwise, merge, combineLatestWith, auditTime, scheduled, queueScheduler, timer } from 'rxjs';
6
+ import { of, forkJoin, from, catchError, map, switchMap, isObservable, firstValueFrom, exhaustMap, EMPTY, debounceTime, distinctUntilChanged, tap, pipe, scan, Observable, Subject, concatMap, filter, take } from 'rxjs';
7
7
  import { submit, required, disabled, readonly, hidden, applyEach, applyWhenValue, applyWhen, apply, email, minLength, maxLength, pattern, min, max, schema, validateStandardSchema, validateTree, form, provideSignalFormsConfig } from '@angular/forms/signals';
8
8
  import { isStandardSchemaMarker } from '@ng-forge/dynamic-forms/schema';
9
9
  import { isPlatformBrowser, NgComponentOutlet, AsyncPipe, NgTemplateOutlet } from '@angular/common';
10
- import { HttpClient } from '@angular/common/http';
11
- import { catchError as catchError$1 } from 'rxjs/operators';
12
10
  import { NG_STATUS_CLASSES } from '@angular/forms/signals/compat';
13
11
 
14
12
  const EMPTY_WRAPPERS = Object.freeze([]);
@@ -258,7 +256,8 @@ function buildFieldInputs(rawInputs, cache, fieldType) {
258
256
 
259
257
  const EMPTY_STATE = Object.freeze({ phase: 'empty' });
260
258
  class FieldComponentSlot {
261
- state = signal(EMPTY_STATE, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
259
+ state = signal(EMPTY_STATE, /* @ts-ignore */
260
+ ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
262
261
  lastInputs = null;
263
262
  phase = () => this.state().phase;
264
263
  snapshot = () => this.state();
@@ -342,8 +341,10 @@ class FieldComponentSlot {
342
341
  }
343
342
 
344
343
  class DfFieldOutlet {
345
- dfFieldOutlet = input.required(...(ngDevMode ? [{ debugName: "dfFieldOutlet" }] : /* istanbul ignore next */ []));
346
- dfFieldOutletEnvironmentInjector = input(undefined, ...(ngDevMode ? [{ debugName: "dfFieldOutletEnvironmentInjector" }] : /* istanbul ignore next */ []));
344
+ dfFieldOutlet = input.required(/* @ts-ignore */
345
+ ...(ngDevMode ? [{ debugName: "dfFieldOutlet" }] : /* istanbul ignore next */ []));
346
+ dfFieldOutletEnvironmentInjector = input(undefined, /* @ts-ignore */
347
+ ...(ngDevMode ? [{ debugName: "dfFieldOutletEnvironmentInjector" }] : /* istanbul ignore next */ []));
347
348
  vcrRef = inject(ViewContainerRef);
348
349
  vcr = signal(this.vcrRef).asReadonly();
349
350
  destroyRef = inject(DestroyRef);
@@ -351,14 +352,20 @@ class DfFieldOutlet {
351
352
  defaultWrappersSignal = inject(DEFAULT_WRAPPERS, { optional: true });
352
353
  readonlyFieldCache = inject(READONLY_FIELD_TREE_CACHE);
353
354
  fieldComponent = new FieldComponentSlot();
354
- componentIdentity = computed(() => this.dfFieldOutlet().component, ...(ngDevMode ? [{ debugName: "componentIdentity" }] : /* istanbul ignore next */ []));
355
- renderReady = computed(() => this.dfFieldOutlet().renderReady() && !this.dfFieldOutlet().hidden(), ...(ngDevMode ? [{ debugName: "renderReady" }] : /* istanbul ignore next */ []));
356
- rawInputs = computed(() => this.dfFieldOutlet().inputs(), ...(ngDevMode ? [{ debugName: "rawInputs" }] : /* istanbul ignore next */ []));
355
+ componentIdentity = computed(() => this.dfFieldOutlet().component, /* @ts-ignore */
356
+ ...(ngDevMode ? [{ debugName: "componentIdentity" }] : /* istanbul ignore next */ []));
357
+ renderReady = computed(() => this.dfFieldOutlet().renderReady() && !this.dfFieldOutlet().hidden(), /* @ts-ignore */
358
+ ...(ngDevMode ? [{ debugName: "renderReady" }] : /* istanbul ignore next */ []));
359
+ rawInputs = computed(() => this.dfFieldOutlet().inputs(), /* @ts-ignore */
360
+ ...(ngDevMode ? [{ debugName: "rawInputs" }] : /* istanbul ignore next */ []));
357
361
  wrappers = computed(() => resolveWrappers(this.dfFieldOutlet().fieldDef, this.defaultWrappersSignal?.(), this.wrapperAutoAssociations), { ...(ngDevMode ? { debugName: "wrappers" } : /* istanbul ignore next */ {}), equal: isSameWrapperChain });
358
- fieldInputs = computed(() => buildFieldInputs(this.rawInputs(), this.readonlyFieldCache, this.dfFieldOutlet().fieldDef.type), ...(ngDevMode ? [{ debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
362
+ fieldInputs = computed(() => buildFieldInputs(this.rawInputs(), this.readonlyFieldCache, this.dfFieldOutlet().fieldDef.type), /* @ts-ignore */
363
+ ...(ngDevMode ? [{ debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
359
364
  defaultEnvInjector = inject(EnvironmentInjector);
360
- fieldEnvInjector = computed(() => this.dfFieldOutletEnvironmentInjector() ?? this.defaultEnvInjector, ...(ngDevMode ? [{ debugName: "fieldEnvInjector" }] : /* istanbul ignore next */ []));
361
- fieldInjector = computed(() => this.dfFieldOutlet().injector, ...(ngDevMode ? [{ debugName: "fieldInjector" }] : /* istanbul ignore next */ []));
365
+ fieldEnvInjector = computed(() => this.dfFieldOutletEnvironmentInjector() ?? this.defaultEnvInjector, /* @ts-ignore */
366
+ ...(ngDevMode ? [{ debugName: "fieldEnvInjector" }] : /* istanbul ignore next */ []));
367
+ fieldInjector = computed(() => this.dfFieldOutlet().injector, /* @ts-ignore */
368
+ ...(ngDevMode ? [{ debugName: "fieldInjector" }] : /* istanbul ignore next */ []));
362
369
  constructor() {
363
370
  createWrapperChainController({
364
371
  vcr: this.vcr,
@@ -376,10 +383,10 @@ class DfFieldOutlet {
376
383
  explicitEffect([this.rawInputs, this.fieldInputs], ([rawInputs, fieldInputs]) => this.fieldComponent.pushInputs(rawInputs, fieldInputs));
377
384
  this.destroyRef.onDestroy(() => this.fieldComponent.destroyOnTeardown());
378
385
  }
379
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfFieldOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
380
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: DfFieldOutlet, isStandalone: true, selector: "[dfFieldOutlet]", inputs: { dfFieldOutlet: { classPropertyName: "dfFieldOutlet", publicName: "dfFieldOutlet", isSignal: true, isRequired: true, transformFunction: null }, dfFieldOutletEnvironmentInjector: { classPropertyName: "dfFieldOutletEnvironmentInjector", publicName: "dfFieldOutletEnvironmentInjector", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
386
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfFieldOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
387
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.0", type: DfFieldOutlet, isStandalone: true, selector: "[dfFieldOutlet]", inputs: { dfFieldOutlet: { classPropertyName: "dfFieldOutlet", publicName: "dfFieldOutlet", isSignal: true, isRequired: true, transformFunction: null }, dfFieldOutletEnvironmentInjector: { classPropertyName: "dfFieldOutletEnvironmentInjector", publicName: "dfFieldOutletEnvironmentInjector", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
381
388
  }
382
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfFieldOutlet, decorators: [{
389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfFieldOutlet, decorators: [{
383
390
  type: Directive,
384
391
  args: [{
385
392
  selector: '[dfFieldOutlet]',
@@ -547,26 +554,32 @@ class PageOrchestratorComponent {
547
554
  fieldContextRegistry = inject(FieldContextRegistryService);
548
555
  functionRegistry = inject(FunctionRegistryService);
549
556
  formOptions = inject(FORM_OPTIONS, { optional: true });
550
- pageFields = input.required(...(ngDevMode ? [{ debugName: "pageFields" }] : /* istanbul ignore next */ []));
551
- form = input.required(...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
552
- fieldSignalContext = input.required(...(ngDevMode ? [{ debugName: "fieldSignalContext" }] : /* istanbul ignore next */ []));
557
+ pageFields = input.required(/* @ts-ignore */
558
+ ...(ngDevMode ? [{ debugName: "pageFields" }] : /* istanbul ignore next */ []));
559
+ form = input.required(/* @ts-ignore */
560
+ ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
561
+ fieldSignalContext = input.required(/* @ts-ignore */
562
+ ...(ngDevMode ? [{ debugName: "fieldSignalContext" }] : /* istanbul ignore next */ []));
553
563
  pageHiddenStates = computed(() => {
554
564
  const pages = this.pageFields();
555
565
  return pages.map((page) => this.evaluatePageHidden(page));
556
- }, ...(ngDevMode ? [{ debugName: "pageHiddenStates" }] : /* istanbul ignore next */ []));
566
+ }, /* @ts-ignore */
567
+ ...(ngDevMode ? [{ debugName: "pageHiddenStates" }] : /* istanbul ignore next */ []));
557
568
  visiblePageIndices = computed(() => {
558
569
  const hiddenStates = this.pageHiddenStates();
559
570
  return hiddenStates
560
571
  .map((hidden, index) => ({ index, hidden }))
561
572
  .filter((item) => !item.hidden)
562
573
  .map((item) => item.index);
563
- }, ...(ngDevMode ? [{ debugName: "visiblePageIndices" }] : /* istanbul ignore next */ []));
574
+ }, /* @ts-ignore */
575
+ ...(ngDevMode ? [{ debugName: "visiblePageIndices" }] : /* istanbul ignore next */ []));
564
576
  currentPageIndex = linkedSignal(() => {
565
577
  const totalPages = this.pageFields().length;
566
578
  if (totalPages === 0)
567
579
  return 0;
568
580
  return 0;
569
- }, ...(ngDevMode ? [{ debugName: "currentPageIndex" }] : /* istanbul ignore next */ []));
581
+ }, /* @ts-ignore */
582
+ ...(ngDevMode ? [{ debugName: "currentPageIndex" }] : /* istanbul ignore next */ []));
570
583
  state = computed(() => {
571
584
  const currentIndex = this.currentPageIndex();
572
585
  const totalPages = this.pageFields().length;
@@ -581,7 +594,8 @@ class PageOrchestratorComponent {
581
594
  isLastPage: isLastVisiblePage,
582
595
  navigationDisabled: false,
583
596
  };
584
- }, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
597
+ }, /* @ts-ignore */
598
+ ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
585
599
  currentPageValid = computed(() => {
586
600
  const currentIndex = this.currentPageIndex();
587
601
  const pages = this.pageFields();
@@ -602,11 +616,13 @@ class PageOrchestratorComponent {
602
616
  }
603
617
  }
604
618
  return true;
605
- }, ...(ngDevMode ? [{ debugName: "currentPageValid" }] : /* istanbul ignore next */ []));
619
+ }, /* @ts-ignore */
620
+ ...(ngDevMode ? [{ debugName: "currentPageValid" }] : /* istanbul ignore next */ []));
606
621
  extendedFieldSignalContext = computed(() => ({
607
622
  ...this.fieldSignalContext(),
608
623
  currentPageValid: this.currentPageValid,
609
- }), ...(ngDevMode ? [{ debugName: "extendedFieldSignalContext" }] : /* istanbul ignore next */ []));
624
+ }), /* @ts-ignore */
625
+ ...(ngDevMode ? [{ debugName: "extendedFieldSignalContext" }] : /* istanbul ignore next */ []));
610
626
  constructor() {
611
627
  this.setupEventListeners();
612
628
  explicitEffect([this.state, this.visiblePageIndices], ([state, visibleIndices]) => {
@@ -765,8 +781,8 @@ class PageOrchestratorComponent {
765
781
  }
766
782
  return false;
767
783
  }
768
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PageOrchestratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
769
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PageOrchestratorComponent, isStandalone: true, selector: "div[page-orchestrator]", inputs: { pageFields: { classPropertyName: "pageFields", publicName: "pageFields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, fieldSignalContext: { classPropertyName: "fieldSignalContext", publicName: "fieldSignalContext", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-current-page": "state().currentPageIndex", "attr.data-total-pages": "state().totalPages" }, classAttribute: "df-page-orchestrator" }, providers: [
784
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: PageOrchestratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
785
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: PageOrchestratorComponent, isStandalone: true, selector: "div[page-orchestrator]", inputs: { pageFields: { classPropertyName: "pageFields", publicName: "pageFields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, fieldSignalContext: { classPropertyName: "fieldSignalContext", publicName: "fieldSignalContext", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-current-page": "state().currentPageIndex", "attr.data-total-pages": "state().totalPages" }, classAttribute: "df-page-orchestrator" }, providers: [
770
786
  {
771
787
  provide: FIELD_SIGNAL_CONTEXT,
772
788
  useFactory: (orchestrator) => orchestrator.extendedFieldSignalContext(),
@@ -805,9 +821,12 @@ class PageOrchestratorComponent {
805
821
  }
806
822
  }
807
823
  }
808
- `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ng-forge-dynamic-forms-page-field.component-BJRNnoz-.mjs').then(m => m.default)], () => [import('./ng-forge-dynamic-forms-page-field.component-BJRNnoz-.mjs').then(m => m.default)]] });
824
+ `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [/* @ts-ignore */
825
+ import('./ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs').then(m => m.default)], () => [/* @ts-ignore */
826
+ import('./ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs').then(m => m.default)]] });
809
827
  }
810
- i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.14", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [import('./ng-forge-dynamic-forms-page-field.component-BJRNnoz-.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
828
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.0", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [/* @ts-ignore */
829
+ import('./ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
811
830
  type: Component,
812
831
  args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
813
832
  @for (pageField of pageFields(); track pageField.key; let i = $index) {
@@ -867,8 +886,6 @@ function collectLeafFieldKeys(fields) {
867
886
  return keys;
868
887
  }
869
888
 
870
- const FORM_INITIALIZER = new InjectionToken('FORM_INITIALIZER');
871
-
872
889
  const NORMALIZED_ARRAY_METADATA = Symbol('normalizedArrayMetadata');
873
890
  function setNormalizedArrayMetadata(arrayField, metadata) {
874
891
  arrayField[NORMALIZED_ARRAY_METADATA] = metadata;
@@ -1008,7 +1025,8 @@ function createSlot() {
1008
1025
  let counter = 0;
1009
1026
  const templates = new Map();
1010
1027
  const itemOrder = [];
1011
- const primitiveFieldKey = signal(undefined, ...(ngDevMode ? [{ debugName: "primitiveFieldKey" }] : /* istanbul ignore next */ []));
1028
+ const primitiveFieldKey = signal(undefined, /* @ts-ignore */
1029
+ ...(ngDevMode ? [{ debugName: "primitiveFieldKey" }] : /* istanbul ignore next */ []));
1012
1030
  return {
1013
1031
  templates,
1014
1032
  itemOrder,
@@ -1064,10 +1082,10 @@ class ArrayItemRegistryService {
1064
1082
  slot.clear();
1065
1083
  this.slots.clear();
1066
1084
  }
1067
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ArrayItemRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1068
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ArrayItemRegistryService });
1085
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ArrayItemRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1086
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ArrayItemRegistryService });
1069
1087
  }
1070
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ArrayItemRegistryService, decorators: [{
1088
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ArrayItemRegistryService, decorators: [{
1071
1089
  type: Injectable
1072
1090
  }] });
1073
1091
 
@@ -1091,10 +1109,10 @@ class SchemaRegistryService {
1091
1109
  }
1092
1110
  return schema;
1093
1111
  }
1094
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SchemaRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1095
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SchemaRegistryService });
1112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SchemaRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1113
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SchemaRegistryService });
1096
1114
  }
1097
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SchemaRegistryService, decorators: [{
1115
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SchemaRegistryService, decorators: [{
1098
1116
  type: Injectable
1099
1117
  }] });
1100
1118
 
@@ -3208,7 +3226,8 @@ class FormStateMachine {
3208
3226
  }
3209
3227
  constructor(config) {
3210
3228
  this.config = config;
3211
- this._state = signal(createUninitializedState(), ...(ngDevMode ? [{ debugName: "_state" }] : /* istanbul ignore next */ []));
3229
+ this._state = signal(createUninitializedState(), /* @ts-ignore */
3230
+ ...(ngDevMode ? [{ debugName: "_state" }] : /* istanbul ignore next */ []));
3212
3231
  this.state = this._state.asReadonly();
3213
3232
  this.state$ = toObservable(this._state, { injector: config.injector });
3214
3233
  this.setupActionProcessing();
@@ -3523,7 +3542,8 @@ class FormStateManager {
3523
3542
  scheduler = createSideEffectScheduler(this.injector);
3524
3543
  machine;
3525
3544
  fieldProcessors = inject(CONTAINER_FIELD_PROCESSORS);
3526
- fieldLoadingErrors = signal([], ...(ngDevMode ? [{ debugName: "fieldLoadingErrors" }] : /* istanbul ignore next */ []));
3545
+ fieldLoadingErrors = signal([], /* @ts-ignore */
3546
+ ...(ngDevMode ? [{ debugName: "fieldLoadingErrors" }] : /* istanbul ignore next */ []));
3527
3547
  _formCache = { current: undefined };
3528
3548
  activeConfig = computed(() => {
3529
3549
  const state = this.machine.state();
@@ -3540,33 +3560,39 @@ class FormStateManager {
3540
3560
  if (state.type === LifecycleState.Initializing)
3541
3561
  return state.config;
3542
3562
  return undefined;
3543
- }, ...(ngDevMode ? [{ debugName: "activeConfig" }] : /* istanbul ignore next */ []));
3563
+ }, /* @ts-ignore */
3564
+ ...(ngDevMode ? [{ debugName: "activeConfig" }] : /* istanbul ignore next */ []));
3544
3565
  renderPhase = computed(() => {
3545
3566
  const state = this.machine.state();
3546
3567
  if (isTransitioningState(state) && state.phase === Phase.Teardown)
3547
3568
  return Phase.Teardown;
3548
3569
  return 'render';
3549
- }, ...(ngDevMode ? [{ debugName: "renderPhase" }] : /* istanbul ignore next */ []));
3550
- shouldRender = computed(() => this.activeConfig() !== undefined, ...(ngDevMode ? [{ debugName: "shouldRender" }] : /* istanbul ignore next */ []));
3570
+ }, /* @ts-ignore */
3571
+ ...(ngDevMode ? [{ debugName: "renderPhase" }] : /* istanbul ignore next */ []));
3572
+ shouldRender = computed(() => this.activeConfig() !== undefined, /* @ts-ignore */
3573
+ ...(ngDevMode ? [{ debugName: "shouldRender" }] : /* istanbul ignore next */ []));
3551
3574
  formModeDetection = computed(() => {
3552
3575
  const config = this.activeConfig();
3553
3576
  if (!config) {
3554
3577
  return { mode: 'non-paged', isValid: true, errors: [] };
3555
3578
  }
3556
3579
  return detectFormMode(config.fields || []);
3557
- }, ...(ngDevMode ? [{ debugName: "formModeDetection" }] : /* istanbul ignore next */ []));
3580
+ }, /* @ts-ignore */
3581
+ ...(ngDevMode ? [{ debugName: "formModeDetection" }] : /* istanbul ignore next */ []));
3558
3582
  formConfigValidation = computed(() => {
3559
3583
  const config = this.activeConfig();
3560
3584
  if (!config)
3561
3585
  return { isValid: true, errors: [], warnings: [] };
3562
3586
  return FormModeValidator.validateFormConfiguration(config.fields || []);
3563
- }, ...(ngDevMode ? [{ debugName: "formConfigValidation" }] : /* istanbul ignore next */ []));
3587
+ }, /* @ts-ignore */
3588
+ ...(ngDevMode ? [{ debugName: "formConfigValidation" }] : /* istanbul ignore next */ []));
3564
3589
  effectiveFormOptions = computed(() => {
3565
3590
  const config = this.activeConfig();
3566
3591
  const configOptions = config?.options || {};
3567
3592
  const inputOptions = this.deps.formOptions() ?? undefined;
3568
3593
  return { ...configOptions, ...inputOptions };
3569
- }, ...(ngDevMode ? [{ debugName: "effectiveFormOptions" }] : /* istanbul ignore next */ []));
3594
+ }, /* @ts-ignore */
3595
+ ...(ngDevMode ? [{ debugName: "effectiveFormOptions" }] : /* istanbul ignore next */ []));
3570
3596
  pageFieldDefinitions = computed(() => {
3571
3597
  const config = this.activeConfig();
3572
3598
  const mode = this.formModeDetection().mode;
@@ -3574,8 +3600,10 @@ class FormStateManager {
3574
3600
  return config.fields.filter(isPageField);
3575
3601
  }
3576
3602
  return [];
3577
- }, ...(ngDevMode ? [{ debugName: "pageFieldDefinitions" }] : /* istanbul ignore next */ []));
3578
- rawFieldRegistry = computed(() => this.fieldRegistry.raw, ...(ngDevMode ? [{ debugName: "rawFieldRegistry" }] : /* istanbul ignore next */ []));
3603
+ }, /* @ts-ignore */
3604
+ ...(ngDevMode ? [{ debugName: "pageFieldDefinitions" }] : /* istanbul ignore next */ []));
3605
+ rawFieldRegistry = computed(() => this.fieldRegistry.raw, /* @ts-ignore */
3606
+ ...(ngDevMode ? [{ debugName: "rawFieldRegistry" }] : /* istanbul ignore next */ []));
3579
3607
  formSetup = computed(() => {
3580
3608
  const registry = this.rawFieldRegistry();
3581
3609
  const state = this.machine.state();
@@ -3600,14 +3628,17 @@ class FormStateManager {
3600
3628
  return this.createFormSetupFromConfig(config.fields, modeDetection.mode, registry);
3601
3629
  }
3602
3630
  return this.createEmptyFormSetup(registry);
3603
- }, ...(ngDevMode ? [{ debugName: "formSetup" }] : /* istanbul ignore next */ []));
3604
- defaultValues = linkedSignal(() => this.formSetup().defaultValues, ...(ngDevMode ? [{ debugName: "defaultValues" }] : /* istanbul ignore next */ []));
3631
+ }, /* @ts-ignore */
3632
+ ...(ngDevMode ? [{ debugName: "formSetup" }] : /* istanbul ignore next */ []));
3633
+ defaultValues = linkedSignal(() => this.formSetup().defaultValues, /* @ts-ignore */
3634
+ ...(ngDevMode ? [{ debugName: "defaultValues" }] : /* istanbul ignore next */ []));
3605
3635
  validKeys = computed(() => {
3606
3636
  const schemaFields = this.formSetup().schemaFields;
3607
3637
  if (!schemaFields || schemaFields.length === 0)
3608
3638
  return undefined;
3609
3639
  return new Set(schemaFields.map((f) => f.key).filter((key) => key !== undefined));
3610
- }, ...(ngDevMode ? [{ debugName: "validKeys" }] : /* istanbul ignore next */ []));
3640
+ }, /* @ts-ignore */
3641
+ ...(ngDevMode ? [{ debugName: "validKeys" }] : /* istanbul ignore next */ []));
3611
3642
  fieldStateSnapshot = computed(() => {
3612
3643
  const setup = this.formSetup();
3613
3644
  if (!setup.schemaFields || setup.schemaFields.length === 0)
@@ -3615,9 +3646,12 @@ class FormStateManager {
3615
3646
  const snapshot = {};
3616
3647
  collectFieldStateSnapshot(setup.schemaFields, asFieldTreeRecord(this.form()), [], snapshot);
3617
3648
  return snapshot;
3618
- }, ...(ngDevMode ? [{ debugName: "fieldStateSnapshot" }] : /* istanbul ignore next */ []));
3619
- excludedValueStore = signal({}, ...(ngDevMode ? [{ debugName: "excludedValueStore" }] : /* istanbul ignore next */ []));
3620
- prevFieldStateSnapshot = signal({}, ...(ngDevMode ? [{ debugName: "prevFieldStateSnapshot" }] : /* istanbul ignore next */ []));
3649
+ }, /* @ts-ignore */
3650
+ ...(ngDevMode ? [{ debugName: "fieldStateSnapshot" }] : /* istanbul ignore next */ []));
3651
+ excludedValueStore = signal({}, /* @ts-ignore */
3652
+ ...(ngDevMode ? [{ debugName: "excludedValueStore" }] : /* istanbul ignore next */ []));
3653
+ prevFieldStateSnapshot = signal({}, /* @ts-ignore */
3654
+ ...(ngDevMode ? [{ debugName: "prevFieldStateSnapshot" }] : /* istanbul ignore next */ []));
3621
3655
  entity = linkedSignal(() => {
3622
3656
  const inputValue = this.deps.value();
3623
3657
  const defaults = this.defaultValues();
@@ -3656,12 +3690,14 @@ class FormStateManager {
3656
3690
  return createFormLevelSchema(config.schema);
3657
3691
  }
3658
3692
  return undefined;
3659
- }), ...(ngDevMode ? [{ debugName: "formSchema" }] : /* istanbul ignore next */ []));
3693
+ }), /* @ts-ignore */
3694
+ ...(ngDevMode ? [{ debugName: "formSchema" }] : /* istanbul ignore next */ []));
3660
3695
  form = computed(() => {
3661
3696
  const schema = this.formSchema();
3662
3697
  const injector = this.injector;
3663
3698
  return untracked(() => (schema ? form(this.entity, schema, { injector }) : form(this.entity, { injector })));
3664
- }, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
3699
+ }, /* @ts-ignore */
3700
+ ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
3665
3701
  isFieldPipelineSettled;
3666
3702
  fieldSignalContext = computed(() => {
3667
3703
  const formSignal = this.form;
@@ -3681,9 +3717,12 @@ class FormStateManager {
3681
3717
  return currentForm;
3682
3718
  },
3683
3719
  };
3684
- }, ...(ngDevMode ? [{ debugName: "fieldSignalContext" }] : /* istanbul ignore next */ []));
3685
- formInstance = computed(() => this.form()(), ...(ngDevMode ? [{ debugName: "formInstance" }] : /* istanbul ignore next */ []));
3686
- formValue = computed(() => this.formInstance().value(), ...(ngDevMode ? [{ debugName: "formValue" }] : /* istanbul ignore next */ []));
3720
+ }, /* @ts-ignore */
3721
+ ...(ngDevMode ? [{ debugName: "fieldSignalContext" }] : /* istanbul ignore next */ []));
3722
+ formInstance = computed(() => this.form()(), /* @ts-ignore */
3723
+ ...(ngDevMode ? [{ debugName: "formInstance" }] : /* istanbul ignore next */ []));
3724
+ formValue = computed(() => this.formInstance().value(), /* @ts-ignore */
3725
+ ...(ngDevMode ? [{ debugName: "formValue" }] : /* istanbul ignore next */ []));
3687
3726
  filteredFormValue = computed(() => {
3688
3727
  const rawValue = this.formValue();
3689
3728
  const setup = this.formSetup();
@@ -3699,7 +3738,8 @@ class FormStateManager {
3699
3738
  };
3700
3739
  const fieldTreeRecord = asFieldTreeRecord(formTree);
3701
3740
  return filterFormValue(rawValue, setup.schemaFields, fieldTreeRecord, setup.registry, this.valueExclusionDefaults, formOptions);
3702
- }, ...(ngDevMode ? [{ debugName: "filteredFormValue" }] : /* istanbul ignore next */ []));
3741
+ }, /* @ts-ignore */
3742
+ ...(ngDevMode ? [{ debugName: "filteredFormValue" }] : /* istanbul ignore next */ []));
3703
3743
  boundFormValue = computed(() => {
3704
3744
  const rawValue = this.formValue();
3705
3745
  const setup = this.formSetup();
@@ -3715,18 +3755,26 @@ class FormStateManager {
3715
3755
  };
3716
3756
  const fieldTreeRecord = asFieldTreeRecord(formTree);
3717
3757
  return filterFormValue(rawValue, setup.schemaFields, fieldTreeRecord, setup.registry, BOUND_VALUE_EXCLUSION_BASELINE, formOptions);
3718
- }, ...(ngDevMode ? [{ debugName: "boundFormValue" }] : /* istanbul ignore next */ []));
3719
- valid = computed(() => this.formInstance().valid(), ...(ngDevMode ? [{ debugName: "valid" }] : /* istanbul ignore next */ []));
3720
- invalid = computed(() => this.formInstance().invalid(), ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
3721
- dirty = computed(() => this.formInstance().dirty(), ...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
3722
- touched = computed(() => this.formInstance().touched(), ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
3723
- errors = computed(() => this.formInstance().errors(), ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
3758
+ }, /* @ts-ignore */
3759
+ ...(ngDevMode ? [{ debugName: "boundFormValue" }] : /* istanbul ignore next */ []));
3760
+ valid = computed(() => this.formInstance().valid(), /* @ts-ignore */
3761
+ ...(ngDevMode ? [{ debugName: "valid" }] : /* istanbul ignore next */ []));
3762
+ invalid = computed(() => this.formInstance().invalid(), /* @ts-ignore */
3763
+ ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
3764
+ dirty = computed(() => this.formInstance().dirty(), /* @ts-ignore */
3765
+ ...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
3766
+ touched = computed(() => this.formInstance().touched(), /* @ts-ignore */
3767
+ ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
3768
+ errors = computed(() => this.formInstance().errors(), /* @ts-ignore */
3769
+ ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
3724
3770
  disabled = computed(() => {
3725
3771
  const optionsDisabled = this.effectiveFormOptions().disabled;
3726
3772
  const formDisabled = this.formInstance().disabled();
3727
3773
  return optionsDisabled ?? formDisabled;
3728
- }, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
3729
- submitting = computed(() => this.formInstance().submitting(), ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
3774
+ }, /* @ts-ignore */
3775
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
3776
+ submitting = computed(() => this.formInstance().submitting(), /* @ts-ignore */
3777
+ ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
3730
3778
  fieldsSource = computed(() => {
3731
3779
  const state = this.machine.state();
3732
3780
  if (isTransitioningState(state)) {
@@ -3751,7 +3799,8 @@ class FormStateManager {
3751
3799
  fieldInjector = computed(() => Injector.create({
3752
3800
  parent: this.injector,
3753
3801
  providers: [{ provide: FIELD_SIGNAL_CONTEXT, useValue: this.fieldSignalContext() }],
3754
- }), ...(ngDevMode ? [{ debugName: "fieldInjector" }] : /* istanbul ignore next */ []));
3802
+ }), /* @ts-ignore */
3803
+ ...(ngDevMode ? [{ debugName: "fieldInjector" }] : /* istanbul ignore next */ []));
3755
3804
  resolvedFields;
3756
3805
  submitted$;
3757
3806
  reset$;
@@ -3817,7 +3866,8 @@ class FormStateManager {
3817
3866
  }), map((fields) => fields.filter((f) => f !== undefined)), scan(reconcileFields, [])), { initialValue: [], injector: this.injector });
3818
3867
  this.isFieldPipelineSettled = computed(() => {
3819
3868
  return this.fieldsSource().length === this.resolvedFields().length;
3820
- }, ...(ngDevMode ? [{ debugName: "isFieldPipelineSettled" }] : /* istanbul ignore next */ []));
3869
+ }, /* @ts-ignore */
3870
+ ...(ngDevMode ? [{ debugName: "isFieldPipelineSettled" }] : /* istanbul ignore next */ []));
3821
3871
  this.submitted$ = this.eventBus.on('submit').pipe(filter(() => {
3822
3872
  if (!this.valid()) {
3823
3873
  this.logger.debug('Form submitted while invalid, not emitting to (submitted) output');
@@ -4038,17 +4088,115 @@ class FormStateManager {
4038
4088
  ngOnDestroy() {
4039
4089
  this.machine.dispatch({ type: Action.Destroy });
4040
4090
  }
4041
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormStateManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4042
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormStateManager });
4091
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: FormStateManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4092
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: FormStateManager });
4043
4093
  }
4044
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormStateManager, decorators: [{
4094
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: FormStateManager, decorators: [{
4045
4095
  type: Injectable
4046
4096
  }], ctorParameters: () => [] });
4047
4097
 
4098
+ function traverseFieldsWithContext(fields, context, visitor, hooks) {
4099
+ for (const field of fields) {
4100
+ visitor(field, context);
4101
+ if (!hasChildFields(field))
4102
+ continue;
4103
+ if (field.type === 'array') {
4104
+ const childContext = mergeContext(context, hooks?.onArrayChild?.(context, field));
4105
+ const arrayChildren = collectArrayChildren(field);
4106
+ traverseFieldsWithContext(arrayChildren, childContext, visitor, hooks);
4107
+ continue;
4108
+ }
4109
+ const overrides = field.type === 'group' ? hooks?.onGroupChild?.(context, field) : hooks?.onLayoutChild?.(context, field);
4110
+ const childContext = mergeContext(context, overrides);
4111
+ traverseFieldsWithContext(normalizeFieldsArray(field.fields), childContext, visitor, hooks);
4112
+ }
4113
+ }
4114
+ function someField(fields, predicate) {
4115
+ return fields.some((field) => {
4116
+ if (predicate(field))
4117
+ return true;
4118
+ if (!hasChildFields(field))
4119
+ return false;
4120
+ const children = field.type === 'array' ? collectArrayChildren(field) : normalizeFieldsArray(field.fields);
4121
+ return someField(children, predicate);
4122
+ });
4123
+ }
4124
+ function collectArrayChildren(field) {
4125
+ let arrayItems = normalizeFieldsArray(field.fields);
4126
+ if (arrayItems.length === 0) {
4127
+ const metadataTemplate = getNormalizedArrayMetadata(field)?.template;
4128
+ if (metadataTemplate) {
4129
+ arrayItems = [
4130
+ Array.isArray(metadataTemplate) ? [...metadataTemplate] : metadataTemplate,
4131
+ ];
4132
+ }
4133
+ }
4134
+ const flattened = [];
4135
+ for (const item of arrayItems) {
4136
+ if (Array.isArray(item)) {
4137
+ flattened.push(...item);
4138
+ }
4139
+ else {
4140
+ flattened.push(item);
4141
+ }
4142
+ }
4143
+ return flattened;
4144
+ }
4145
+ function mergeContext(base, overrides) {
4146
+ return overrides ? { ...base, ...overrides } : { ...base };
4147
+ }
4148
+
4149
+ function configHasDerivations(fields) {
4150
+ return someField(fields, (field) => {
4151
+ if (!field.key)
4152
+ return false;
4153
+ const validationField = field;
4154
+ return !!validationField.derivation || !!validationField.logic?.some(isDerivationLogicConfig);
4155
+ });
4156
+ }
4157
+
4158
+ const DERIVATION_RENDER_GATE = new InjectionToken('DERIVATION_RENDER_GATE');
4159
+ function createDerivationRenderGate() {
4160
+ const stateManager = inject(FormStateManager);
4161
+ const injector = inject(Injector);
4162
+ const pendingTasks = inject(PendingTasks);
4163
+ const logger = inject(DynamicFormLogger);
4164
+ const hasDerivations = computed(() => {
4165
+ const setup = stateManager.formSetup();
4166
+ return !!setup && configHasDerivations(setup.schemaFields);
4167
+ }, /* @ts-ignore */
4168
+ ...(ngDevMode ? [{ debugName: "hasDerivations" }] : /* istanbul ignore next */ []));
4169
+ const engine = signal('idle', /* @ts-ignore */
4170
+ ...(ngDevMode ? [{ debugName: "engine" }] : /* istanbul ignore next */ []));
4171
+ explicitEffect([hasDerivations], ([has]) => {
4172
+ if (!has || engine() !== 'idle')
4173
+ return;
4174
+ engine.set('loading');
4175
+ pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs')
4176
+ .then(({ bootstrapDerivationOrchestrator }) => {
4177
+ runInInjectionContext(injector, () => bootstrapDerivationOrchestrator());
4178
+ engine.set('wired');
4179
+ })
4180
+ .catch((error) => {
4181
+ engine.set('failed');
4182
+ logger.error('[Dynamic Forms] Failed to load the derivation engine; derivations will not apply.', error);
4183
+ }));
4184
+ });
4185
+ return computed(() => {
4186
+ if (!hasDerivations())
4187
+ return true;
4188
+ const state = engine();
4189
+ return state === 'wired' || state === 'failed';
4190
+ });
4191
+ }
4192
+
4193
+ const FORM_INITIALIZER = new InjectionToken('FORM_INITIALIZER');
4194
+
4048
4195
  const AUTO_ID_PREFIX = 'df-';
4049
4196
  class DynamicFormInstanceRegistry {
4050
4197
  slots = new Map();
4051
- _membership = signal(0, ...(ngDevMode ? [{ debugName: "_membership" }] : /* istanbul ignore next */ []));
4198
+ _membership = signal(0, /* @ts-ignore */
4199
+ ...(ngDevMode ? [{ debugName: "_membership" }] : /* istanbul ignore next */ []));
4052
4200
  multiplePresent = computed(() => {
4053
4201
  this._membership();
4054
4202
  let visible = 0;
@@ -4060,7 +4208,8 @@ class DynamicFormInstanceRegistry {
4060
4208
  }
4061
4209
  }
4062
4210
  return false;
4063
- }, ...(ngDevMode ? [{ debugName: "multiplePresent" }] : /* istanbul ignore next */ []));
4211
+ }, /* @ts-ignore */
4212
+ ...(ngDevMode ? [{ debugName: "multiplePresent" }] : /* istanbul ignore next */ []));
4064
4213
  register(visible) {
4065
4214
  let slot = 1;
4066
4215
  while (this.slots.has(slot))
@@ -4073,10 +4222,10 @@ class DynamicFormInstanceRegistry {
4073
4222
  this.slots.delete(Number(id.slice(AUTO_ID_PREFIX.length)));
4074
4223
  this._membership.update((m) => m + 1);
4075
4224
  }
4076
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormInstanceRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4077
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormInstanceRegistry, providedIn: 'root' });
4225
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DynamicFormInstanceRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4226
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DynamicFormInstanceRegistry, providedIn: 'root' });
4078
4227
  }
4079
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormInstanceRegistry, decorators: [{
4228
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DynamicFormInstanceRegistry, decorators: [{
4080
4229
  type: Injectable,
4081
4230
  args: [{ providedIn: 'root' }]
4082
4231
  }] });
@@ -4098,15 +4247,18 @@ class FormIdPrefixService {
4098
4247
  options = inject(FORM_OPTIONS, { optional: true });
4099
4248
  logger = inject(DynamicFormLogger, { optional: true });
4100
4249
  host = inject((ElementRef)).nativeElement;
4101
- visible = signal(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
4250
+ visible = signal(true, /* @ts-ignore */
4251
+ ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
4102
4252
  autoId = this.registry.register(this.visible);
4103
- rawPrefix = computed(() => this.options?.()?.idPrefix?.trim() || undefined, ...(ngDevMode ? [{ debugName: "rawPrefix" }] : /* istanbul ignore next */ []));
4253
+ rawPrefix = computed(() => this.options?.()?.idPrefix?.trim() || undefined, /* @ts-ignore */
4254
+ ...(ngDevMode ? [{ debugName: "rawPrefix" }] : /* istanbul ignore next */ []));
4104
4255
  prefix = computed(() => {
4105
4256
  const explicit = this.rawPrefix();
4106
4257
  if (explicit)
4107
4258
  return sanitizeIdPrefix(explicit);
4108
4259
  return this.registry.multiplePresent() ? this.autoId : '';
4109
- }, ...(ngDevMode ? [{ debugName: "prefix" }] : /* istanbul ignore next */ []));
4260
+ }, /* @ts-ignore */
4261
+ ...(ngDevMode ? [{ debugName: "prefix" }] : /* istanbul ignore next */ []));
4110
4262
  constructor() {
4111
4263
  const destroyRef = inject(DestroyRef);
4112
4264
  destroyRef.onDestroy(() => this.registry.unregister(this.autoId));
@@ -4124,10 +4276,10 @@ class FormIdPrefixService {
4124
4276
  });
4125
4277
  }
4126
4278
  }
4127
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormIdPrefixService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4128
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormIdPrefixService });
4279
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: FormIdPrefixService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4280
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: FormIdPrefixService });
4129
4281
  }
4130
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FormIdPrefixService, decorators: [{
4282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: FormIdPrefixService, decorators: [{
4131
4283
  type: Injectable
4132
4284
  }], ctorParameters: () => [] });
4133
4285
 
@@ -4136,2588 +4288,159 @@ const DERIVATION_WARNING_TRACKER = new InjectionToken('DerivationWarningTracker'
4136
4288
  factory: createWarningTracker,
4137
4289
  });
4138
4290
 
4139
- function parseArrayPath(path) {
4140
- const ARRAY_PLACEHOLDER = '.$.';
4141
- const placeholderIndex = path.indexOf(ARRAY_PLACEHOLDER);
4142
- if (placeholderIndex === -1) {
4143
- return {
4144
- arrayPath: '',
4145
- relativePath: '',
4146
- isArrayPath: false,
4147
- };
4148
- }
4149
- return {
4150
- arrayPath: path.substring(0, placeholderIndex),
4151
- relativePath: path.substring(placeholderIndex + ARRAY_PLACEHOLDER.length),
4152
- isArrayPath: true,
4153
- };
4154
- }
4155
- function resolveArrayPath(path, index) {
4156
- const info = parseArrayPath(path);
4157
- if (!info.isArrayPath) {
4158
- return path;
4159
- }
4160
- return `${info.arrayPath}.${index}.${info.relativePath}`;
4161
- }
4162
- function isArrayPlaceholderPath(path) {
4163
- return path.includes('.$.');
4164
- }
4165
- function extractArrayPath(path) {
4166
- return parseArrayPath(path).arrayPath;
4167
- }
4168
- function splitPath(path) {
4169
- if (!path)
4170
- return [];
4171
- return path
4172
- .replace(/\[(\d+)\]/g, '.$1')
4173
- .split('.')
4174
- .filter(Boolean);
4175
- }
4176
- function joinPath(segments) {
4177
- return segments.join('.');
4178
- }
4179
- function getParentPath(path) {
4180
- const segments = splitPath(path);
4181
- if (segments.length <= 1)
4182
- return '';
4183
- return joinPath(segments.slice(0, -1));
4184
- }
4185
- function getLeafPath(path) {
4186
- const segments = splitPath(path);
4187
- return segments[segments.length - 1] ?? '';
4188
- }
4189
- function parseMultiArrayPath(path) {
4190
- const parts = path.split('.');
4191
- const segments = [];
4192
- const placeholderPositions = [];
4193
- for (let i = 0; i < parts.length; i++) {
4194
- if (parts[i] === '$') {
4195
- placeholderPositions.push(i);
4196
- }
4197
- else {
4198
- segments.push(parts[i]);
4199
- }
4200
- }
4201
- return {
4202
- isArrayPath: placeholderPositions.length > 0,
4203
- placeholderCount: placeholderPositions.length,
4204
- segments,
4205
- placeholderPositions,
4206
- };
4207
- }
4208
- function resolveMultiArrayPath(path, indices) {
4209
- const parts = path.split('.');
4210
- let indexPointer = 0;
4211
- const resolved = parts.map((part) => {
4212
- if (part === '$') {
4213
- if (indexPointer >= indices.length) {
4214
- throw new Error(`Not enough indices provided for path '${path}'. ` +
4215
- `Expected ${parts.filter((p) => p === '$').length} indices, got ${indices.length}.`);
4216
- }
4217
- return String(indices[indexPointer++]);
4291
+ const ADDON_ACTION_HANDLERS = new InjectionToken('ADDON_ACTION_HANDLERS');
4292
+ const ADDON_ACTION_REGISTRY = new InjectionToken('ADDON_ACTION_REGISTRY');
4293
+ function createAddonActionRegistry() {
4294
+ const sources = inject(ADDON_ACTION_HANDLERS, { optional: true }) ?? [];
4295
+ const map = new Map();
4296
+ for (const handlers of sources) {
4297
+ for (const [name, fn] of Object.entries(handlers)) {
4298
+ map.set(name, fn);
4218
4299
  }
4219
- return part;
4220
- });
4221
- if (indexPointer < indices.length) {
4222
- throw new Error(`Too many indices provided for path '${path}'. ` + `Expected ${indexPointer} indices, got ${indices.length}.`);
4223
4300
  }
4224
- return resolved.join('.');
4225
- }
4226
- function countArrayPlaceholders(path) {
4227
- return path.split('.').filter((part) => part === '$').length;
4301
+ return map;
4228
4302
  }
4229
4303
 
4230
- function createEmptyDerivationCollection() {
4231
- return { entries: [] };
4304
+ function coreProviders() {
4305
+ return [
4306
+ EventBus,
4307
+ { provide: CONTAINER_FIELD_PROCESSORS, useFactory: createContainerFieldProcessors },
4308
+ SchemaRegistryService,
4309
+ FunctionRegistryService,
4310
+ {
4311
+ provide: FORM_STATE_DEPS,
4312
+ useFactory: () => ({ config: null, formOptions: null, value: null, source: null }),
4313
+ },
4314
+ FormStateManager,
4315
+ {
4316
+ provide: RootFormRegistryService,
4317
+ useFactory: (stateManager) => new RootFormRegistryService(stateManager.formValue, computed(() => stateManager.form())),
4318
+ deps: [FormStateManager],
4319
+ },
4320
+ FieldContextRegistryService,
4321
+ ArrayItemRegistryService,
4322
+ {
4323
+ provide: DEFAULT_PROPS,
4324
+ useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.defaultProps),
4325
+ deps: [FormStateManager],
4326
+ },
4327
+ {
4328
+ provide: DEFAULT_WRAPPERS,
4329
+ useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.defaultWrappers),
4330
+ deps: [FormStateManager],
4331
+ },
4332
+ {
4333
+ provide: DEFAULT_VALIDATION_MESSAGES,
4334
+ useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.defaultValidationMessages),
4335
+ deps: [FormStateManager],
4336
+ },
4337
+ {
4338
+ provide: FORM_OPTIONS,
4339
+ useFactory: (stateManager) => stateManager.effectiveFormOptions,
4340
+ deps: [FormStateManager],
4341
+ },
4342
+ {
4343
+ provide: EXTERNAL_DATA,
4344
+ useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.externalData),
4345
+ deps: [FormStateManager],
4346
+ },
4347
+ FormIdPrefixService,
4348
+ {
4349
+ provide: FORM_ID_PREFIX,
4350
+ useFactory: (svc) => svc.prefix,
4351
+ deps: [FormIdPrefixService],
4352
+ },
4353
+ { provide: DEPRECATION_WARNING_TRACKER, useFactory: createWarningTracker },
4354
+ { provide: ADDON_ACTION_REGISTRY, useFactory: createAddonActionRegistry },
4355
+ ];
4232
4356
  }
4233
- function createDerivationChainContext() {
4234
- return {
4235
- appliedDerivations: new Set(),
4236
- iteration: 0,
4237
- };
4357
+ function derivationProviders() {
4358
+ return [
4359
+ { provide: DERIVATION_WARNING_TRACKER, useFactory: createWarningTracker },
4360
+ { provide: DERIVATION_RENDER_GATE, useFactory: createDerivationRenderGate },
4361
+ ];
4238
4362
  }
4239
- function createDerivationKey(fieldKey) {
4240
- return fieldKey;
4363
+ function propertyDerivationProviders() {
4364
+ return [{ provide: PROPERTY_OVERRIDE_STORE, useFactory: createPropertyOverrideStore }];
4241
4365
  }
4242
- function parseDerivationKey(key) {
4243
- return { fieldKey: key };
4366
+ function httpExpressionProviders() {
4367
+ return [{ provide: HTTP_CONDITION_CACHE, useFactory: () => new HttpConditionCache(100) }, HttpConditionFunctionCacheService];
4244
4368
  }
4245
-
4246
- function isThenableOrObservable(value) {
4247
- if (value === null || typeof value !== 'object')
4248
- return false;
4249
- const candidate = value;
4250
- return typeof candidate.then === 'function' || typeof candidate.subscribe === 'function';
4369
+ function asyncExpressionProviders() {
4370
+ return [AsyncConditionFunctionCacheService];
4251
4371
  }
4252
- function computeValueFromEntry(entry, evalContext, options) {
4253
- if (entry.value !== undefined) {
4254
- return entry.value;
4255
- }
4256
- if (entry.expression) {
4257
- return ExpressionParser.evaluate(entry.expression, evalContext);
4258
- }
4259
- if (entry.fn || entry.functionName) {
4260
- if (entry.fn && entry.functionName) {
4261
- evalContext.logger.warn(`Both "fn" and "functionName" are set on derivation for '${options.subject}'. Inline "fn" takes precedence; "functionName" is ignored.`);
4262
- }
4263
- const fn = entry.fn ?? (entry.functionName ? options.derivationFunctions?.[entry.functionName] : undefined);
4264
- if (!fn) {
4265
- const kind = options.functionKind ?? 'Derivation function';
4266
- throw new DynamicFormError(`${kind} '${entry.functionName}' not found in customFnConfig.derivations`);
4267
- }
4268
- const result = fn(evalContext);
4269
- if (isThenableOrObservable(result)) {
4270
- evalContext.logger.warn(`Derivation for '${options.subject}' returned a Promise or Observable. ` +
4271
- `Synchronous derivations must return a value; use 'asyncDerivations' or an HTTP derivation for asynchronous logic. Skipping.`);
4272
- return undefined;
4273
- }
4274
- return result;
4275
- }
4276
- throw new DynamicFormError(`Derivation for ${options.subject} has no value source. Specify 'value', 'expression', 'functionName', or 'fn'.`);
4372
+ function dynamicValueProviders() {
4373
+ return [DynamicValueFunctionCacheService];
4277
4374
  }
4278
-
4279
- function getParentPathInScope(fieldKey) {
4280
- const lastDot = fieldKey.lastIndexOf('.');
4281
- if (lastDot <= 0)
4282
- return undefined;
4283
- return fieldKey.slice(0, lastDot);
4375
+ function logicProviders() {
4376
+ return [LogicFunctionCacheService];
4284
4377
  }
4285
- function resolveArrayItemScope(pathInfo, arrayItem) {
4286
- const relativePath = pathInfo.isArrayPath ? pathInfo.relativePath : '';
4287
- const innerParentPath = relativePath.includes('.') ? relativePath.slice(0, relativePath.lastIndexOf('.')) : '';
4288
- const groupValue = innerParentPath ? getNestedValue(arrayItem, innerParentPath) : arrayItem;
4289
- const fieldValue = relativePath ? getNestedValue(arrayItem, relativePath) : arrayItem;
4290
- return { relativePath, groupValue, fieldValue };
4378
+ function provideDynamicFormDI() {
4379
+ return [
4380
+ ...coreProviders(),
4381
+ ...logicProviders(),
4382
+ ...dynamicValueProviders(),
4383
+ ...httpExpressionProviders(),
4384
+ ...asyncExpressionProviders(),
4385
+ ...propertyDerivationProviders(),
4386
+ ...derivationProviders(),
4387
+ ];
4291
4388
  }
4292
4389
 
4293
- const MAX_DERIVATION_ITERATIONS = 10;
4294
- const ARRAY_PLACEHOLDER = '.$.';
4295
- const MAX_AST_CACHE_SIZE = 1000;
4296
- const DERIVATION_KEY_DELIMITER = '\x00';
4297
-
4298
- function resolveFieldInstance(rootForm, fieldPath) {
4299
- const parts = fieldPath.split('.');
4300
- let current = rootForm;
4301
- for (let i = 0; i < parts.length - 1; i++) {
4302
- const next = current[parts[i]];
4303
- if (!next)
4304
- return undefined;
4305
- current = next;
4306
- }
4307
- const fieldAccessor = current[parts[parts.length - 1]];
4308
- if (!fieldAccessor)
4309
- return undefined;
4310
- return untracked(fieldAccessor);
4311
- }
4312
- function readFieldDirty(rootForm, fieldPath) {
4313
- const fieldInstance = resolveFieldInstance(rootForm, fieldPath);
4314
- if (!fieldInstance)
4315
- return undefined;
4316
- return untracked(fieldInstance.dirty);
4317
- }
4318
- function resetFieldState(rootForm, fieldPath) {
4319
- const fieldInstance = resolveFieldInstance(rootForm, fieldPath);
4320
- if (!fieldInstance)
4321
- return;
4322
- fieldInstance.reset();
4323
- }
4324
- function applyValueToForm(targetPath, value, rootForm, logger, warningTracker) {
4325
- if (!targetPath.includes('.')) {
4326
- return setFieldValue(rootForm, targetPath, value, logger, warningTracker);
4327
- }
4328
- const parts = targetPath.split('.');
4329
- let current = rootForm;
4330
- for (let i = 0; i < parts.length - 1; i++) {
4331
- const part = parts[i];
4332
- if (part === '$') {
4333
- return false;
4334
- }
4335
- const next = current[part];
4336
- if (!next) {
4337
- warnMissingField(targetPath, logger, warningTracker);
4338
- return false; }
4339
- current = next;
4340
- }
4341
- const finalPart = parts[parts.length - 1];
4342
- return setFieldValue(current, finalPart, value, logger, warningTracker);
4343
- }
4344
- function setFieldValue(parent, fieldKey, value, logger, warningTracker) {
4345
- const fieldAccessor = parent[fieldKey];
4346
- if (!fieldAccessor) {
4347
- warnMissingField(fieldKey, logger, warningTracker);
4348
- return false;
4349
- }
4350
- const fieldInstance = untracked(fieldAccessor);
4351
- if (!fieldInstance || typeof fieldInstance !== 'object') {
4352
- warnMissingField(fieldKey, logger, warningTracker);
4353
- return false;
4354
- }
4355
- const valueSignal = fieldInstance.value;
4356
- if (isWritableSignal(valueSignal)) {
4357
- valueSignal.set(value);
4358
- return true;
4390
+ class EventDispatcher {
4391
+ bus;
4392
+ dispatch(event) {
4393
+ this.bus?.emitInstance(event);
4359
4394
  }
4360
- else {
4361
- warnMissingField(fieldKey, logger, warningTracker);
4362
- return false;
4395
+ connect(bus) {
4396
+ this.bus = bus;
4363
4397
  }
4364
- }
4365
- function warnMissingField(fieldKey, logger, warningTracker) {
4366
- if (warningTracker) {
4367
- if (warningTracker.warnedKeys.has(fieldKey)) {
4368
- return;
4369
- }
4370
- warningTracker.warnedKeys.add(fieldKey);
4398
+ disconnect() {
4399
+ this.bus = undefined;
4371
4400
  }
4372
- logger?.warn(`Derivation: target field '${fieldKey}' not found in form. ` +
4373
- `Ensure the field is defined in your form configuration. ` +
4374
- `This warning is shown once per field.`);
4401
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: EventDispatcher, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4402
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: EventDispatcher });
4375
4403
  }
4404
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: EventDispatcher, decorators: [{
4405
+ type: Injectable
4406
+ }] });
4376
4407
 
4377
- function applyDerivations(collection, context, changedFields) {
4378
- const chainContext = createDerivationChainContext();
4379
- chainContext.changedFields = changedFields;
4380
- chainContext.formFieldState = createFormFieldStateMap(context.rootForm, false);
4381
- const { derivationLogger } = context;
4382
- const maxIterations = context.maxIterations ?? MAX_DERIVATION_ITERATIONS;
4383
- let appliedCount = 0;
4384
- let skippedCount = 0;
4385
- let errorCount = 0;
4386
- let warnCount = 0;
4387
- const entriesToProcess = changedFields ? getEntriesForChangedFields$1(collection.entries, changedFields) : collection.entries;
4388
- derivationLogger.cycleStart('onChange', entriesToProcess.length);
4389
- let hasChanges = true;
4390
- while (hasChanges && chainContext.iteration < maxIterations) {
4391
- chainContext.iteration++;
4392
- hasChanges = false;
4393
- derivationLogger.iteration(chainContext.iteration);
4394
- for (const entry of entriesToProcess) {
4395
- const result = tryApplyDerivation(entry, context, chainContext);
4396
- if (result.applied) {
4397
- appliedCount++;
4398
- hasChanges = true;
4399
- }
4400
- else if (result.error) {
4401
- errorCount++;
4402
- }
4403
- else if (result.warning) {
4404
- warnCount++;
4405
- skippedCount++;
4406
- }
4407
- else {
4408
- skippedCount++;
4409
- }
4410
- }
4411
- }
4412
- const processingResult = {
4413
- appliedCount,
4414
- skippedCount,
4415
- errorCount,
4416
- warnCount,
4417
- iterations: chainContext.iteration,
4418
- maxIterationsReached: chainContext.iteration >= maxIterations,
4419
- };
4420
- if (processingResult.maxIterationsReached) {
4421
- derivationLogger.maxIterationsReached(processingResult, 'onChange');
4422
- }
4423
- derivationLogger.summary(processingResult, 'onChange');
4424
- return processingResult;
4425
- }
4426
- function getEntriesForChangedFields$1(entries, changedFields) {
4427
- return entries.filter((entry) => {
4428
- if (entry.dependsOn.length === 0 || entry.dependsOn.includes('*')) {
4429
- return true;
4430
- }
4431
- if (entry.dependsOn.some((dep) => changedFields.has(dep))) {
4432
- return true;
4433
- }
4434
- for (const changed of changedFields) {
4435
- if (entry.fieldKey.startsWith(changed + '.'))
4436
- return true;
4437
- if (entry.dependsOn.some((dep) => dep.startsWith(changed + '.')))
4438
- return true;
4439
- }
4440
- return false;
4441
- });
4408
+ class DfTemplate {
4409
+ dfTemplate = input.required(/* @ts-ignore */
4410
+ ...(ngDevMode ? [{ debugName: "dfTemplate" }] : /* istanbul ignore next */ []));
4411
+ templateRef = inject(TemplateRef);
4412
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfTemplate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
4413
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.0", type: DfTemplate, isStandalone: true, selector: "ng-template[dfTemplate]", inputs: { dfTemplate: { classPropertyName: "dfTemplate", publicName: "dfTemplate", isSignal: true, isRequired: true, transformFunction: null } }, exportAs: ["dfTemplate"], ngImport: i0 });
4442
4414
  }
4443
- function tryApplyDerivation(entry, context, chainContext) {
4444
- const { derivationLogger } = context;
4445
- if (entry.http || entry.asyncFunctionName || entry.asyncFn) {
4446
- return { applied: false, fieldKey: entry.fieldKey };
4447
- }
4448
- if (isArrayPlaceholderPath(entry.fieldKey)) {
4449
- return tryApplyArrayDerivation(entry, context, chainContext);
4450
- }
4451
- const derivationKey = createDerivationKey(entry.fieldKey);
4452
- if (chainContext.appliedDerivations.has(derivationKey)) {
4453
- derivationLogger.evaluation({
4454
- debugName: entry.debugName,
4455
- fieldKey: entry.fieldKey,
4456
- result: 'skipped',
4457
- skipReason: 'already-applied',
4458
- });
4459
- return { applied: false, fieldKey: entry.fieldKey };
4460
- }
4461
- if (shouldSkipForUserOverride(entry, entry.fieldKey, context, chainContext)) {
4462
- derivationLogger.evaluation({
4463
- debugName: entry.debugName,
4464
- fieldKey: entry.fieldKey,
4465
- result: 'skipped',
4466
- skipReason: 'user-override',
4467
- });
4468
- return { applied: false, fieldKey: entry.fieldKey };
4469
- }
4470
- const formValue = untracked(() => context.formValue());
4471
- const evalContext = createEvaluationContext$1(entry, formValue, context, chainContext);
4472
- if (!evaluateDerivationCondition(entry.condition, evalContext)) {
4473
- derivationLogger.evaluation({
4474
- debugName: entry.debugName,
4475
- fieldKey: entry.fieldKey,
4476
- result: 'skipped',
4477
- skipReason: 'condition-false',
4478
- });
4479
- return { applied: false, fieldKey: entry.fieldKey };
4480
- }
4481
- let newValue;
4482
- try {
4483
- newValue = computeDerivedValue(entry, evalContext, context);
4484
- }
4485
- catch (error) {
4486
- const errorMessage = error instanceof Error ? error.message : String(error);
4487
- context.logger.error(formatDerivationError(entry, 'compute', errorMessage));
4488
- derivationLogger.evaluation({
4489
- debugName: entry.debugName,
4490
- fieldKey: entry.fieldKey,
4491
- result: 'error',
4492
- error: errorMessage,
4493
- });
4494
- return {
4495
- applied: false,
4496
- fieldKey: entry.fieldKey,
4497
- error: errorMessage,
4498
- };
4499
- }
4500
- const currentValue = getNestedValue(formValue, entry.fieldKey);
4501
- if (isEqual(currentValue, newValue)) {
4502
- derivationLogger.evaluation({
4503
- debugName: entry.debugName,
4504
- fieldKey: entry.fieldKey,
4505
- result: 'skipped',
4506
- skipReason: 'value-unchanged',
4507
- });
4508
- return { applied: false, fieldKey: entry.fieldKey };
4415
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfTemplate, decorators: [{
4416
+ type: Directive,
4417
+ args: [{
4418
+ selector: 'ng-template[dfTemplate]',
4419
+ exportAs: 'dfTemplate',
4420
+ }]
4421
+ }], propDecorators: { dfTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "dfTemplate", required: true }] }] } });
4422
+ class DfFieldTemplateRegistry {
4423
+ _map = signal(new Map(), /* @ts-ignore */
4424
+ ...(ngDevMode ? [{ debugName: "_map" }] : /* istanbul ignore next */ []));
4425
+ map = this._map.asReadonly();
4426
+ set(value) {
4427
+ this._map.set(value);
4509
4428
  }
4510
- try {
4511
- const wasApplied = applyValueToForm(entry.fieldKey, newValue, context.rootForm, context.logger, context.warningTracker);
4512
- if (wasApplied) {
4513
- chainContext.appliedDerivations.add(derivationKey);
4514
- derivationLogger.evaluation({
4515
- debugName: entry.debugName,
4516
- fieldKey: entry.fieldKey,
4517
- result: 'applied',
4518
- previousValue: currentValue,
4519
- newValue,
4520
- });
4521
- return { applied: true, fieldKey: entry.fieldKey, newValue };
4522
- }
4523
- else {
4524
- derivationLogger.evaluation({
4525
- debugName: entry.debugName,
4526
- fieldKey: entry.fieldKey,
4527
- result: 'skipped',
4528
- skipReason: 'target-not-found',
4529
- });
4530
- return {
4531
- applied: false,
4532
- fieldKey: entry.fieldKey,
4533
- warning: `Field '${entry.fieldKey}' not found`,
4534
- };
4535
- }
4536
- }
4537
- catch (error) {
4538
- const errorMessage = error instanceof Error ? error.message : String(error);
4539
- context.logger.error(formatDerivationError(entry, 'apply', errorMessage));
4540
- derivationLogger.evaluation({
4541
- debugName: entry.debugName,
4542
- fieldKey: entry.fieldKey,
4543
- result: 'error',
4544
- error: errorMessage,
4545
- });
4546
- return {
4547
- applied: false,
4548
- fieldKey: entry.fieldKey,
4549
- error: errorMessage,
4550
- };
4551
- }
4552
- }
4553
- function tryApplyArrayDerivation(entry, context, chainContext) {
4554
- const formValue = untracked(() => context.formValue());
4555
- const pathInfo = parseArrayPath(entry.fieldKey);
4556
- if (!pathInfo.isArrayPath) {
4557
- return { applied: false, fieldKey: entry.fieldKey, error: 'Invalid array derivation path' };
4558
- }
4559
- const { arrayPath } = pathInfo;
4560
- const arrayValue = getNestedValue(formValue, arrayPath);
4561
- if (!Array.isArray(arrayValue)) {
4562
- return { applied: false, fieldKey: entry.fieldKey };
4563
- }
4564
- let appliedAny = false;
4565
- for (let i = 0; i < arrayValue.length; i++) {
4566
- const resolvedPath = resolveArrayPath(entry.fieldKey, i);
4567
- const derivationKey = createDerivationKey(resolvedPath);
4568
- if (chainContext.appliedDerivations.has(derivationKey)) {
4569
- continue;
4570
- }
4571
- if (shouldSkipForUserOverride(entry, resolvedPath, context, chainContext)) {
4572
- context.derivationLogger.evaluation({
4573
- debugName: entry.debugName,
4574
- fieldKey: resolvedPath,
4575
- result: 'skipped',
4576
- skipReason: 'user-override',
4577
- });
4578
- continue;
4579
- }
4580
- const arrayItem = arrayValue[i];
4581
- const evalContext = createArrayItemEvaluationContext$1(entry, arrayItem, formValue, i, arrayPath, context, chainContext);
4582
- if (!evaluateDerivationCondition(entry.condition, evalContext)) {
4583
- continue;
4584
- }
4585
- let newValue;
4586
- try {
4587
- newValue = computeDerivedValue(entry, evalContext, context);
4588
- }
4589
- catch (error) {
4590
- const errorMessage = error instanceof Error ? error.message : String(error);
4591
- context.logger.error(formatDerivationError(entry, 'compute', `[index ${i}] ${errorMessage}`));
4592
- continue;
4593
- }
4594
- const currentValue = getNestedValue(formValue, resolvedPath);
4595
- if (isEqual(currentValue, newValue)) {
4596
- continue;
4597
- }
4598
- try {
4599
- applyValueToForm(resolvedPath, newValue, context.rootForm, context.logger, context.warningTracker);
4600
- chainContext.appliedDerivations.add(derivationKey);
4601
- appliedAny = true;
4602
- }
4603
- catch (error) {
4604
- const errorMessage = error instanceof Error ? error.message : String(error);
4605
- context.logger.error(formatDerivationError(entry, 'apply', `[index ${i}] ${errorMessage}`));
4606
- }
4607
- }
4608
- return { applied: appliedAny, fieldKey: entry.fieldKey };
4609
- }
4610
- function createEvaluationContext$1(entry, formValue, context, chainContext) {
4611
- const fieldValue = getNestedValue(formValue, entry.fieldKey);
4612
- const fieldAccessor = context.rootForm[entry.fieldKey];
4613
- const fieldState = fieldAccessor ? readFieldStateInfo(fieldAccessor, false) : undefined;
4614
- const parentPath = getParentPathInScope(entry.fieldKey);
4615
- const groupValue = parentPath ? getNestedValue(formValue, parentPath) : undefined;
4616
- return {
4617
- fieldValue,
4618
- formValue,
4619
- fieldPath: entry.fieldKey,
4620
- groupValue,
4621
- customFunctions: context.customFunctions,
4622
- externalData: context.externalData,
4623
- logger: context.logger,
4624
- fieldState,
4625
- formFieldState: chainContext.formFieldState,
4626
- };
4627
- }
4628
- function createArrayItemEvaluationContext$1(entry, arrayItem, rootFormValue, itemIndex, arrayPath, context, chainContext) {
4629
- const pathInfo = parseArrayPath(entry.fieldKey);
4630
- let fieldState;
4631
- if (pathInfo.isArrayPath && pathInfo.relativePath) {
4632
- const rootFormRecord = context.rootForm;
4633
- const arrayAccessor = rootFormRecord[arrayPath];
4634
- if (arrayAccessor) {
4635
- const arrayItems = arrayAccessor;
4636
- const itemAccessor = arrayItems[String(itemIndex)];
4637
- if (itemAccessor) {
4638
- const itemFields = itemAccessor;
4639
- const fieldAccessor = itemFields[pathInfo.relativePath];
4640
- if (fieldAccessor) {
4641
- fieldState = readFieldStateInfo(fieldAccessor, false);
4642
- }
4643
- }
4644
- }
4645
- }
4646
- const { relativePath, groupValue, fieldValue } = resolveArrayItemScope(pathInfo, arrayItem);
4647
- return {
4648
- fieldValue,
4649
- formValue: arrayItem,
4650
- fieldPath: relativePath ? `${arrayPath}.${itemIndex}.${relativePath}` : `${arrayPath}.${itemIndex}`,
4651
- groupValue,
4652
- customFunctions: context.customFunctions,
4653
- externalData: context.externalData,
4654
- logger: context.logger,
4655
- rootFormValue,
4656
- arrayIndex: itemIndex,
4657
- arrayPath,
4658
- fieldState,
4659
- formFieldState: chainContext.formFieldState,
4660
- };
4661
- }
4662
- function evaluateDerivationCondition(condition, context) {
4663
- if (typeof condition === 'boolean') {
4664
- return condition;
4665
- }
4666
- return evaluateCondition(condition, context);
4667
- }
4668
- function computeDerivedValue(entry, evalContext, applicatorContext) {
4669
- return computeValueFromEntry(entry, evalContext, {
4670
- derivationFunctions: applicatorContext.derivationFunctions,
4671
- subject: entry.fieldKey,
4672
- });
4673
- }
4674
- const ERROR_PREFIX$1 = '[Derivation]';
4675
- function formatDerivationError(entry, phase, message) {
4676
- const source = entry.expression
4677
- ? `expression: "${entry.expression.substring(0, 50)}${entry.expression.length > 50 ? '...' : ''}"`
4678
- : entry.functionName
4679
- ? `function: "${entry.functionName}"`
4680
- : entry.fn
4681
- ? 'inline fn'
4682
- : entry.value !== undefined
4683
- ? 'static value'
4684
- : 'unknown source';
4685
- return `${ERROR_PREFIX$1} Failed to ${phase} derivation (field: ${entry.fieldKey}, ${source}): ${message}`;
4686
- }
4687
- function hasDependencyChanged(entry, changedFields) {
4688
- return entry.dependsOn.some((dep) => dep === '*' || changedFields.has(dep));
4689
- }
4690
- function shouldSkipForUserOverride(entry, resolvedFieldKey, context, chainContext) {
4691
- if (!entry.stopOnUserOverride)
4692
- return false;
4693
- const isDirty = readFieldDirty(context.rootForm, resolvedFieldKey) ?? false;
4694
- if (!isDirty)
4695
- return false;
4696
- if (entry.reEngageOnDependencyChange && chainContext.changedFields) {
4697
- if (hasDependencyChanged(entry, chainContext.changedFields)) {
4698
- resetFieldState(context.rootForm, resolvedFieldKey);
4699
- return false;
4700
- }
4701
- }
4702
- return true;
4703
- }
4704
- function applyDerivationsForTrigger(collection, trigger, context, changedFields) {
4705
- const filteredEntries = collection.entries.filter((entry) => {
4706
- if (entry.http || entry.asyncFunctionName || entry.asyncFn)
4707
- return false;
4708
- if (trigger === 'onChange') {
4709
- return !entry.trigger || entry.trigger === 'onChange';
4710
- }
4711
- return entry.trigger === trigger;
4712
- });
4713
- const filteredCollection = {
4714
- entries: filteredEntries,
4715
- };
4716
- return applyDerivations(filteredCollection, context, changedFields);
4717
- }
4718
- function getDebouncedDerivationEntries(collection) {
4719
- return collection.entries.filter((entry) => entry.trigger === 'debounced');
4720
- }
4721
-
4722
- function topologicalSort(entries) {
4723
- if (entries.length <= 1) {
4724
- return [...entries];
4725
- }
4726
- const graph = new Map();
4727
- const inDegree = new Map();
4728
- for (const entry of entries) {
4729
- graph.set(entry, new Set());
4730
- inDegree.set(entry, 0);
4731
- }
4732
- const derivationsByField = new Map();
4733
- for (const entry of entries) {
4734
- const fieldEntries = derivationsByField.get(entry.fieldKey) ?? [];
4735
- fieldEntries.push(entry);
4736
- derivationsByField.set(entry.fieldKey, fieldEntries);
4737
- if (entry.fieldKey.includes('.$.')) {
4738
- const relativePath = entry.fieldKey.split('.$.')[1];
4739
- if (relativePath) {
4740
- const relativeEntries = derivationsByField.get(relativePath) ?? [];
4741
- relativeEntries.push(entry);
4742
- derivationsByField.set(relativePath, relativeEntries);
4743
- }
4744
- }
4745
- }
4746
- const wildcardDependents = [];
4747
- for (const entry of entries) {
4748
- if (entry.dependsOn.includes('*')) {
4749
- wildcardDependents.push(entry);
4750
- }
4751
- }
4752
- for (const entryB of entries) {
4753
- for (const dep of entryB.dependsOn) {
4754
- if (dep === '*')
4755
- continue;
4756
- const producers = derivationsByField.get(dep);
4757
- if (producers) {
4758
- for (const entryA of producers) {
4759
- const entryAEdges = graph.get(entryA);
4760
- if (entryA !== entryB && entryAEdges && !entryAEdges.has(entryB)) {
4761
- entryAEdges.add(entryB);
4762
- inDegree.set(entryB, (inDegree.get(entryB) ?? 0) + 1);
4763
- }
4764
- }
4765
- }
4766
- }
4767
- }
4768
- for (const entryB of wildcardDependents) {
4769
- for (const entryA of entries) {
4770
- const entryAEdges = graph.get(entryA);
4771
- if (entryA !== entryB && entryAEdges && !entryAEdges.has(entryB)) {
4772
- entryAEdges.add(entryB);
4773
- inDegree.set(entryB, (inDegree.get(entryB) ?? 0) + 1);
4774
- }
4775
- }
4776
- }
4777
- const queue = [];
4778
- const sorted = [];
4779
- for (const entry of entries) {
4780
- if (inDegree.get(entry) === 0) {
4781
- queue.push(entry);
4782
- }
4783
- }
4784
- while (queue.length > 0) {
4785
- const current = queue.shift();
4786
- if (!current)
4787
- break; sorted.push(current);
4788
- const neighbors = graph.get(current) ?? new Set();
4789
- for (const neighbor of neighbors) {
4790
- const newDegree = (inDegree.get(neighbor) ?? 0) - 1;
4791
- inDegree.set(neighbor, newDegree);
4792
- if (newDegree === 0) {
4793
- queue.push(neighbor);
4794
- }
4795
- }
4796
- }
4797
- if (sorted.length !== entries.length) {
4798
- const sortedSet = new Set(sorted);
4799
- for (const entry of entries) {
4800
- if (!sortedSet.has(entry)) {
4801
- sorted.push(entry);
4802
- }
4803
- }
4804
- }
4805
- return sorted;
4806
- }
4807
-
4808
- function extractDependenciesFromConfig(config) {
4809
- const deps = new Set();
4810
- if (config.dependsOn && config.dependsOn.length > 0) {
4811
- config.dependsOn.forEach((dep) => deps.add(dep));
4812
- }
4813
- else {
4814
- if (config.expression) {
4815
- extractStringDependencies(config.expression).forEach((dep) => deps.add(dep));
4816
- }
4817
- if (config.functionName || config.fn) {
4818
- deps.add('*');
4819
- }
4820
- }
4821
- if (config.condition && config.condition !== true) {
4822
- extractExpressionDependencies(config.condition).forEach((dep) => deps.add(dep));
4823
- }
4824
- return Array.from(deps);
4825
- }
4826
-
4827
- function extractInlineFn(config) {
4828
- return config.fn;
4829
- }
4830
- function extractInlineAsyncFn(config) {
4831
- return config.asyncFn;
4832
- }
4833
-
4834
- function traverseFieldsWithContext(fields, context, visitor, hooks) {
4835
- for (const field of fields) {
4836
- visitor(field, context);
4837
- if (!hasChildFields(field))
4838
- continue;
4839
- if (field.type === 'array') {
4840
- const childContext = mergeContext(context, hooks?.onArrayChild?.(context, field));
4841
- const arrayChildren = collectArrayChildren(field);
4842
- traverseFieldsWithContext(arrayChildren, childContext, visitor, hooks);
4843
- continue;
4844
- }
4845
- const overrides = field.type === 'group' ? hooks?.onGroupChild?.(context, field) : hooks?.onLayoutChild?.(context, field);
4846
- const childContext = mergeContext(context, overrides);
4847
- traverseFieldsWithContext(normalizeFieldsArray(field.fields), childContext, visitor, hooks);
4848
- }
4849
- }
4850
- function collectArrayChildren(field) {
4851
- let arrayItems = normalizeFieldsArray(field.fields);
4852
- if (arrayItems.length === 0) {
4853
- const metadataTemplate = getNormalizedArrayMetadata(field)?.template;
4854
- if (metadataTemplate) {
4855
- arrayItems = [
4856
- Array.isArray(metadataTemplate) ? [...metadataTemplate] : metadataTemplate,
4857
- ];
4858
- }
4859
- }
4860
- const flattened = [];
4861
- for (const item of arrayItems) {
4862
- if (Array.isArray(item)) {
4863
- flattened.push(...item);
4864
- }
4865
- else {
4866
- flattened.push(item);
4867
- }
4868
- }
4869
- return flattened;
4870
- }
4871
- function mergeContext(base, overrides) {
4872
- return overrides ? { ...base, ...overrides } : { ...base };
4873
- }
4874
-
4875
- const SELF_DEPENDENCY_TOKEN = '$self';
4876
- const GROUP_DEPENDENCY_TOKEN = '$group';
4877
- function buildEffectiveFieldKey(fieldKey, context) {
4878
- if (context.arrayPath && context.groupPath) {
4879
- return `${context.arrayPath}.$.${context.groupPath}.${fieldKey}`;
4880
- }
4881
- if (context.arrayPath) {
4882
- return `${context.arrayPath}.$.${fieldKey}`;
4883
- }
4884
- if (context.groupPath) {
4885
- return `${context.groupPath}.${fieldKey}`;
4886
- }
4887
- return fieldKey;
4888
- }
4889
- function buildNearestGroupPath(context) {
4890
- if (context.arrayPath && context.groupPath) {
4891
- return `${context.arrayPath}.$.${context.groupPath}`;
4892
- }
4893
- return context.arrayPath ?? context.groupPath;
4894
- }
4895
- function resolveTokenDependencies(deps, effectiveFieldKey, context) {
4896
- return deps.map((dep) => {
4897
- if (dep === SELF_DEPENDENCY_TOKEN) {
4898
- return effectiveFieldKey;
4899
- }
4900
- if (dep.startsWith(`${SELF_DEPENDENCY_TOKEN}.`)) {
4901
- return effectiveFieldKey + dep.slice(SELF_DEPENDENCY_TOKEN.length);
4902
- }
4903
- if (dep === GROUP_DEPENDENCY_TOKEN || dep.startsWith(`${GROUP_DEPENDENCY_TOKEN}.`)) {
4904
- const groupPath = buildNearestGroupPath(context);
4905
- if (!groupPath) {
4906
- throw new DynamicFormError(`Derivation for '${effectiveFieldKey}' uses '${dep}' but the field has no parent group or array. ` +
4907
- `'${GROUP_DEPENDENCY_TOKEN}' is only valid for fields nested inside a group or array container.`);
4908
- }
4909
- if (dep === GROUP_DEPENDENCY_TOKEN)
4910
- return groupPath;
4911
- return groupPath + dep.slice(GROUP_DEPENDENCY_TOKEN.length);
4912
- }
4913
- return dep;
4914
- });
4915
- }
4916
- const CONTEXT_TRAVERSAL_OPTIONS = {
4917
- onArrayChild: (_parent, field) => ({ arrayPath: field.key, groupPath: undefined }),
4918
- onGroupChild: (parent, field) => {
4919
- if (!field.key)
4920
- return {};
4921
- return { groupPath: parent.groupPath ? `${parent.groupPath}.${field.key}` : field.key };
4922
- },
4923
- };
4924
-
4925
- function collectDerivations(fields) {
4926
- const entries = [];
4927
- traverseFieldsWithContext(fields, {}, (field, context) => collectValueEntriesFromField(field, entries, context), CONTEXT_TRAVERSAL_OPTIONS);
4928
- return { entries: topologicalSort(entries) };
4929
- }
4930
- function collectAllDerivations(fields) {
4931
- const valueEntries = [];
4932
- const propertyEntries = [];
4933
- traverseFieldsWithContext(fields, {}, (field, context) => {
4934
- collectValueEntriesFromField(field, valueEntries, context);
4935
- collectPropertyEntriesFromField(field, propertyEntries, context);
4936
- }, CONTEXT_TRAVERSAL_OPTIONS);
4937
- return {
4938
- value: { entries: topologicalSort(valueEntries) },
4939
- property: { entries: propertyEntries },
4940
- };
4941
- }
4942
- function collectValueEntriesFromField(field, entries, context) {
4943
- const fieldKey = field.key;
4944
- if (!fieldKey)
4945
- return;
4946
- const validationField = field;
4947
- if (validationField.derivation) {
4948
- entries.push(createShorthandEntry(fieldKey, validationField.derivation, context));
4949
- }
4950
- if (validationField.logic) {
4951
- for (const logicConfig of validationField.logic) {
4952
- if (!isDerivationLogicConfig(logicConfig))
4953
- continue;
4954
- if (hasTargetProperty(logicConfig))
4955
- continue; entries.push(createValueLogicEntry(fieldKey, logicConfig, context));
4956
- }
4957
- }
4958
- }
4959
- function collectPropertyEntriesFromField(field, entries, context) {
4960
- const fieldKey = field.key;
4961
- if (!fieldKey)
4962
- return;
4963
- const validationField = field;
4964
- if (!validationField.logic)
4965
- return;
4966
- for (const logicConfig of validationField.logic) {
4967
- if (!isDerivationLogicConfig(logicConfig))
4968
- continue;
4969
- if (!hasTargetProperty(logicConfig))
4970
- continue;
4971
- entries.push(createPropertyLogicEntry(fieldKey, logicConfig, context));
4972
- }
4973
- }
4974
- function createShorthandEntry(fieldKey, expression, context) {
4975
- const effectiveFieldKey = buildEffectiveFieldKey(fieldKey, context);
4976
- return {
4977
- fieldKey: effectiveFieldKey,
4978
- dependsOn: extractStringDependencies(expression),
4979
- condition: true,
4980
- expression,
4981
- trigger: 'onChange',
4982
- isShorthand: true,
4983
- };
4984
- }
4985
- function createValueLogicEntry(fieldKey, config, context) {
4986
- const effectiveFieldKey = buildEffectiveFieldKey(fieldKey, context);
4987
- if (config.source === 'http') {
4988
- if (config.dependsOn.length === 0) {
4989
- throw new DynamicFormError(`HTTP derivation for '${effectiveFieldKey}' requires explicit 'dependsOn'. ` +
4990
- `Wildcard dependencies would trigger HTTP requests on every form change.`);
4991
- }
4992
- if (config.dependsOn.includes('*')) {
4993
- throw new DynamicFormError(`HTTP derivation for '${effectiveFieldKey}' cannot use wildcard ('*') in 'dependsOn'. ` +
4994
- `Wildcards would trigger HTTP requests on every form change. Specify explicit field dependencies instead.`);
4995
- }
4996
- }
4997
- if (config.source === 'asyncFunction') {
4998
- if (config.dependsOn.length === 0) {
4999
- throw new DynamicFormError(`Async derivation for '${effectiveFieldKey}' requires explicit 'dependsOn'. ` +
5000
- `Wildcard dependencies would trigger async functions on every form change.`);
5001
- }
5002
- if (config.dependsOn.includes('*')) {
5003
- throw new DynamicFormError(`Async derivation for '${effectiveFieldKey}' cannot use wildcard ('*') in 'dependsOn'. ` +
5004
- `Wildcards would trigger async functions on every form change. Specify explicit field dependencies instead.`);
5005
- }
5006
- }
5007
- const dependsOn = resolveTokenDependencies(extractDependenciesFromConfig(config), effectiveFieldKey, context);
5008
- const condition = config.condition ?? true;
5009
- const trigger = config.trigger ?? 'onChange';
5010
- const debounceMs = trigger === 'debounced' ? config.debounceMs : undefined;
5011
- return {
5012
- fieldKey: effectiveFieldKey,
5013
- dependsOn,
5014
- condition,
5015
- value: config.value,
5016
- expression: config.expression,
5017
- functionName: config.functionName,
5018
- fn: extractInlineFn(config),
5019
- http: config.http,
5020
- responseExpression: config.responseExpression,
5021
- asyncFunctionName: config.asyncFunctionName,
5022
- asyncFn: extractInlineAsyncFn(config),
5023
- trigger,
5024
- debounceMs,
5025
- isShorthand: false,
5026
- originalConfig: config,
5027
- debugName: config.debugName,
5028
- stopOnUserOverride: config.stopOnUserOverride,
5029
- reEngageOnDependencyChange: config.reEngageOnDependencyChange,
5030
- };
5031
- }
5032
- function createPropertyLogicEntry(fieldKey, config, context) {
5033
- const effectiveFieldKey = buildEffectiveFieldKey(fieldKey, context);
5034
- const errorLocation = `'${effectiveFieldKey}.${config.targetProperty}'`;
5035
- const untypedConfig = config;
5036
- if (untypedConfig.source === 'http' || untypedConfig.source === 'asyncFunction') {
5037
- const conflictingSyncSources = [];
5038
- if (untypedConfig.value !== undefined)
5039
- conflictingSyncSources.push('value');
5040
- if (untypedConfig.expression !== undefined)
5041
- conflictingSyncSources.push('expression');
5042
- if (untypedConfig.functionName !== undefined)
5043
- conflictingSyncSources.push('functionName');
5044
- if (untypedConfig.fn !== undefined)
5045
- conflictingSyncSources.push('fn');
5046
- if (conflictingSyncSources.length > 0) {
5047
- throw new DynamicFormError(`Property derivation for ${errorLocation} sets 'source: ${JSON.stringify(untypedConfig.source)}' alongside ` +
5048
- `sync value source(s) [${conflictingSyncSources.join(', ')}]. These are mutually exclusive — remove either ` +
5049
- `the sync fields or the async source.`);
5050
- }
5051
- }
5052
- if (untypedConfig.source === 'http' && (untypedConfig.asyncFunctionName !== undefined || untypedConfig.asyncFn !== undefined)) {
5053
- throw new DynamicFormError(`Property derivation for ${errorLocation} sets 'source: "http"' alongside an async function — these are mutually exclusive.`);
5054
- }
5055
- if (untypedConfig.source === 'asyncFunction' && (untypedConfig.http !== undefined || untypedConfig.responseExpression !== undefined)) {
5056
- throw new DynamicFormError(`Property derivation for ${errorLocation} sets 'source: "asyncFunction"' alongside HTTP fields — these are mutually exclusive.`);
5057
- }
5058
- if (untypedConfig.source === 'http') {
5059
- if (!untypedConfig.http) {
5060
- throw new DynamicFormError(`HTTP property derivation for ${errorLocation} requires an 'http' config object.`);
5061
- }
5062
- if (typeof untypedConfig.responseExpression !== 'string' || untypedConfig.responseExpression.trim() === '') {
5063
- throw new DynamicFormError(`HTTP property derivation for ${errorLocation} requires a non-empty 'responseExpression'.`);
5064
- }
5065
- if (!Array.isArray(untypedConfig.dependsOn) || untypedConfig.dependsOn.length === 0) {
5066
- throw new DynamicFormError(`HTTP property derivation for ${errorLocation} requires explicit 'dependsOn'. ` +
5067
- `Wildcard dependencies would trigger HTTP requests on every form change.`);
5068
- }
5069
- if (untypedConfig.dependsOn.includes('*')) {
5070
- throw new DynamicFormError(`HTTP property derivation for ${errorLocation} cannot use wildcard ('*') in 'dependsOn'. ` +
5071
- `Wildcards would trigger HTTP requests on every form change. Specify explicit field dependencies instead.`);
5072
- }
5073
- }
5074
- if (untypedConfig.source === 'asyncFunction') {
5075
- if (!untypedConfig.asyncFunctionName && !untypedConfig.asyncFn) {
5076
- throw new DynamicFormError(`Async property derivation for ${errorLocation} requires either 'asyncFunctionName' or 'asyncFn'.`);
5077
- }
5078
- if (!Array.isArray(untypedConfig.dependsOn) || untypedConfig.dependsOn.length === 0) {
5079
- throw new DynamicFormError(`Async property derivation for ${errorLocation} requires explicit 'dependsOn'. ` +
5080
- `Wildcard dependencies would trigger async functions on every form change.`);
5081
- }
5082
- if (untypedConfig.dependsOn.includes('*')) {
5083
- throw new DynamicFormError(`Async property derivation for ${errorLocation} cannot use wildcard ('*') in 'dependsOn'. ` +
5084
- `Wildcards would trigger async functions on every form change. Specify explicit field dependencies instead.`);
5085
- }
5086
- }
5087
- const dependsOn = resolveTokenDependencies(extractDependenciesFromConfig(config), effectiveFieldKey, context);
5088
- const condition = config.condition ?? true;
5089
- const trigger = config.trigger ?? 'onChange';
5090
- const debounceMs = trigger === 'debounced' ? config.debounceMs : undefined;
5091
- return {
5092
- fieldKey: effectiveFieldKey,
5093
- targetProperty: config.targetProperty,
5094
- dependsOn,
5095
- condition,
5096
- value: config.value,
5097
- expression: config.expression,
5098
- functionName: config.functionName,
5099
- fn: extractInlineFn(config),
5100
- http: config.http,
5101
- responseExpression: config.responseExpression,
5102
- asyncFunctionName: config.asyncFunctionName,
5103
- asyncFn: extractInlineAsyncFn(config),
5104
- trigger,
5105
- debounceMs,
5106
- debugName: config.debugName,
5107
- originalConfig: config,
5108
- };
5109
- }
5110
-
5111
- function collectPropertyDerivations(fields) {
5112
- return collectAllDerivations(fields).property;
5113
- }
5114
-
5115
- function detectCycles(collection) {
5116
- const graph = buildDependencyGraph(collection);
5117
- if (graph.size === 0) {
5118
- return { hasCycle: false };
5119
- }
5120
- const bidirectionalPairs = detectBidirectionalPairs(collection);
5121
- const result = detectCyclesWithDFS(graph, bidirectionalPairs);
5122
- if (bidirectionalPairs.size > 0) {
5123
- result.bidirectionalPairs = Array.from(bidirectionalPairs);
5124
- }
5125
- return result;
5126
- }
5127
- function detectBidirectionalPairs(collection) {
5128
- const pairs = new Set();
5129
- const dependencyMap = new Map();
5130
- for (const entry of collection.entries) {
5131
- const deps = dependencyMap.get(entry.fieldKey) ?? new Set();
5132
- for (const dep of entry.dependsOn) {
5133
- if (dep !== '*' && dep !== entry.fieldKey) {
5134
- deps.add(dep);
5135
- }
5136
- }
5137
- dependencyMap.set(entry.fieldKey, deps);
5138
- }
5139
- for (const [fieldA, depsA] of dependencyMap) {
5140
- for (const fieldB of depsA) {
5141
- const depsB = dependencyMap.get(fieldB);
5142
- if (depsB?.has(fieldA)) {
5143
- const pairKey = fieldA < fieldB ? `${fieldA}↔${fieldB}` : `${fieldB}↔${fieldA}`;
5144
- pairs.add(pairKey);
5145
- }
5146
- }
5147
- }
5148
- return pairs;
5149
- }
5150
- function isBidirectionalCycle(cyclePath, bidirectionalPairs) {
5151
- if (cyclePath.length !== 3) {
5152
- return false;
5153
- }
5154
- const [first, second, third] = cyclePath;
5155
- if (first !== third) {
5156
- return false;
5157
- }
5158
- const pairKey = first < second ? `${first}↔${second}` : `${second}↔${first}`;
5159
- return bidirectionalPairs.has(pairKey);
5160
- }
5161
- function buildDependencyGraph(collection) {
5162
- const graph = new Map();
5163
- const ensureNode = (fieldKey) => {
5164
- let node = graph.get(fieldKey);
5165
- if (!node) {
5166
- node = {
5167
- fieldKey,
5168
- dependsOn: new Set(),
5169
- dependedOnBy: new Set(),
5170
- };
5171
- graph.set(fieldKey, node);
5172
- }
5173
- return node;
5174
- };
5175
- for (const entry of collection.entries) {
5176
- const fieldNode = ensureNode(entry.fieldKey);
5177
- for (const dep of entry.dependsOn) {
5178
- if (dep !== '*' && dep !== entry.fieldKey) {
5179
- const depNode = ensureNode(dep);
5180
- fieldNode.dependsOn.add(dep);
5181
- depNode.dependedOnBy.add(entry.fieldKey);
5182
- }
5183
- }
5184
- }
5185
- return graph;
5186
- }
5187
- function detectCyclesWithDFS(graph, bidirectionalPairs) {
5188
- const visitState = new Map();
5189
- const parent = new Map();
5190
- for (const fieldKey of graph.keys()) {
5191
- visitState.set(fieldKey, 0 /* VisitState.Unvisited */);
5192
- }
5193
- for (const fieldKey of graph.keys()) {
5194
- if (visitState.get(fieldKey) === 0 /* VisitState.Unvisited */) {
5195
- const cycleResult = dfsVisit(fieldKey, graph, visitState, parent, [], bidirectionalPairs);
5196
- if (cycleResult) {
5197
- return cycleResult;
5198
- }
5199
- }
5200
- }
5201
- return { hasCycle: false };
5202
- }
5203
- function dfsVisit(fieldKey, graph, visitState, parent, path, bidirectionalPairs) {
5204
- visitState.set(fieldKey, 1 /* VisitState.InProgress */);
5205
- path.push(fieldKey);
5206
- const node = graph.get(fieldKey);
5207
- if (!node) {
5208
- visitState.set(fieldKey, 2 /* VisitState.Completed */);
5209
- path.pop();
5210
- return null;
5211
- }
5212
- for (const targetFieldKey of node.dependedOnBy) {
5213
- const targetState = visitState.get(targetFieldKey);
5214
- if (targetState === 1 /* VisitState.InProgress */) {
5215
- const cyclePath = extractCyclePath(path, targetFieldKey);
5216
- if (isBidirectionalCycle(cyclePath, bidirectionalPairs)) {
5217
- continue;
5218
- }
5219
- return {
5220
- hasCycle: true,
5221
- cyclePath,
5222
- errorMessage: formatCycleError(cyclePath),
5223
- };
5224
- }
5225
- if (targetState === 0 /* VisitState.Unvisited */) {
5226
- parent.set(targetFieldKey, fieldKey);
5227
- const result = dfsVisit(targetFieldKey, graph, visitState, parent, path, bidirectionalPairs);
5228
- if (result) {
5229
- return result;
5230
- }
5231
- }
5232
- }
5233
- visitState.set(fieldKey, 2 /* VisitState.Completed */);
5234
- path.pop();
5235
- return null;
5236
- }
5237
- function extractCyclePath(path, cycleStart) {
5238
- const cycleStartIndex = path.indexOf(cycleStart);
5239
- if (cycleStartIndex === -1) {
5240
- return [...path, cycleStart];
5241
- }
5242
- const cyclePath = path.slice(cycleStartIndex);
5243
- cyclePath.push(cycleStart); return cyclePath;
5244
- }
5245
- function formatCycleError(cyclePath) {
5246
- const pathStr = cyclePath.join(' -> ');
5247
- return (`Derivation cycle detected: ${pathStr}\n` +
5248
- `This would cause an infinite loop at runtime. ` +
5249
- `Remove one of the derivations to break the cycle.`);
5250
- }
5251
- function validateNoCycles(collection, logger) {
5252
- const result = detectCycles(collection);
5253
- if (result.hasCycle) {
5254
- throw new Error(result.errorMessage);
5255
- }
5256
- if (DEV_MODE && result.bidirectionalPairs && result.bidirectionalPairs.length > 0 && logger) {
5257
- logger.warn('Derivation: bidirectional derivation patterns detected. ' +
5258
- 'These patterns stabilize via equality checks, but may oscillate with floating-point values ' +
5259
- '(e.g., currency conversions with rounding). ' +
5260
- 'Consider adding tolerance-based comparisons for numeric values.', result.bidirectionalPairs);
5261
- }
5262
- }
5263
-
5264
- const LOG_PREFIX$3 = 'HTTP Derivation -';
5265
- const DEFAULT_HTTP_DEBOUNCE_MS$1 = 300;
5266
- function createHttpDerivationStream(entry, formValue$, context) {
5267
- if (isArrayPlaceholderPath(entry.fieldKey)) {
5268
- context.logger.warn(`${LOG_PREFIX$3} HTTP derivation for array field '${entry.fieldKey}' is not supported. ` +
5269
- `Array HTTP derivations will be supported in a future release.`);
5270
- return EMPTY;
5271
- }
5272
- if (!entry.http || !entry.responseExpression) {
5273
- return EMPTY;
5274
- }
5275
- const responseExpression = entry.responseExpression;
5276
- const debounceMs = entry.debounceMs ?? DEFAULT_HTTP_DEBOUNCE_MS$1;
5277
- return formValue$.pipe(startWith(null), pairwise(), map(([previous, current]) => ({
5278
- current: current,
5279
- changedFields: getChangedKeys(previous, current),
5280
- })),
5281
- filter(({ changedFields }) => {
5282
- if (changedFields.size === 0)
5283
- return false;
5284
- return entry.dependsOn.some((dep) => changedFields.has(dep));
5285
- }), debounceTime(debounceMs), switchMap(({ current, changedFields }) => {
5286
- return new Observable((subscriber) => {
5287
- const formAccessor = untracked(() => context.form());
5288
- if (entry.stopOnUserOverride) {
5289
- const isDirty = readFieldDirty(formAccessor, entry.fieldKey);
5290
- if (isDirty) {
5291
- if (entry.reEngageOnDependencyChange && changedFields.size > 0) {
5292
- if (entry.dependsOn.some((dep) => changedFields.has(dep))) {
5293
- resetFieldState(formAccessor, entry.fieldKey);
5294
- }
5295
- else {
5296
- const derivationLogger = untracked(() => context.derivationLogger());
5297
- derivationLogger.evaluation({
5298
- debugName: entry.debugName,
5299
- fieldKey: entry.fieldKey,
5300
- result: 'skipped',
5301
- skipReason: 'user-override',
5302
- });
5303
- subscriber.complete();
5304
- return;
5305
- }
5306
- }
5307
- else {
5308
- const derivationLogger = untracked(() => context.derivationLogger());
5309
- derivationLogger.evaluation({
5310
- debugName: entry.debugName,
5311
- fieldKey: entry.fieldKey,
5312
- result: 'skipped',
5313
- skipReason: 'user-override',
5314
- });
5315
- subscriber.complete();
5316
- return;
5317
- }
5318
- }
5319
- }
5320
- const customFunctions = context.customFunctions?.();
5321
- const externalData = context.externalData?.();
5322
- const fieldValue = getNestedValue(current, entry.fieldKey);
5323
- const fieldAccessor = formAccessor[entry.fieldKey];
5324
- const fieldState = fieldAccessor ? readFieldStateInfo(fieldAccessor, false) : undefined;
5325
- const evalContext = {
5326
- fieldValue,
5327
- formValue: current,
5328
- fieldPath: entry.fieldKey,
5329
- customFunctions,
5330
- externalData,
5331
- logger: context.logger,
5332
- fieldState,
5333
- formFieldState: createFormFieldStateMap(formAccessor, false),
5334
- };
5335
- if (entry.condition !== true) {
5336
- const conditionMet = typeof entry.condition === 'boolean' ? entry.condition : evaluateCondition(entry.condition, evalContext);
5337
- if (!conditionMet) {
5338
- const derivationLogger = untracked(() => context.derivationLogger());
5339
- derivationLogger.evaluation({
5340
- debugName: entry.debugName,
5341
- fieldKey: entry.fieldKey,
5342
- result: 'skipped',
5343
- skipReason: 'condition-false',
5344
- });
5345
- subscriber.complete();
5346
- return;
5347
- }
5348
- }
5349
- const resolvedRequest = resolveHttpRequest(entry.http, evalContext);
5350
- if (!resolvedRequest) {
5351
- const derivationLogger = untracked(() => context.derivationLogger());
5352
- derivationLogger.evaluation({
5353
- debugName: entry.debugName,
5354
- fieldKey: entry.fieldKey,
5355
- result: 'skipped',
5356
- skipReason: 'condition-false',
5357
- });
5358
- subscriber.complete();
5359
- return;
5360
- }
5361
- const method = (resolvedRequest.method ?? 'GET').toUpperCase();
5362
- const httpSub = context.httpClient
5363
- .request(method, resolvedRequest.url, {
5364
- body: resolvedRequest.body,
5365
- headers: resolvedRequest.headers,
5366
- })
5367
- .subscribe({
5368
- next: (response) => {
5369
- try {
5370
- const newValue = ExpressionParser.evaluate(responseExpression, { response });
5371
- const currentFormValue = untracked(() => context.formValue());
5372
- const currentValue = getNestedValue(currentFormValue, entry.fieldKey);
5373
- if (isEqual(currentValue, newValue)) {
5374
- const derivationLogger = untracked(() => context.derivationLogger());
5375
- derivationLogger.evaluation({
5376
- debugName: entry.debugName,
5377
- fieldKey: entry.fieldKey,
5378
- result: 'skipped',
5379
- skipReason: 'value-unchanged',
5380
- });
5381
- subscriber.complete();
5382
- return;
5383
- }
5384
- const currentForm = untracked(() => context.form());
5385
- if (entry.stopOnUserOverride && readFieldDirty(currentForm, entry.fieldKey)) {
5386
- const derivationLogger = untracked(() => context.derivationLogger());
5387
- derivationLogger.evaluation({
5388
- debugName: entry.debugName,
5389
- fieldKey: entry.fieldKey,
5390
- result: 'skipped',
5391
- skipReason: 'user-override',
5392
- });
5393
- subscriber.complete();
5394
- return;
5395
- }
5396
- applyValueToForm(entry.fieldKey, newValue, currentForm, context.logger, context.warningTracker);
5397
- const derivationLogger = untracked(() => context.derivationLogger());
5398
- derivationLogger.evaluation({
5399
- debugName: entry.debugName,
5400
- fieldKey: entry.fieldKey,
5401
- result: 'applied',
5402
- previousValue: currentValue,
5403
- newValue,
5404
- });
5405
- subscriber.complete();
5406
- }
5407
- catch (error) {
5408
- const message = error instanceof Error ? error.message : String(error);
5409
- context.logger.warn(`${LOG_PREFIX$3} Failed to process response for '${entry.fieldKey}': ${message}`);
5410
- subscriber.complete();
5411
- }
5412
- },
5413
- error: (error) => {
5414
- const message = error instanceof Error ? error.message : String(error);
5415
- context.logger.warn(`${LOG_PREFIX$3} HTTP request failed for '${entry.fieldKey}': ${message}`);
5416
- subscriber.complete();
5417
- },
5418
- });
5419
- return () => {
5420
- httpSub.unsubscribe();
5421
- };
5422
- });
5423
- }), catchError$1((error) => {
5424
- const message = error instanceof Error ? error.message : String(error);
5425
- context.logger.warn(`${LOG_PREFIX$3} Unexpected stream error for '${entry.fieldKey}': ${message}`);
5426
- return EMPTY;
5427
- }));
5428
- }
5429
-
5430
- const LOG_PREFIX$2 = 'Async Derivation -';
5431
- const DEFAULT_ASYNC_DEBOUNCE_MS$1 = 300;
5432
- function createAsyncDerivationStream(entry, formValue$, context) {
5433
- if (isArrayPlaceholderPath(entry.fieldKey)) {
5434
- context.logger.warn(`${LOG_PREFIX$2} Async derivation for array field '${entry.fieldKey}' is not supported. ` +
5435
- `Array async derivations will be supported in a future release.`);
5436
- return EMPTY;
5437
- }
5438
- if (!entry.asyncFunctionName && !entry.asyncFn) {
5439
- context.logger.warn(`${LOG_PREFIX$2} Derivation for '${entry.fieldKey}' has neither "asyncFunctionName" nor "asyncFn". ` +
5440
- `One of the two is required for source: 'asyncFunction'.`);
5441
- return EMPTY;
5442
- }
5443
- if (entry.asyncFn && entry.asyncFunctionName) {
5444
- context.logger.warn(`${LOG_PREFIX$2} Both "asyncFn" and "asyncFunctionName" are set on derivation for '${entry.fieldKey}'. ` +
5445
- `Inline "asyncFn" takes precedence; "asyncFunctionName" is ignored.`);
5446
- }
5447
- const inlineAsyncFn = entry.asyncFn;
5448
- const asyncFunctionName = entry.asyncFunctionName;
5449
- const debounceMs = entry.debounceMs ?? DEFAULT_ASYNC_DEBOUNCE_MS$1;
5450
- return formValue$.pipe(startWith(null), pairwise(), map(([previous, current]) => ({
5451
- current: current,
5452
- changedFields: getChangedKeys(previous, current),
5453
- })),
5454
- filter(({ changedFields }) => {
5455
- if (changedFields.size === 0)
5456
- return false;
5457
- return entry.dependsOn.some((dep) => changedFields.has(dep));
5458
- }), debounceTime(debounceMs), switchMap(({ current, changedFields }) => {
5459
- return new Observable((subscriber) => {
5460
- const formAccessor = untracked(() => context.form());
5461
- if (entry.stopOnUserOverride) {
5462
- const isDirty = readFieldDirty(formAccessor, entry.fieldKey);
5463
- if (isDirty) {
5464
- if (entry.reEngageOnDependencyChange) {
5465
- resetFieldState(formAccessor, entry.fieldKey);
5466
- }
5467
- else {
5468
- const derivationLogger = untracked(() => context.derivationLogger());
5469
- derivationLogger.evaluation({
5470
- debugName: entry.debugName,
5471
- fieldKey: entry.fieldKey,
5472
- result: 'skipped',
5473
- skipReason: 'user-override',
5474
- });
5475
- subscriber.complete();
5476
- return;
5477
- }
5478
- }
5479
- }
5480
- const customFunctions = context.customFunctions?.();
5481
- const asyncDerivationFunctions = context.asyncDerivationFunctions?.();
5482
- const externalData = context.externalData?.();
5483
- const asyncFn = inlineAsyncFn ?? (asyncFunctionName ? asyncDerivationFunctions?.[asyncFunctionName] : undefined);
5484
- if (!asyncFn) {
5485
- context.logger.warn(`${LOG_PREFIX$2} Async derivation function '${asyncFunctionName}' not found for field '${entry.fieldKey}'. ` +
5486
- `Register it in customFnConfig.asyncDerivations.`);
5487
- subscriber.complete();
5488
- return;
5489
- }
5490
- const fieldValue = getNestedValue(current, entry.fieldKey);
5491
- const fieldAccessor = formAccessor[entry.fieldKey];
5492
- const fieldState = fieldAccessor ? readFieldStateInfo(fieldAccessor, false) : undefined;
5493
- const evalContext = {
5494
- fieldValue,
5495
- formValue: current,
5496
- fieldPath: entry.fieldKey,
5497
- customFunctions,
5498
- externalData,
5499
- logger: context.logger,
5500
- fieldState,
5501
- formFieldState: createFormFieldStateMap(formAccessor, false),
5502
- };
5503
- if (entry.condition !== true) {
5504
- const conditionMet = typeof entry.condition === 'boolean' ? entry.condition : evaluateCondition(entry.condition, evalContext);
5505
- if (!conditionMet) {
5506
- const derivationLogger = untracked(() => context.derivationLogger());
5507
- derivationLogger.evaluation({
5508
- debugName: entry.debugName,
5509
- fieldKey: entry.fieldKey,
5510
- result: 'skipped',
5511
- skipReason: 'condition-false',
5512
- });
5513
- subscriber.complete();
5514
- return;
5515
- }
5516
- }
5517
- const result$ = from(asyncFn(evalContext));
5518
- const asyncSub = result$.subscribe({
5519
- next: (newValue) => {
5520
- try {
5521
- const currentFormValue = untracked(() => context.formValue());
5522
- const currentValue = getNestedValue(currentFormValue, entry.fieldKey);
5523
- if (isEqual(currentValue, newValue)) {
5524
- const derivationLogger = untracked(() => context.derivationLogger());
5525
- derivationLogger.evaluation({
5526
- debugName: entry.debugName,
5527
- fieldKey: entry.fieldKey,
5528
- result: 'skipped',
5529
- skipReason: 'value-unchanged',
5530
- });
5531
- subscriber.complete();
5532
- return;
5533
- }
5534
- const currentForm = untracked(() => context.form());
5535
- if (entry.stopOnUserOverride && readFieldDirty(currentForm, entry.fieldKey)) {
5536
- const derivationLogger = untracked(() => context.derivationLogger());
5537
- derivationLogger.evaluation({
5538
- debugName: entry.debugName,
5539
- fieldKey: entry.fieldKey,
5540
- result: 'skipped',
5541
- skipReason: 'user-override',
5542
- });
5543
- subscriber.complete();
5544
- return;
5545
- }
5546
- applyValueToForm(entry.fieldKey, newValue, currentForm, context.logger, context.warningTracker);
5547
- const derivationLogger = untracked(() => context.derivationLogger());
5548
- derivationLogger.evaluation({
5549
- debugName: entry.debugName,
5550
- fieldKey: entry.fieldKey,
5551
- result: 'applied',
5552
- previousValue: currentValue,
5553
- newValue,
5554
- });
5555
- subscriber.complete();
5556
- }
5557
- catch (error) {
5558
- const message = error instanceof Error ? error.message : String(error);
5559
- context.logger.warn(`${LOG_PREFIX$2} Failed to process result for '${entry.fieldKey}': ${message}`);
5560
- subscriber.complete();
5561
- }
5562
- },
5563
- error: (error) => {
5564
- const message = error instanceof Error ? error.message : String(error);
5565
- context.logger.warn(`${LOG_PREFIX$2} Async function failed for '${entry.fieldKey}': ${message}`);
5566
- subscriber.complete();
5567
- },
5568
- complete: () => {
5569
- subscriber.complete();
5570
- },
5571
- });
5572
- return () => {
5573
- asyncSub.unsubscribe();
5574
- };
5575
- });
5576
- }), catchError$1((error) => {
5577
- const message = error instanceof Error ? error.message : String(error);
5578
- context.logger.warn(`${LOG_PREFIX$2} Unexpected stream error for '${entry.fieldKey}': ${message}`);
5579
- return EMPTY;
5580
- }));
5581
- }
5582
-
5583
- function resolveExternalData(externalDataSignal) {
5584
- const externalDataRecord = untracked(() => externalDataSignal?.());
5585
- if (!externalDataRecord)
5586
- return undefined;
5587
- const resolved = {};
5588
- for (const [key, value] of Object.entries(externalDataRecord)) {
5589
- if (isSignal(value)) {
5590
- resolved[key] = untracked(() => value());
5591
- }
5592
- else {
5593
- resolved[key] = value;
5594
- }
5595
- }
5596
- return resolved;
5597
- }
5598
-
5599
- function getDebouncePeriods(entries) {
5600
- const periods = new Set();
5601
- for (const entry of entries) {
5602
- if (entry.trigger === 'debounced') {
5603
- periods.add(entry.debounceMs ?? DEFAULT_DEBOUNCE_MS);
5604
- }
5605
- }
5606
- return Array.from(periods);
5607
- }
5608
- function filterEntriesByDebouncePeriod(entries, period) {
5609
- return entries.filter((entry) => entry.trigger === 'debounced' && (entry.debounceMs ?? DEFAULT_DEBOUNCE_MS) === period);
5610
- }
5611
-
5612
- function entrySetsEqual(prev, next, sig) {
5613
- if (prev.length !== next.length)
5614
- return false;
5615
- const counts = new Map();
5616
- for (const item of prev) {
5617
- const key = sig(item);
5618
- counts.set(key, (counts.get(key) ?? 0) + 1);
5619
- }
5620
- for (const item of next) {
5621
- const key = sig(item);
5622
- const remaining = counts.get(key);
5623
- if (!remaining)
5624
- return false;
5625
- if (remaining === 1)
5626
- counts.delete(key);
5627
- else
5628
- counts.set(key, remaining - 1);
5629
- }
5630
- return counts.size === 0;
5631
- }
5632
- function buildEntryStreamPipeline(config) {
5633
- return config.collection$.pipe(map((collection) => config.selectEntries(collection)), distinctUntilChanged((prev, next) => entrySetsEqual(prev, next, config.entrySignature)), switchMap((entries) => {
5634
- if (entries.length === 0)
5635
- return EMPTY;
5636
- const streams = entries.map((entry) => config.createStream(entry)).filter((stream) => stream !== null);
5637
- if (streams.length === 0)
5638
- return EMPTY;
5639
- return merge(...streams);
5640
- }));
5641
- }
5642
-
5643
- function setupOnChangeStream(opts) {
5644
- const collection$ = toObservable(opts.collectionSignal, { injector: opts.injector });
5645
- const formValue$ = toObservable(opts.formValueSignal, { injector: opts.injector });
5646
- const extra$ = opts.additionalAwakeners?.length ? opts.additionalAwakeners.map((s) => toObservable(s, { injector: opts.injector })) : [];
5647
- collection$
5648
- .pipe(filter((collection) => collection !== null), combineLatestWith(formValue$, ...extra$), auditTime(0), startWith(null), pairwise(), filter((pair) => pair[1] !== null), map(([previous, current]) => ({
5649
- collection: current[0],
5650
- changedFields: getChangedKeys(previous?.[1] ?? null, current[1]),
5651
- })), exhaustMap(({ collection, changedFields }) => {
5652
- opts.applyOnChange(collection, changedFields);
5653
- return scheduled([null], queueScheduler);
5654
- }), takeUntilDestroyed(opts.destroyRef))
5655
- .subscribe({
5656
- error: (err) => opts.logger.error(opts.errorLabel, err),
5657
- });
5658
- }
5659
- function setupDebouncedStream(opts) {
5660
- toObservable(opts.formValueSignal, { injector: opts.injector })
5661
- .pipe(debounceTime(DEFAULT_DEBOUNCE_MS), startWith(null), pairwise(), filter((pair) => pair[1] !== null), map(([previous, current]) => ({ current, changedFields: getChangedKeys(previous, current) })), filter(({ changedFields }) => changedFields.size > 0), switchMap(({ changedFields }) => {
5662
- const collection = untracked(() => opts.collectionSignal());
5663
- if (!collection)
5664
- return of(null);
5665
- const debouncePeriods = getDebouncePeriods(collection.entries);
5666
- if (debouncePeriods.length === 0)
5667
- return of(null);
5668
- const periodStreams = debouncePeriods.map((debounceMs) => {
5669
- const additionalWait = Math.max(0, debounceMs - DEFAULT_DEBOUNCE_MS);
5670
- if (additionalWait === 0) {
5671
- return of(null).pipe(map(() => {
5672
- opts.applyDebouncedForPeriod(debounceMs, collection, changedFields);
5673
- }));
5674
- }
5675
- return timer(additionalWait).pipe(map(() => {
5676
- const fresh = untracked(() => opts.collectionSignal()) ?? collection;
5677
- opts.applyDebouncedForPeriod(debounceMs, fresh, changedFields);
5678
- }));
5679
- });
5680
- return merge(...periodStreams);
5681
- }), takeUntilDestroyed(opts.destroyRef))
5682
- .subscribe({
5683
- error: (err) => opts.logger.error(opts.errorLabel, err),
5684
- });
5685
- }
5686
- function setupEntryAsyncStream(opts) {
5687
- const collection$ = toObservable(opts.collectionSignal, { injector: opts.injector });
5688
- buildEntryStreamPipeline({
5689
- collection$,
5690
- selectEntries: opts.selectEntries,
5691
- entrySignature: opts.entrySignature,
5692
- createStream: opts.createStream,
5693
- })
5694
- .pipe(catchError((err) => {
5695
- opts.logger.error(opts.errorLabel, err);
5696
- return EMPTY;
5697
- }), takeUntilDestroyed(opts.destroyRef))
5698
- .subscribe();
5699
- }
5700
-
5701
- function createEmptyPropertyDerivationCollection() {
5702
- return { entries: [] };
5703
- }
5704
- function isAsyncPropertyDerivationEntry(entry) {
5705
- return Boolean(entry.http) || Boolean(entry.asyncFunctionName) || Boolean(entry.asyncFn);
5706
- }
5707
-
5708
- const ERROR_PREFIX = '[PropertyDerivation]';
5709
- function applyPropertyDerivations(collection, context, changedFields) {
5710
- let appliedCount = 0;
5711
- let skippedCount = 0;
5712
- let errorCount = 0;
5713
- const baseEntries = changedFields ? getEntriesForChangedFields(collection.entries, changedFields) : collection.entries;
5714
- const entriesToProcess = baseEntries.filter((entry) => !isAsyncPropertyDerivationEntry(entry));
5715
- for (const entry of entriesToProcess) {
5716
- try {
5717
- const applied = tryApplyPropertyDerivation(entry, context);
5718
- if (applied) {
5719
- appliedCount++;
5720
- }
5721
- else {
5722
- skippedCount++;
5723
- }
5724
- }
5725
- catch (error) {
5726
- errorCount++;
5727
- const errorMessage = error instanceof Error ? error.message : String(error);
5728
- context.logger.error(`${ERROR_PREFIX} Failed to process property derivation (field: ${entry.fieldKey}, property: ${entry.targetProperty}): ${errorMessage}`);
5729
- }
5730
- }
5731
- return { appliedCount, skippedCount, errorCount };
5732
- }
5733
- function applyPropertyDerivationsForTrigger(collection, trigger, context, changedFields) {
5734
- const filteredEntries = collection.entries.filter((entry) => {
5735
- if (trigger === 'onChange') {
5736
- return !entry.trigger || entry.trigger === 'onChange';
5737
- }
5738
- return entry.trigger === trigger;
5739
- });
5740
- const filteredCollection = { entries: filteredEntries };
5741
- return applyPropertyDerivations(filteredCollection, context, changedFields);
5742
- }
5743
- function getEntriesForChangedFields(entries, changedFields) {
5744
- return entries.filter((entry) => {
5745
- if (entry.dependsOn.includes('*'))
5746
- return true;
5747
- return entry.dependsOn.some((dep) => changedFields.has(dep));
5748
- });
5749
- }
5750
- function tryApplyPropertyDerivation(entry, context) {
5751
- if (isArrayPlaceholderPath(entry.fieldKey)) {
5752
- return tryApplyArrayPropertyDerivation(entry, context);
5753
- }
5754
- const formValue = untracked(() => context.formValue());
5755
- const evalContext = createEvaluationContext(entry, formValue, context);
5756
- if (!evaluatePropertyCondition(entry.condition, evalContext)) {
5757
- return false;
5758
- }
5759
- const newValue = computePropertyValue(entry, evalContext, context);
5760
- context.store.setOverride(entry.fieldKey, entry.targetProperty, newValue);
5761
- return true;
5762
- }
5763
- function tryApplyArrayPropertyDerivation(entry, context) {
5764
- const formValue = untracked(() => context.formValue());
5765
- const pathInfo = parseArrayPath(entry.fieldKey);
5766
- if (!pathInfo.isArrayPath) {
5767
- return false;
5768
- }
5769
- const { arrayPath } = pathInfo;
5770
- const arrayValue = getNestedValue(formValue, arrayPath);
5771
- if (!Array.isArray(arrayValue)) {
5772
- return false;
5773
- }
5774
- let appliedAny = false;
5775
- for (let i = 0; i < arrayValue.length; i++) {
5776
- const resolvedPath = resolveArrayPath(entry.fieldKey, i);
5777
- const arrayItem = arrayValue[i];
5778
- const evalContext = createArrayItemEvaluationContext(entry, arrayItem, formValue, i, arrayPath, context);
5779
- if (!evaluatePropertyCondition(entry.condition, evalContext)) {
5780
- continue;
5781
- }
5782
- try {
5783
- const newValue = computePropertyValue(entry, evalContext, context);
5784
- context.store.setOverride(resolvedPath, entry.targetProperty, newValue);
5785
- appliedAny = true;
5786
- }
5787
- catch (error) {
5788
- const errorMessage = error instanceof Error ? error.message : String(error);
5789
- context.logger.error(`${ERROR_PREFIX} Failed to compute property derivation (field: ${entry.fieldKey}, property: ${entry.targetProperty}, index: ${i}): ${errorMessage}`);
5790
- }
5791
- }
5792
- return appliedAny;
5793
- }
5794
- function createEvaluationContext(entry, formValue, context) {
5795
- const fieldValue = getNestedValue(formValue, entry.fieldKey);
5796
- const parentPath = getParentPathInScope(entry.fieldKey);
5797
- const groupValue = parentPath ? getNestedValue(formValue, parentPath) : undefined;
5798
- return {
5799
- fieldValue,
5800
- formValue,
5801
- fieldPath: entry.fieldKey,
5802
- groupValue,
5803
- customFunctions: context.customFunctions,
5804
- externalData: context.externalData,
5805
- logger: context.logger,
5806
- };
5807
- }
5808
- function createArrayItemEvaluationContext(entry, arrayItem, rootFormValue, itemIndex, arrayPath, context) {
5809
- const pathInfo = parseArrayPath(entry.fieldKey);
5810
- const { relativePath, groupValue, fieldValue } = resolveArrayItemScope(pathInfo, arrayItem);
5811
- return {
5812
- fieldValue,
5813
- formValue: arrayItem,
5814
- fieldPath: relativePath ? `${arrayPath}.${itemIndex}.${relativePath}` : `${arrayPath}.${itemIndex}`,
5815
- groupValue,
5816
- customFunctions: context.customFunctions,
5817
- externalData: context.externalData,
5818
- logger: context.logger,
5819
- rootFormValue,
5820
- arrayIndex: itemIndex,
5821
- arrayPath,
5822
- };
5823
- }
5824
- function evaluatePropertyCondition(condition, context) {
5825
- if (typeof condition === 'boolean') {
5826
- return condition;
5827
- }
5828
- return evaluateCondition(condition, context);
5829
- }
5830
- function computePropertyValue(entry, evalContext, applicatorContext) {
5831
- return computeValueFromEntry(entry, evalContext, {
5832
- derivationFunctions: applicatorContext.derivationFunctions,
5833
- subject: `${entry.fieldKey}.${entry.targetProperty}`,
5834
- functionKind: 'Property derivation function',
5835
- });
5836
- }
5837
-
5838
- const LOG_PREFIX$1 = 'HTTP Property Derivation -';
5839
- const DEFAULT_HTTP_DEBOUNCE_MS = 300;
5840
- function createHttpPropertyDerivationStream(entry, formValue$, context) {
5841
- if (isArrayPlaceholderPath(entry.fieldKey)) {
5842
- context.logger.warn(`${LOG_PREFIX$1} HTTP property derivation for array field '${entry.fieldKey}' is not supported. ` +
5843
- `Array HTTP property derivations will be supported in a future release.`);
5844
- return EMPTY;
5845
- }
5846
- if (!entry.http || !entry.responseExpression) {
5847
- return EMPTY;
5848
- }
5849
- const responseExpression = entry.responseExpression;
5850
- const debounceMs = entry.debounceMs ?? DEFAULT_HTTP_DEBOUNCE_MS;
5851
- return formValue$.pipe(startWith(null), pairwise(), map(([previous, current]) => ({
5852
- current: current,
5853
- changedFields: getChangedKeys(previous, current),
5854
- })), filter(({ changedFields }) => {
5855
- if (changedFields.size === 0)
5856
- return false;
5857
- return entry.dependsOn.some((dep) => changedFields.has(dep));
5858
- }), debounceTime(debounceMs), switchMap(({ current }) => {
5859
- return new Observable((subscriber) => {
5860
- const customFunctions = context.customFunctions?.();
5861
- const externalData = context.externalData?.();
5862
- const fieldValue = getNestedValue(current, entry.fieldKey);
5863
- const evalContext = {
5864
- fieldValue,
5865
- formValue: current,
5866
- fieldPath: entry.fieldKey,
5867
- customFunctions,
5868
- externalData,
5869
- logger: context.logger,
5870
- };
5871
- if (entry.condition !== true) {
5872
- const conditionMet = typeof entry.condition === 'boolean' ? entry.condition : evaluateCondition(entry.condition, evalContext);
5873
- if (!conditionMet) {
5874
- subscriber.complete();
5875
- return;
5876
- }
5877
- }
5878
- const resolvedRequest = resolveHttpRequest(entry.http, evalContext);
5879
- if (!resolvedRequest) {
5880
- subscriber.complete();
5881
- return;
5882
- }
5883
- const method = (resolvedRequest.method ?? 'GET').toUpperCase();
5884
- const httpSub = context.httpClient
5885
- .request(method, resolvedRequest.url, {
5886
- body: resolvedRequest.body,
5887
- headers: resolvedRequest.headers,
5888
- })
5889
- .subscribe({
5890
- next: (response) => {
5891
- try {
5892
- const newValue = ExpressionParser.evaluate(responseExpression, { response });
5893
- untracked(() => context.store.setOverride(entry.fieldKey, entry.targetProperty, newValue));
5894
- subscriber.complete();
5895
- }
5896
- catch (error) {
5897
- const message = error instanceof Error ? error.message : String(error);
5898
- context.logger.warn(`${LOG_PREFIX$1} Failed to process response for '${entry.fieldKey}.${entry.targetProperty}': ${message}`);
5899
- subscriber.complete();
5900
- }
5901
- },
5902
- error: (error) => {
5903
- const message = error instanceof Error ? error.message : String(error);
5904
- context.logger.warn(`${LOG_PREFIX$1} HTTP request failed for '${entry.fieldKey}.${entry.targetProperty}': ${message}`);
5905
- subscriber.complete();
5906
- },
5907
- });
5908
- return () => {
5909
- httpSub.unsubscribe();
5910
- };
5911
- });
5912
- }), catchError$1((error) => {
5913
- const message = error instanceof Error ? error.message : String(error);
5914
- context.logger.warn(`${LOG_PREFIX$1} Unexpected stream error for '${entry.fieldKey}.${entry.targetProperty}': ${message}`);
5915
- return EMPTY;
5916
- }));
5917
- }
5918
-
5919
- const LOG_PREFIX = 'Async Property Derivation -';
5920
- const DEFAULT_ASYNC_DEBOUNCE_MS = 300;
5921
- function createAsyncPropertyDerivationStream(entry, formValue$, context) {
5922
- if (isArrayPlaceholderPath(entry.fieldKey)) {
5923
- context.logger.warn(`${LOG_PREFIX} Async property derivation for array field '${entry.fieldKey}' is not supported. ` +
5924
- `Array async property derivations will be supported in a future release.`);
5925
- return EMPTY;
5926
- }
5927
- if (!entry.asyncFunctionName && !entry.asyncFn) {
5928
- context.logger.warn(`${LOG_PREFIX} Property derivation for '${entry.fieldKey}.${entry.targetProperty}' has neither "asyncFunctionName" nor "asyncFn". ` +
5929
- `One of the two is required for source: 'asyncFunction'.`);
5930
- return EMPTY;
5931
- }
5932
- if (entry.asyncFn && entry.asyncFunctionName) {
5933
- context.logger.warn(`${LOG_PREFIX} Both "asyncFn" and "asyncFunctionName" are set on property derivation for '${entry.fieldKey}.${entry.targetProperty}'. ` +
5934
- `Inline "asyncFn" takes precedence; "asyncFunctionName" is ignored.`);
5935
- }
5936
- const inlineAsyncFn = entry.asyncFn;
5937
- const asyncFunctionName = entry.asyncFunctionName;
5938
- const debounceMs = entry.debounceMs ?? DEFAULT_ASYNC_DEBOUNCE_MS;
5939
- return formValue$.pipe(startWith(null), pairwise(), map(([previous, current]) => ({
5940
- current: current,
5941
- changedFields: getChangedKeys(previous, current),
5942
- })), filter(({ changedFields }) => {
5943
- if (changedFields.size === 0)
5944
- return false;
5945
- return entry.dependsOn.some((dep) => changedFields.has(dep));
5946
- }), debounceTime(debounceMs), switchMap(({ current }) => {
5947
- return new Observable((subscriber) => {
5948
- const customFunctions = context.customFunctions?.();
5949
- const asyncDerivationFunctions = context.asyncDerivationFunctions?.();
5950
- const externalData = context.externalData?.();
5951
- const asyncFn = inlineAsyncFn ?? (asyncFunctionName ? asyncDerivationFunctions?.[asyncFunctionName] : undefined);
5952
- if (!asyncFn) {
5953
- context.logger.warn(`${LOG_PREFIX} Async derivation function '${asyncFunctionName}' not found for '${entry.fieldKey}.${entry.targetProperty}'. ` +
5954
- `Register it in customFnConfig.asyncDerivations.`);
5955
- subscriber.complete();
5956
- return;
5957
- }
5958
- const fieldValue = getNestedValue(current, entry.fieldKey);
5959
- const evalContext = {
5960
- fieldValue,
5961
- formValue: current,
5962
- fieldPath: entry.fieldKey,
5963
- customFunctions,
5964
- externalData,
5965
- logger: context.logger,
5966
- };
5967
- if (entry.condition !== true) {
5968
- const conditionMet = typeof entry.condition === 'boolean' ? entry.condition : evaluateCondition(entry.condition, evalContext);
5969
- if (!conditionMet) {
5970
- subscriber.complete();
5971
- return;
5972
- }
5973
- }
5974
- const result$ = from(asyncFn(evalContext));
5975
- const asyncSub = result$.subscribe({
5976
- next: (newValue) => {
5977
- try {
5978
- untracked(() => context.store.setOverride(entry.fieldKey, entry.targetProperty, newValue));
5979
- subscriber.complete();
5980
- }
5981
- catch (error) {
5982
- const message = error instanceof Error ? error.message : String(error);
5983
- context.logger.warn(`${LOG_PREFIX} Failed to process result for '${entry.fieldKey}.${entry.targetProperty}': ${message}`);
5984
- subscriber.complete();
5985
- }
5986
- },
5987
- error: (error) => {
5988
- const message = error instanceof Error ? error.message : String(error);
5989
- context.logger.warn(`${LOG_PREFIX} Async function failed for '${entry.fieldKey}.${entry.targetProperty}': ${message}`);
5990
- subscriber.complete();
5991
- },
5992
- complete: () => {
5993
- subscriber.complete();
5994
- },
5995
- });
5996
- return () => {
5997
- asyncSub.unsubscribe();
5998
- };
5999
- });
6000
- }), catchError$1((error) => {
6001
- const message = error instanceof Error ? error.message : String(error);
6002
- context.logger.warn(`${LOG_PREFIX} Unexpected stream error for '${entry.fieldKey}.${entry.targetProperty}': ${message}`);
6003
- return EMPTY;
6004
- }));
6005
- }
6006
-
6007
- class DerivationOrchestrator {
6008
- config;
6009
- injector = inject(Injector);
6010
- destroyRef = inject(DestroyRef);
6011
- logger = inject(DynamicFormLogger);
6012
- warningTracker = inject(DERIVATION_WARNING_TRACKER);
6013
- functionRegistry = inject(FunctionRegistryService);
6014
- httpClient = inject(HttpClient, { optional: true });
6015
- formOptions;
6016
- derivationCollection;
6017
- propertyDerivationCollection;
6018
- constructor(config) {
6019
- this.config = config;
6020
- const valueEnabled = !!(config.form && config.derivationLogger);
6021
- const propertyStore = config.propertyStore;
6022
- const propertyEnabled = !!propertyStore;
6023
- const sharedAllDerivations = valueEnabled && propertyEnabled
6024
- ? computed(() => {
6025
- const fields = config.schemaFields();
6026
- if (!fields || fields.length === 0)
6027
- return null;
6028
- return collectAllDerivations(fields);
6029
- })
6030
- : null;
6031
- this.derivationCollection = valueEnabled
6032
- ? this.setupValuePipeline(sharedAllDerivations)
6033
- : computed(() => null);
6034
- this.propertyDerivationCollection = propertyStore
6035
- ? this.setupPropertyPipeline(propertyStore, sharedAllDerivations)
6036
- : computed(() => null);
6037
- }
6038
- setupValuePipeline(sharedAllDerivations) {
6039
- this.formOptions = inject(FORM_OPTIONS);
6040
- const collection = computed(() => {
6041
- const fields = this.config.schemaFields();
6042
- if (!fields || fields.length === 0) {
6043
- return null;
6044
- }
6045
- const collected = sharedAllDerivations ? (sharedAllDerivations()?.value ?? null) : collectDerivations(fields);
6046
- if (!collected || collected.entries.length === 0) {
6047
- return null;
6048
- }
6049
- validateNoCycles(collected, this.logger);
6050
- if (DEV_MODE) {
6051
- warnAboutWildcardDependencies(this.logger, collected.entries, fields.length);
6052
- warnAboutMisconfiguredReEngagement(this.logger, collected.entries);
6053
- }
6054
- return collected;
6055
- }, ...(ngDevMode ? [{ debugName: "collection" }] : /* istanbul ignore next */ []));
6056
- setupOnChangeStream({
6057
- injector: this.injector,
6058
- destroyRef: this.destroyRef,
6059
- logger: this.logger,
6060
- errorLabel: 'Derivation onChange stream error',
6061
- collectionSignal: collection,
6062
- formValueSignal: this.config.formValue,
6063
- additionalAwakeners: [this.config.form],
6064
- applyOnChange: (current, changedFields) => {
6065
- this.applyOnChangeDerivations(current, untracked(() => this.config.form()), changedFields);
6066
- },
6067
- });
6068
- setupDebouncedStream({
6069
- injector: this.injector,
6070
- destroyRef: this.destroyRef,
6071
- logger: this.logger,
6072
- errorLabel: 'Derivation debounced stream error',
6073
- collectionSignal: collection,
6074
- formValueSignal: this.config.formValue,
6075
- applyDebouncedForPeriod: (debounceMs, current, changedFields) => {
6076
- const formAccessor = untracked(() => this.config.form());
6077
- if (!formAccessor)
6078
- return;
6079
- this.applyDebouncedEntriesForPeriod(debounceMs, current, formAccessor, changedFields);
6080
- },
6081
- });
6082
- this.setupValueHttpStreams(collection);
6083
- this.setupValueAsyncFunctionStreams(collection);
6084
- return collection;
6085
- }
6086
- setupPropertyPipeline(propertyStore, sharedAllDerivations) {
6087
- const collection = computed(() => {
6088
- const fields = this.config.schemaFields();
6089
- if (!fields || fields.length === 0) {
6090
- return null;
6091
- }
6092
- const collected = sharedAllDerivations ? (sharedAllDerivations()?.property ?? null) : collectPropertyDerivations(fields);
6093
- if (!collected || collected.entries.length === 0) {
6094
- return null;
6095
- }
6096
- return collected;
6097
- }, ...(ngDevMode ? [{ debugName: "collection" }] : /* istanbul ignore next */ []));
6098
- explicitEffect([collection, this.config.schemaFields], ([current, fields]) => {
6099
- propertyStore.clear();
6100
- if (!current)
6101
- return;
6102
- for (const entry of current.entries) {
6103
- propertyStore.registerField(entry.fieldKey);
6104
- }
6105
- if (DEV_MODE) {
6106
- warnAboutWildcardPropertyDependencies(this.logger, current.entries, fields?.length ?? 0);
6107
- }
6108
- });
6109
- setupOnChangeStream({
6110
- injector: this.injector,
6111
- destroyRef: this.destroyRef,
6112
- logger: this.logger,
6113
- errorLabel: 'Property derivation onChange stream error',
6114
- collectionSignal: collection,
6115
- formValueSignal: this.config.formValue,
6116
- applyOnChange: (current) => this.applyOnChangePropertyDerivations(current, propertyStore),
6117
- });
6118
- setupDebouncedStream({
6119
- injector: this.injector,
6120
- destroyRef: this.destroyRef,
6121
- logger: this.logger,
6122
- errorLabel: 'Property derivation debounced stream error',
6123
- collectionSignal: collection,
6124
- formValueSignal: this.config.formValue,
6125
- applyDebouncedForPeriod: (debounceMs, current, changedFields) => {
6126
- this.applyDebouncedPropertyEntriesForPeriod(debounceMs, current, propertyStore, changedFields);
6127
- },
6128
- });
6129
- this.setupPropertyHttpStreams(collection, propertyStore);
6130
- this.setupPropertyAsyncFunctionStreams(collection, propertyStore);
6131
- return collection;
6132
- }
6133
- applyOnChangeDerivations(collection, formAccessor, changedFields) {
6134
- const applicatorContext = {
6135
- formValue: this.config.formValue,
6136
- rootForm: formAccessor,
6137
- derivationFunctions: this.functionRegistry.getDerivationFunctions(),
6138
- customFunctions: this.functionRegistry.getCustomFunctions(),
6139
- externalData: resolveExternalData(this.config.externalData),
6140
- logger: this.logger,
6141
- warningTracker: this.warningTracker,
6142
- derivationLogger: untracked(() => this.config.derivationLogger()),
6143
- maxIterations: untracked(() => this.formOptions()?.maxDerivationIterations),
6144
- };
6145
- const result = applyDerivationsForTrigger(collection, 'onChange', applicatorContext, changedFields);
6146
- if (result.maxIterationsReached) {
6147
- this.logger.warn(`Derivation processing reached max iterations. ` +
6148
- `This may indicate a loop in derivation logic that wasn't caught at build time. ` +
6149
- `Applied: ${result.appliedCount}, Skipped: ${result.skippedCount}, Errors: ${result.errorCount}`);
6150
- }
6151
- }
6152
- applyDebouncedEntriesForPeriod(debounceMs, collection, formAccessor, changedFields) {
6153
- const debouncedEntries = collection.entries.filter((entry) => entry.trigger === 'debounced' && (entry.debounceMs ?? DEFAULT_DEBOUNCE_MS) === debounceMs);
6154
- if (debouncedEntries.length === 0) {
6155
- return;
6156
- }
6157
- const filteredCollection = {
6158
- entries: debouncedEntries,
6159
- };
6160
- const applicatorContext = {
6161
- formValue: this.config.formValue,
6162
- rootForm: formAccessor,
6163
- derivationFunctions: this.functionRegistry.getDerivationFunctions(),
6164
- customFunctions: this.functionRegistry.getCustomFunctions(),
6165
- externalData: resolveExternalData(this.config.externalData),
6166
- logger: this.logger,
6167
- warningTracker: this.warningTracker,
6168
- derivationLogger: untracked(() => this.config.derivationLogger()),
6169
- maxIterations: untracked(() => this.formOptions()?.maxDerivationIterations),
6170
- };
6171
- const result = applyDerivationsForTrigger(filteredCollection, 'debounced', applicatorContext, changedFields);
6172
- if (result.maxIterationsReached) {
6173
- this.logger.warn(`Debounced derivation processing reached max iterations (${debounceMs}ms). ` +
6174
- `Applied: ${result.appliedCount}, Skipped: ${result.skippedCount}, Errors: ${result.errorCount}`);
6175
- }
6176
- }
6177
- setupValueHttpStreams(collectionSignal) {
6178
- const formValue$ = toObservable(this.config.formValue, { injector: this.injector });
6179
- setupEntryAsyncStream({
6180
- injector: this.injector,
6181
- destroyRef: this.destroyRef,
6182
- logger: this.logger,
6183
- errorLabel: 'HTTP Derivation: outer stream error',
6184
- collectionSignal,
6185
- selectEntries: (collection) => collection?.entries.filter((entry) => entry.http) ?? [],
6186
- entrySignature: valueHttpEntrySignature,
6187
- createStream: (entry) => {
6188
- if (!this.httpClient) {
6189
- this.logger.error('HTTP Derivation: HttpClient is not available. Ensure provideHttpClient() is included in your application providers.');
6190
- return null;
6191
- }
6192
- const context = {
6193
- formValue: this.config.formValue,
6194
- form: this.config.form,
6195
- httpClient: this.httpClient,
6196
- logger: this.logger,
6197
- derivationLogger: this.config.derivationLogger,
6198
- customFunctions: () => this.functionRegistry.getCustomFunctions(),
6199
- externalData: () => resolveExternalData(this.config.externalData),
6200
- warningTracker: this.warningTracker,
6201
- };
6202
- return createHttpDerivationStream(entry, formValue$, context);
6203
- },
6204
- });
6205
- }
6206
- setupValueAsyncFunctionStreams(collectionSignal) {
6207
- const formValue$ = toObservable(this.config.formValue, { injector: this.injector });
6208
- setupEntryAsyncStream({
6209
- injector: this.injector,
6210
- destroyRef: this.destroyRef,
6211
- logger: this.logger,
6212
- errorLabel: 'Async Derivation: outer stream error',
6213
- collectionSignal,
6214
- selectEntries: (collection) => collection?.entries.filter((entry) => entry.asyncFunctionName || entry.asyncFn) ?? [],
6215
- entrySignature: valueAsyncEntrySignature,
6216
- createStream: (entry) => createAsyncDerivationStream(entry, formValue$, {
6217
- formValue: this.config.formValue,
6218
- form: this.config.form,
6219
- logger: this.logger,
6220
- derivationLogger: this.config.derivationLogger,
6221
- customFunctions: () => this.functionRegistry.getCustomFunctions(),
6222
- asyncDerivationFunctions: () => this.functionRegistry.getAsyncDerivationFunctions(),
6223
- externalData: () => resolveExternalData(this.config.externalData),
6224
- warningTracker: this.warningTracker,
6225
- }),
6226
- });
6227
- }
6228
- applyOnChangePropertyDerivations(collection, store) {
6229
- const applicatorContext = {
6230
- formValue: this.config.formValue,
6231
- store,
6232
- derivationFunctions: this.functionRegistry.getDerivationFunctions(),
6233
- customFunctions: this.functionRegistry.getCustomFunctions(),
6234
- externalData: resolveExternalData(this.config.externalData),
6235
- logger: this.logger,
6236
- warningTracker: this.warningTracker,
6237
- };
6238
- applyPropertyDerivationsForTrigger(collection, 'onChange', applicatorContext);
6239
- }
6240
- applyDebouncedPropertyEntriesForPeriod(debounceMs, collection, store, changedFields) {
6241
- const debouncedEntries = collection.entries.filter((entry) => entry.trigger === 'debounced' && (entry.debounceMs ?? DEFAULT_DEBOUNCE_MS) === debounceMs);
6242
- if (debouncedEntries.length === 0)
6243
- return;
6244
- const filteredCollection = { entries: debouncedEntries };
6245
- const applicatorContext = {
6246
- formValue: this.config.formValue,
6247
- store,
6248
- derivationFunctions: this.functionRegistry.getDerivationFunctions(),
6249
- customFunctions: this.functionRegistry.getCustomFunctions(),
6250
- externalData: resolveExternalData(this.config.externalData),
6251
- logger: this.logger,
6252
- warningTracker: this.warningTracker,
6253
- };
6254
- applyPropertyDerivationsForTrigger(filteredCollection, 'debounced', applicatorContext, changedFields);
6255
- }
6256
- setupPropertyHttpStreams(collectionSignal, store) {
6257
- const formValue$ = toObservable(this.config.formValue, { injector: this.injector });
6258
- setupEntryAsyncStream({
6259
- injector: this.injector,
6260
- destroyRef: this.destroyRef,
6261
- logger: this.logger,
6262
- errorLabel: 'HTTP Property Derivation: outer stream error',
6263
- collectionSignal,
6264
- selectEntries: (collection) => collection?.entries.filter((entry) => entry.http) ?? [],
6265
- entrySignature: propertyHttpEntrySignature,
6266
- createStream: (entry) => {
6267
- if (!this.httpClient) {
6268
- this.logger.error('HTTP Property Derivation: HttpClient is not available. Ensure provideHttpClient() is included in your application providers.');
6269
- return null;
6270
- }
6271
- return createHttpPropertyDerivationStream(entry, formValue$, {
6272
- formValue: this.config.formValue,
6273
- store,
6274
- httpClient: this.httpClient,
6275
- logger: this.logger,
6276
- customFunctions: () => this.functionRegistry.getCustomFunctions(),
6277
- externalData: () => resolveExternalData(this.config.externalData),
6278
- });
6279
- },
6280
- });
6281
- }
6282
- setupPropertyAsyncFunctionStreams(collectionSignal, store) {
6283
- const formValue$ = toObservable(this.config.formValue, { injector: this.injector });
6284
- setupEntryAsyncStream({
6285
- injector: this.injector,
6286
- destroyRef: this.destroyRef,
6287
- logger: this.logger,
6288
- errorLabel: 'Async Property Derivation: outer stream error',
6289
- collectionSignal,
6290
- selectEntries: (collection) => collection?.entries.filter((entry) => entry.asyncFunctionName || entry.asyncFn) ?? [],
6291
- entrySignature: propertyAsyncEntrySignature,
6292
- createStream: (entry) => createAsyncPropertyDerivationStream(entry, formValue$, {
6293
- formValue: this.config.formValue,
6294
- store,
6295
- logger: this.logger,
6296
- customFunctions: () => this.functionRegistry.getCustomFunctions(),
6297
- asyncDerivationFunctions: () => this.functionRegistry.getAsyncDerivationFunctions(),
6298
- externalData: () => resolveExternalData(this.config.externalData),
6299
- }),
6300
- });
6301
- }
6302
- }
6303
- function valueHttpEntrySignature(entry) {
6304
- const config = {
6305
- http: entry.http,
6306
- responseExpression: entry.responseExpression,
6307
- dependsOn: entry.dependsOn,
6308
- debounceMs: entry.debounceMs,
6309
- trigger: entry.trigger,
6310
- condition: entry.condition,
6311
- stopOnUserOverride: entry.stopOnUserOverride,
6312
- reEngageOnDependencyChange: entry.reEngageOnDependencyChange,
6313
- };
6314
- return `${entry.fieldKey}:${JSON.stringify(config)}`;
6315
- }
6316
- function valueAsyncEntrySignature(entry) {
6317
- const config = {
6318
- asyncFunctionName: entry.asyncFunctionName,
6319
- asyncFnId: entry.asyncFn ? `inline:${entry.fieldKey}` : undefined,
6320
- dependsOn: entry.dependsOn,
6321
- debounceMs: entry.debounceMs,
6322
- trigger: entry.trigger,
6323
- condition: entry.condition,
6324
- stopOnUserOverride: entry.stopOnUserOverride,
6325
- reEngageOnDependencyChange: entry.reEngageOnDependencyChange,
6326
- };
6327
- return `${entry.fieldKey}:${JSON.stringify(config)}`;
6328
- }
6329
- function propertyHttpEntrySignature(entry) {
6330
- const config = {
6331
- http: entry.http,
6332
- responseExpression: entry.responseExpression,
6333
- dependsOn: entry.dependsOn,
6334
- debounceMs: entry.debounceMs,
6335
- trigger: entry.trigger,
6336
- condition: entry.condition,
6337
- };
6338
- return `${entry.fieldKey}.${entry.targetProperty}:${JSON.stringify(config)}`;
6339
- }
6340
- function propertyAsyncEntrySignature(entry) {
6341
- const config = {
6342
- asyncFunctionName: entry.asyncFunctionName,
6343
- asyncFnId: entry.asyncFn ? `inline:${entry.fieldKey}.${entry.targetProperty}` : undefined,
6344
- dependsOn: entry.dependsOn,
6345
- debounceMs: entry.debounceMs,
6346
- trigger: entry.trigger,
6347
- condition: entry.condition,
6348
- };
6349
- return `${entry.fieldKey}.${entry.targetProperty}:${JSON.stringify(config)}`;
6350
- }
6351
- function createDerivationOrchestrator(config) {
6352
- return new DerivationOrchestrator(config);
6353
- }
6354
- const DERIVATION_ORCHESTRATOR = new InjectionToken('DERIVATION_ORCHESTRATOR');
6355
- const PROPERTY_DERIVATION_ORCHESTRATOR = new InjectionToken('PROPERTY_DERIVATION_ORCHESTRATOR');
6356
- function injectDerivationOrchestrator() {
6357
- return inject(DERIVATION_ORCHESTRATOR);
6358
- }
6359
- function warnAboutWildcardDependencies(logger, entries, fieldCount) {
6360
- const wildcardEntries = entries.filter((entry) => entry.dependsOn.includes('*'));
6361
- if (wildcardEntries.length === 0)
6362
- return;
6363
- const implicitWildcards = wildcardEntries.filter((entry) => !entry.http &&
6364
- !entry.asyncFunctionName &&
6365
- !entry.asyncFn &&
6366
- (entry.functionName || entry.fn) &&
6367
- (!entry.originalConfig?.dependsOn || entry.originalConfig.dependsOn.length === 0));
6368
- if (implicitWildcards.length > 0) {
6369
- const derivationDescs = implicitWildcards.map((e) => `${e.fieldKey} (${e.functionName ?? '<inline fn>'})`);
6370
- logger.warn('Derivation: custom functions without explicit dependsOn detected. ' +
6371
- `These run on EVERY form change, which may impact performance (form has ${fieldCount} fields). ` +
6372
- 'Consider specifying explicit dependsOn arrays for better performance.', derivationDescs);
6373
- }
6374
- }
6375
- function warnAboutMisconfiguredReEngagement(logger, entries) {
6376
- const misconfigured = entries.filter((entry) => entry.reEngageOnDependencyChange && !entry.stopOnUserOverride);
6377
- if (misconfigured.length === 0)
6378
- return;
6379
- const fieldKeys = misconfigured.map((e) => e.debugName ?? e.fieldKey);
6380
- logger.warn('Derivation: reEngageOnDependencyChange without stopOnUserOverride detected. ' +
6381
- 'reEngageOnDependencyChange only takes effect when stopOnUserOverride is true. ' +
6382
- 'Either add stopOnUserOverride: true or remove reEngageOnDependencyChange.', fieldKeys);
6383
- }
6384
- function warnAboutWildcardPropertyDependencies(logger, entries, fieldCount) {
6385
- const implicitWildcards = entries.filter((entry) => entry.dependsOn.includes('*') &&
6386
- (entry.functionName || entry.fn) &&
6387
- (!entry.originalConfig?.dependsOn || entry.originalConfig.dependsOn.length === 0));
6388
- if (implicitWildcards.length > 0) {
6389
- const derivationDescs = implicitWildcards.map((e) => `${e.fieldKey}.${e.targetProperty} (${e.functionName ?? '<inline fn>'})`);
6390
- logger.warn('PropertyDerivation: custom functions without explicit dependsOn detected. ' +
6391
- `These run on EVERY form change, which may impact performance (form has ${fieldCount} fields). ` +
6392
- 'Consider specifying explicit dependsOn arrays for better performance.', derivationDescs);
6393
- }
6394
- }
6395
-
6396
- class ActiveDerivationLogger {
6397
- logger;
6398
- config = createDefaultDerivationLogConfig();
6399
- setConfig(config) {
6400
- this.config = config;
6401
- }
6402
- cycleStart(trigger, entryCount) {
6403
- if (!shouldLog(this.config, 'verbose'))
6404
- return;
6405
- this.logger.debug(`Derivation - Starting cycle (${trigger}) with ${entryCount} derivation(s)`);
6406
- }
6407
- iteration(iterationNumber) {
6408
- if (!shouldLog(this.config, 'verbose'))
6409
- return;
6410
- this.logger.debug(`Derivation - Iteration ${iterationNumber}`);
6411
- }
6412
- evaluation(entry) {
6413
- if (!shouldLog(this.config, 'verbose'))
6414
- return;
6415
- const name = entry.debugName ? `"${entry.debugName}"` : entry.fieldKey;
6416
- switch (entry.result) {
6417
- case 'applied':
6418
- this.logger.debug(`Derivation - Applied ${name}`, {
6419
- field: entry.fieldKey,
6420
- previousValue: entry.previousValue,
6421
- newValue: entry.newValue,
6422
- ...(entry.durationMs !== undefined && { durationMs: entry.durationMs }),
6423
- });
6424
- break;
6425
- case 'skipped':
6426
- this.logger.debug(`Derivation - Skipped ${name} (${this.formatSkipReason(entry.skipReason)})`, {
6427
- field: entry.fieldKey,
6428
- reason: entry.skipReason,
6429
- });
6430
- break;
6431
- case 'error':
6432
- this.logger.debug(`Derivation - Error ${name}`, {
6433
- field: entry.fieldKey,
6434
- error: entry.error,
6435
- });
6436
- break;
6437
- }
6438
- }
6439
- summary(result, trigger) {
6440
- if (!shouldLog(this.config, 'summary'))
6441
- return;
6442
- if (result.appliedCount === 0 && result.errorCount === 0)
6443
- return;
6444
- this.logger.debug(`Derivation - Cycle complete (${trigger})`, {
6445
- applied: result.appliedCount,
6446
- skipped: result.skippedCount,
6447
- errors: result.errorCount,
6448
- iterations: result.iterations,
6449
- });
6450
- }
6451
- maxIterationsReached(result, trigger) {
6452
- this.logger.warn(`Derivation - Max iterations reached (${trigger}). ` +
6453
- `This may indicate a loop in derivation logic. ` +
6454
- `Applied: ${result.appliedCount}, Skipped: ${result.skippedCount}, Errors: ${result.errorCount}`);
6455
- }
6456
- formatSkipReason(reason) {
6457
- switch (reason) {
6458
- case 'condition-false':
6459
- return 'condition not met';
6460
- case 'value-unchanged':
6461
- return 'value unchanged';
6462
- case 'already-applied':
6463
- return 'already applied this cycle';
6464
- case 'user-override':
6465
- return 'user override active';
6466
- case 'target-not-found':
6467
- return 'target not found';
6468
- default:
6469
- return 'unknown';
6470
- }
6471
- }
6472
- }
6473
- class NoopDerivationLogger {
6474
- cycleStart() {
6475
- /* no-op */
6476
- }
6477
- iteration() {
6478
- /* no-op */
6479
- }
6480
- evaluation() {
6481
- /* no-op */
6482
- }
6483
- summary() {
6484
- /* no-op */
6485
- }
6486
- maxIterationsReached() {
6487
- /* no-op */
6488
- }
6489
- }
6490
- const NOOP_INSTANCE = new NoopDerivationLogger();
6491
- function createDerivationLogger(config, logger) {
6492
- const effectiveConfig = config ?? createDefaultDerivationLogConfig();
6493
- if (effectiveConfig.level === 'none') {
6494
- return NOOP_INSTANCE;
6495
- }
6496
- const service = new ActiveDerivationLogger();
6497
- service.logger = logger;
6498
- service.setConfig(effectiveConfig);
6499
- return service;
6500
- }
6501
-
6502
- function isDynamicFormFeature(value) {
6503
- return (typeof value === 'object' &&
6504
- value !== null &&
6505
- 'ɵkind' in value &&
6506
- typeof value.ɵkind === 'string' &&
6507
- 'ɵproviders' in value &&
6508
- Array.isArray(value.ɵproviders));
6509
- }
6510
- function createFeature(kind, providers) {
6511
- return {
6512
- ɵkind: kind,
6513
- ɵproviders: providers,
6514
- };
6515
- }
6516
-
6517
- class ConsoleLogger {
6518
- prefix = '[Dynamic Forms]';
6519
- debug(message, ...args) {
6520
- console.debug(this.prefix, message, ...args);
6521
- }
6522
- info(message, ...args) {
6523
- console.info(this.prefix, message, ...args);
6524
- }
6525
- warn(message, ...args) {
6526
- console.warn(this.prefix, message, ...args);
6527
- }
6528
- error(message, ...args) {
6529
- console.error(this.prefix, message, ...args);
6530
- }
6531
- }
6532
-
6533
- const DERIVATION_LOG_CONFIG = new InjectionToken('DERIVATION_LOG_CONFIG', {
6534
- providedIn: 'root',
6535
- factory: createDefaultDerivationLogConfig,
6536
- });
6537
- function withLoggerConfig(config = true) {
6538
- if (typeof config === 'boolean' || typeof config === 'function') {
6539
- const isEnabled = typeof config === 'function' ? config() : config;
6540
- const logger = isEnabled ? new ConsoleLogger() : new NoopLogger();
6541
- return createFeature('logger', [{ provide: DynamicFormLogger, useValue: logger }]);
6542
- }
6543
- const isEnabled = config.enabled !== false;
6544
- const logger = isEnabled ? new ConsoleLogger() : new NoopLogger();
6545
- const providers = [{ provide: DynamicFormLogger, useValue: logger }];
6546
- if (config.derivations !== undefined) {
6547
- providers.push({
6548
- provide: DERIVATION_LOG_CONFIG,
6549
- useValue: { level: config.derivations },
6550
- });
6551
- }
6552
- return createFeature('logger', providers);
6553
- }
6554
-
6555
- const ADDON_ACTION_HANDLERS = new InjectionToken('ADDON_ACTION_HANDLERS');
6556
- const ADDON_ACTION_REGISTRY = new InjectionToken('ADDON_ACTION_REGISTRY');
6557
- function createAddonActionRegistry() {
6558
- const sources = inject(ADDON_ACTION_HANDLERS, { optional: true }) ?? [];
6559
- const map = new Map();
6560
- for (const handlers of sources) {
6561
- for (const [name, fn] of Object.entries(handlers)) {
6562
- map.set(name, fn);
6563
- }
6564
- }
6565
- return map;
6566
- }
6567
-
6568
- function coreProviders() {
6569
- return [
6570
- EventBus,
6571
- { provide: CONTAINER_FIELD_PROCESSORS, useFactory: createContainerFieldProcessors },
6572
- SchemaRegistryService,
6573
- FunctionRegistryService,
6574
- {
6575
- provide: FORM_STATE_DEPS,
6576
- useFactory: () => ({ config: null, formOptions: null, value: null, source: null }),
6577
- },
6578
- FormStateManager,
6579
- {
6580
- provide: RootFormRegistryService,
6581
- useFactory: (stateManager) => new RootFormRegistryService(stateManager.formValue, computed(() => stateManager.form())),
6582
- deps: [FormStateManager],
6583
- },
6584
- FieldContextRegistryService,
6585
- ArrayItemRegistryService,
6586
- {
6587
- provide: DEFAULT_PROPS,
6588
- useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.defaultProps),
6589
- deps: [FormStateManager],
6590
- },
6591
- {
6592
- provide: DEFAULT_WRAPPERS,
6593
- useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.defaultWrappers),
6594
- deps: [FormStateManager],
6595
- },
6596
- {
6597
- provide: DEFAULT_VALIDATION_MESSAGES,
6598
- useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.defaultValidationMessages),
6599
- deps: [FormStateManager],
6600
- },
6601
- {
6602
- provide: FORM_OPTIONS,
6603
- useFactory: (stateManager) => stateManager.effectiveFormOptions,
6604
- deps: [FormStateManager],
6605
- },
6606
- {
6607
- provide: EXTERNAL_DATA,
6608
- useFactory: (stateManager) => computed(() => stateManager.activeConfig()?.externalData),
6609
- deps: [FormStateManager],
6610
- },
6611
- FormIdPrefixService,
6612
- {
6613
- provide: FORM_ID_PREFIX,
6614
- useFactory: (svc) => svc.prefix,
6615
- deps: [FormIdPrefixService],
6616
- },
6617
- { provide: DEPRECATION_WARNING_TRACKER, useFactory: createWarningTracker },
6618
- { provide: ADDON_ACTION_REGISTRY, useFactory: createAddonActionRegistry },
6619
- ];
6620
- }
6621
- function derivationProviders() {
6622
- return [
6623
- { provide: DERIVATION_WARNING_TRACKER, useFactory: createWarningTracker },
6624
- {
6625
- provide: DERIVATION_ORCHESTRATOR,
6626
- useFactory: (stateManager, logger, logConfig, externalData, propertyStore) => {
6627
- const config = {
6628
- schemaFields: computed(() => stateManager.formSetup()?.schemaFields),
6629
- formValue: stateManager.formValue,
6630
- form: computed(() => stateManager.form()),
6631
- derivationLogger: computed(() => createDerivationLogger(logConfig, logger)),
6632
- propertyStore,
6633
- externalData,
6634
- };
6635
- return createDerivationOrchestrator(config);
6636
- },
6637
- deps: [FormStateManager, DynamicFormLogger, DERIVATION_LOG_CONFIG, EXTERNAL_DATA, PROPERTY_OVERRIDE_STORE],
6638
- },
6639
- { provide: FORM_INITIALIZER, useExisting: DERIVATION_ORCHESTRATOR, multi: true },
6640
- ];
6641
- }
6642
- function propertyDerivationProviders() {
6643
- return [
6644
- { provide: PROPERTY_OVERRIDE_STORE, useFactory: createPropertyOverrideStore },
6645
- { provide: PROPERTY_DERIVATION_ORCHESTRATOR, useExisting: DERIVATION_ORCHESTRATOR },
6646
- ];
6647
- }
6648
- function httpExpressionProviders() {
6649
- return [{ provide: HTTP_CONDITION_CACHE, useFactory: () => new HttpConditionCache(100) }, HttpConditionFunctionCacheService];
6650
- }
6651
- function asyncExpressionProviders() {
6652
- return [AsyncConditionFunctionCacheService];
6653
- }
6654
- function dynamicValueProviders() {
6655
- return [DynamicValueFunctionCacheService];
6656
- }
6657
- function logicProviders() {
6658
- return [LogicFunctionCacheService];
6659
- }
6660
- function provideDynamicFormDI() {
6661
- return [
6662
- ...coreProviders(),
6663
- ...logicProviders(),
6664
- ...dynamicValueProviders(),
6665
- ...httpExpressionProviders(),
6666
- ...asyncExpressionProviders(),
6667
- ...propertyDerivationProviders(),
6668
- ...derivationProviders(),
6669
- ];
6670
- }
6671
-
6672
- class EventDispatcher {
6673
- bus;
6674
- dispatch(event) {
6675
- this.bus?.emitInstance(event);
6676
- }
6677
- connect(bus) {
6678
- this.bus = bus;
6679
- }
6680
- disconnect() {
6681
- this.bus = undefined;
6682
- }
6683
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EventDispatcher, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6684
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EventDispatcher });
6685
- }
6686
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EventDispatcher, decorators: [{
6687
- type: Injectable
6688
- }] });
6689
-
6690
- class DfTemplate {
6691
- dfTemplate = input.required(...(ngDevMode ? [{ debugName: "dfTemplate" }] : /* istanbul ignore next */ []));
6692
- templateRef = inject(TemplateRef);
6693
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfTemplate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
6694
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: DfTemplate, isStandalone: true, selector: "ng-template[dfTemplate]", inputs: { dfTemplate: { classPropertyName: "dfTemplate", publicName: "dfTemplate", isSignal: true, isRequired: true, transformFunction: null } }, exportAs: ["dfTemplate"], ngImport: i0 });
6695
- }
6696
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfTemplate, decorators: [{
6697
- type: Directive,
6698
- args: [{
6699
- selector: 'ng-template[dfTemplate]',
6700
- exportAs: 'dfTemplate',
6701
- }]
6702
- }], propDecorators: { dfTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "dfTemplate", required: true }] }] } });
6703
- class DfFieldTemplateRegistry {
6704
- _map = signal(new Map(), ...(ngDevMode ? [{ debugName: "_map" }] : /* istanbul ignore next */ []));
6705
- map = this._map.asReadonly();
6706
- set(value) {
6707
- this._map.set(value);
6708
- }
6709
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfFieldTemplateRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6710
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfFieldTemplateRegistry });
4429
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfFieldTemplateRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4430
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfFieldTemplateRegistry });
6711
4431
  }
6712
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfFieldTemplateRegistry, decorators: [{
4432
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfFieldTemplateRegistry, decorators: [{
6713
4433
  type: Injectable
6714
4434
  }] });
6715
4435
 
6716
4436
  class DynamicForm {
6717
4437
  config = input.required({ ...(ngDevMode ? { debugName: "config" } : /* istanbul ignore next */ {}), alias: 'dynamic-form' });
6718
- formOptions = input(undefined, ...(ngDevMode ? [{ debugName: "formOptions" }] : /* istanbul ignore next */ []));
6719
- value = model(undefined, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
6720
- source = input('inline', ...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
4438
+ formOptions = input(undefined, /* @ts-ignore */
4439
+ ...(ngDevMode ? [{ debugName: "formOptions" }] : /* istanbul ignore next */ []));
4440
+ value = model(undefined, /* @ts-ignore */
4441
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
4442
+ source = input('inline', /* @ts-ignore */
4443
+ ...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
6721
4444
  destroyRef = inject(DestroyRef);
6722
4445
  injector = inject(Injector);
6723
4446
  environmentInjector = inject(EnvironmentInjector);
@@ -6725,7 +4448,8 @@ class DynamicForm {
6725
4448
  logger = inject(DynamicFormLogger);
6726
4449
  dispatcher = inject(EventDispatcher, { optional: true });
6727
4450
  templateRegistry = inject(DfFieldTemplateRegistry);
6728
- _projectedTemplates = contentChildren(DfTemplate, ...(ngDevMode ? [{ debugName: "_projectedTemplates" }] : /* istanbul ignore next */ []));
4451
+ _projectedTemplates = contentChildren(DfTemplate, /* @ts-ignore */
4452
+ ...(ngDevMode ? [{ debugName: "_projectedTemplates" }] : /* istanbul ignore next */ []));
6729
4453
  stateManager = this.connectDeps();
6730
4454
  formIdPrefix = inject(FormIdPrefixService);
6731
4455
  idPrefix = this.formIdPrefix.prefix;
@@ -6747,12 +4471,15 @@ class DynamicForm {
6747
4471
  disabled = this.stateManager.disabled;
6748
4472
  submitting = this.stateManager.submitting;
6749
4473
  fieldLoadingErrors = this.stateManager.fieldLoadingErrors;
6750
- shouldRender = this.stateManager.shouldRender;
4474
+ derivationReady = inject(DERIVATION_RENDER_GATE);
4475
+ shouldRender = computed(() => this.stateManager.shouldRender() && this.derivationReady(), /* @ts-ignore */
4476
+ ...(ngDevMode ? [{ debugName: "shouldRender" }] : /* istanbul ignore next */ []));
6751
4477
  resolvedFields = this.stateManager.resolvedFields;
6752
4478
  totalComponentsCount = computed(() => {
6753
4479
  const fields = this.stateManager.formSetup()?.fields ?? [];
6754
4480
  return countContainersRecursive(fields) + 1;
6755
- }, ...(ngDevMode ? [{ debugName: "totalComponentsCount" }] : /* istanbul ignore next */ []));
4481
+ }, /* @ts-ignore */
4482
+ ...(ngDevMode ? [{ debugName: "totalComponentsCount" }] : /* istanbul ignore next */ []));
6756
4483
  initialized$ = setupInitializationTracking({
6757
4484
  eventBus: this.eventBus,
6758
4485
  totalComponentsCount: this.totalComponentsCount,
@@ -6821,8 +4548,8 @@ class DynamicForm {
6821
4548
  error: (err) => this.logger.error('Submission handler error', err),
6822
4549
  });
6823
4550
  }
6824
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
6825
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicForm, isStandalone: true, selector: "form[dynamic-form]", inputs: { config: { classPropertyName: "config", publicName: "dynamic-form", isSignal: true, isRequired: true, transformFunction: null }, formOptions: { classPropertyName: "formOptions", publicName: "formOptions", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", validityChange: "validityChange", dirtyChange: "dirtyChange", submitted: "submitted", reset: "reset", cleared: "cleared", events: "events", initialized: "initialized", onPageChange: "onPageChange", onPageNavigationStateChange: "onPageNavigationStateChange" }, host: { attributes: { "novalidate": "" }, listeners: { "submit": "onNativeSubmit($event)" }, properties: { "class.disabled": "disabled()", "class.df-form-paged": "formModeDetection().mode === \"paged\"", "class.df-form-non-paged": "formModeDetection().mode === \"non-paged\"", "attr.data-form-mode": "formModeDetection().mode", "attr.id": "idPrefix() || null" }, classAttribute: "df-dynamic-form df-form" }, providers: [
4551
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DynamicForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
4552
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: DynamicForm, isStandalone: true, selector: "form[dynamic-form]", inputs: { config: { classPropertyName: "config", publicName: "dynamic-form", isSignal: true, isRequired: true, transformFunction: null }, formOptions: { classPropertyName: "formOptions", publicName: "formOptions", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", validityChange: "validityChange", dirtyChange: "dirtyChange", submitted: "submitted", reset: "reset", cleared: "cleared", events: "events", initialized: "initialized", onPageChange: "onPageChange", onPageNavigationStateChange: "onPageNavigationStateChange" }, host: { attributes: { "novalidate": "" }, listeners: { "submit": "onNativeSubmit($event)" }, properties: { "class.disabled": "disabled()", "class.df-form-paged": "formModeDetection().mode === \"paged\"", "class.df-form-non-paged": "formModeDetection().mode === \"non-paged\"", "attr.data-form-mode": "formModeDetection().mode", "attr.id": "idPrefix() || null" }, classAttribute: "df-dynamic-form df-form" }, providers: [
6826
4553
  provideDynamicFormDI(),
6827
4554
  DfFieldTemplateRegistry,
6828
4555
  { provide: DF_FIELD_TEMPLATES, useFactory: () => inject(DfFieldTemplateRegistry).map },
@@ -6850,7 +4577,7 @@ class DynamicForm {
6850
4577
  }
6851
4578
  `, isInline: true, styles: [".df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap, .5rem);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-sm, .5rem)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns, 12),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-md, .5rem)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-lg, .5rem)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-xl, .5rem)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}:host>*{grid-column:1/-1}:host.df-form-spacing-custom{--df-grid-row-gap: var(--df-form-custom-spacing, 1.5rem)}:host.df-form-gap-none{--df-grid-row-gap: 0}:host.df-form-gap-xs{--df-grid-row-gap: .25rem}:host.df-form-gap-sm{--df-grid-row-gap: .5rem}:host.df-form-gap-md{--df-grid-row-gap: 1rem}:host.df-form-gap-lg{--df-grid-row-gap: 1.5rem}:host.df-form-gap-xl{--df-grid-row-gap: 2rem}:host.df-form-paged{gap:0}\n"], dependencies: [{ kind: "directive", type: DfFieldOutlet, selector: "[dfFieldOutlet]", inputs: ["dfFieldOutlet", "dfFieldOutletEnvironmentInjector"] }, { kind: "component", type: PageOrchestratorComponent, selector: "div[page-orchestrator]", inputs: ["pageFields", "form", "fieldSignalContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6852
4579
  }
6853
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicForm, decorators: [{
4580
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DynamicForm, decorators: [{
6854
4581
  type: Component,
6855
4582
  args: [{ selector: 'form[dynamic-form]', imports: [DfFieldOutlet, PageOrchestratorComponent], template: `
6856
4583
  @if (shouldRender()) {
@@ -7006,35 +4733,35 @@ const DISPLAY_FIELD_TYPES_BASE = {
7006
4733
  const BUILT_IN_FIELDS = [
7007
4734
  {
7008
4735
  name: 'row',
7009
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-bA-8ICHF.mjs'),
4736
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs'),
7010
4737
  mapper: rowFieldMapper,
7011
4738
  valueHandling: 'flatten',
7012
4739
  ...CONTAINER_FIELD_TYPES_BASE,
7013
4740
  },
7014
4741
  {
7015
4742
  name: 'group',
7016
- loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-D0_nmXf2.mjs'),
4743
+ loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs'),
7017
4744
  mapper: groupFieldMapper,
7018
4745
  valueHandling: 'include',
7019
4746
  ...CONTAINER_FIELD_TYPES_BASE,
7020
4747
  },
7021
4748
  {
7022
4749
  name: 'array',
7023
- loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-BfRH3TBm.mjs'),
4750
+ loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs'),
7024
4751
  mapper: arrayFieldMapper,
7025
4752
  valueHandling: 'include',
7026
4753
  ...CONTAINER_FIELD_TYPES_BASE,
7027
4754
  },
7028
4755
  {
7029
4756
  name: 'page',
7030
- loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-BJRNnoz-.mjs'),
4757
+ loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs'),
7031
4758
  mapper: pageFieldMapper,
7032
4759
  valueHandling: 'flatten',
7033
4760
  ...CONTAINER_FIELD_TYPES_BASE,
7034
4761
  },
7035
4762
  {
7036
4763
  name: 'text',
7037
- loadComponent: () => import('./ng-forge-dynamic-forms-text-field.component-DABkT0O7.mjs'),
4764
+ loadComponent: () => import('./ng-forge-dynamic-forms-text-field.component-CNCpmf5_.mjs'),
7038
4765
  mapper: textFieldMapper,
7039
4766
  valueHandling: 'exclude',
7040
4767
  ...DISPLAY_FIELD_TYPES_BASE,
@@ -7045,7 +4772,7 @@ const BUILT_IN_FIELDS = [
7045
4772
  },
7046
4773
  {
7047
4774
  name: 'container',
7048
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-bA-8ICHF.mjs'),
4775
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs'),
7049
4776
  mapper: containerFieldMapper,
7050
4777
  valueHandling: 'flatten',
7051
4778
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -7054,16 +4781,47 @@ const BUILT_IN_FIELDS = [
7054
4781
  const BUILT_IN_WRAPPERS = [
7055
4782
  {
7056
4783
  wrapperName: 'css',
7057
- loadComponent: () => import('./ng-forge-dynamic-forms-css-wrapper.component-DjhcONFh.mjs'),
4784
+ loadComponent: () => import('./ng-forge-dynamic-forms-css-wrapper.component-AScQAJTQ.mjs'),
7058
4785
  },
7059
4786
  {
7060
4787
  wrapperName: 'row',
7061
- loadComponent: () => import('./ng-forge-dynamic-forms-row-wrapper.component-CwkYn5yl.mjs'),
4788
+ loadComponent: () => import('./ng-forge-dynamic-forms-row-wrapper.component-BlVa801t.mjs'),
7062
4789
  },
7063
4790
  ];
7064
4791
 
4792
+ function isDynamicFormFeature(value) {
4793
+ return (typeof value === 'object' &&
4794
+ value !== null &&
4795
+ 'ɵkind' in value &&
4796
+ typeof value.ɵkind === 'string' &&
4797
+ 'ɵproviders' in value &&
4798
+ Array.isArray(value.ɵproviders));
4799
+ }
4800
+ function createFeature(kind, providers) {
4801
+ return {
4802
+ ɵkind: kind,
4803
+ ɵproviders: providers,
4804
+ };
4805
+ }
4806
+
7065
4807
  const ADDON_KIND_DEFINITIONS = new InjectionToken('ADDON_KIND_DEFINITIONS');
7066
4808
 
4809
+ class ConsoleLogger {
4810
+ prefix = '[Dynamic Forms]';
4811
+ debug(message, ...args) {
4812
+ console.debug(this.prefix, message, ...args);
4813
+ }
4814
+ info(message, ...args) {
4815
+ console.info(this.prefix, message, ...args);
4816
+ }
4817
+ warn(message, ...args) {
4818
+ console.warn(this.prefix, message, ...args);
4819
+ }
4820
+ error(message, ...args) {
4821
+ console.error(this.prefix, message, ...args);
4822
+ }
4823
+ }
4824
+
7067
4825
  function createWrappers(...registrations) {
7068
4826
  return {
7069
4827
  ɵkind: 'wrappers',
@@ -7166,6 +4924,28 @@ function provideDynamicForm(...items) {
7166
4924
  ]);
7167
4925
  }
7168
4926
 
4927
+ const DERIVATION_LOG_CONFIG = new InjectionToken('DERIVATION_LOG_CONFIG', {
4928
+ providedIn: 'root',
4929
+ factory: createDefaultDerivationLogConfig,
4930
+ });
4931
+ function withLoggerConfig(config = true) {
4932
+ if (typeof config === 'boolean' || typeof config === 'function') {
4933
+ const isEnabled = typeof config === 'function' ? config() : config;
4934
+ const logger = isEnabled ? new ConsoleLogger() : new NoopLogger();
4935
+ return createFeature('logger', [{ provide: DynamicFormLogger, useValue: logger }]);
4936
+ }
4937
+ const isEnabled = config.enabled !== false;
4938
+ const logger = isEnabled ? new ConsoleLogger() : new NoopLogger();
4939
+ const providers = [{ provide: DynamicFormLogger, useValue: logger }];
4940
+ if (config.derivations !== undefined) {
4941
+ providers.push({
4942
+ provide: DERIVATION_LOG_CONFIG,
4943
+ useValue: { level: config.derivations },
4944
+ });
4945
+ }
4946
+ return createFeature('logger', providers);
4947
+ }
4948
+
7169
4949
  function withEventFormValue() {
7170
4950
  return createFeature('event-form-value', [{ provide: EMIT_FORM_VALUE_ON_EVENTS, useValue: true }]);
7171
4951
  }
@@ -7198,21 +4978,29 @@ class DfAddonSlot {
7198
4978
  registry = injectAddonKindRegistry();
7199
4979
  logger = inject(DynamicFormLogger);
7200
4980
  hostInjector = inject(Injector);
7201
- addon = input.required(...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
7202
- fieldInputs = input(...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
7203
- hidden = input(undefined, ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
7204
- slotAttr = computed(() => this.addon().slot, ...(ngDevMode ? [{ debugName: "slotAttr" }] : /* istanbul ignore next */ []));
7205
- className = computed(() => this.addon().className ?? null, ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
4981
+ addon = input.required(/* @ts-ignore */
4982
+ ...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
4983
+ fieldInputs = input(/* @ts-ignore */
4984
+ ...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
4985
+ hidden = input(undefined, /* @ts-ignore */
4986
+ ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
4987
+ slotAttr = computed(() => this.addon().slot, /* @ts-ignore */
4988
+ ...(ngDevMode ? [{ debugName: "slotAttr" }] : /* istanbul ignore next */ []));
4989
+ className = computed(() => this.addon().className ?? null, /* @ts-ignore */
4990
+ ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
7206
4991
  _hiddenByValue = new WeakMap();
7207
- _resolvedHidden = signal(undefined, ...(ngDevMode ? [{ debugName: "_resolvedHidden" }] : /* istanbul ignore next */ []));
4992
+ _resolvedHidden = signal(undefined, /* @ts-ignore */
4993
+ ...(ngDevMode ? [{ debugName: "_resolvedHidden" }] : /* istanbul ignore next */ []));
7208
4994
  isHidden = computed(() => {
7209
4995
  const pre = this.hidden();
7210
4996
  if (pre)
7211
4997
  return pre();
7212
4998
  const local = this._resolvedHidden();
7213
4999
  return local ? local() : false;
7214
- }, ...(ngDevMode ? [{ debugName: "isHidden" }] : /* istanbul ignore next */ []));
7215
- asyncLoaded = signal(undefined, ...(ngDevMode ? [{ debugName: "asyncLoaded" }] : /* istanbul ignore next */ []));
5000
+ }, /* @ts-ignore */
5001
+ ...(ngDevMode ? [{ debugName: "isHidden" }] : /* istanbul ignore next */ []));
5002
+ asyncLoaded = signal(undefined, /* @ts-ignore */
5003
+ ...(ngDevMode ? [{ debugName: "asyncLoaded" }] : /* istanbul ignore next */ []));
7216
5004
  resolvedComponent = computed(() => {
7217
5005
  const kind = this.addon().kind;
7218
5006
  const cached = this.registry.getLoadedKindComponent(kind);
@@ -7220,11 +5008,13 @@ class DfAddonSlot {
7220
5008
  return cached;
7221
5009
  const loaded = this.asyncLoaded();
7222
5010
  return loaded?.kind === kind ? loaded.component : undefined;
7223
- }, ...(ngDevMode ? [{ debugName: "resolvedComponent" }] : /* istanbul ignore next */ []));
5011
+ }, /* @ts-ignore */
5012
+ ...(ngDevMode ? [{ debugName: "resolvedComponent" }] : /* istanbul ignore next */ []));
7224
5013
  kindInputs = computed(() => ({
7225
5014
  addon: this.addon(),
7226
5015
  fieldInputs: this.fieldInputs(),
7227
- }), ...(ngDevMode ? [{ debugName: "kindInputs" }] : /* istanbul ignore next */ []));
5016
+ }), /* @ts-ignore */
5017
+ ...(ngDevMode ? [{ debugName: "kindInputs" }] : /* istanbul ignore next */ []));
7228
5018
  constructor() {
7229
5019
  explicitEffect([this.addon], ([addon]) => {
7230
5020
  const h = addon.hidden;
@@ -7249,14 +5039,14 @@ class DfAddonSlot {
7249
5039
  });
7250
5040
  });
7251
5041
  }
7252
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfAddonSlot, deps: [], target: i0.ɵɵFactoryTarget.Component });
7253
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DfAddonSlot, isStandalone: true, selector: "df-addon-slot", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.slot": "slotAttr()", "class": "className()", "style.display": "isHidden() ? \"none\" : null" } }, ngImport: i0, template: `
5042
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfAddonSlot, deps: [], target: i0.ɵɵFactoryTarget.Component });
5043
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: DfAddonSlot, isStandalone: true, selector: "df-addon-slot", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.slot": "slotAttr()", "class": "className()", "style.display": "isHidden() ? \"none\" : null" } }, ngImport: i0, template: `
7254
5044
  @if (resolvedComponent(); as cmp) {
7255
5045
  <ng-container *ngComponentOutlet="cmp; inputs: kindInputs()" />
7256
5046
  }
7257
5047
  `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7258
5048
  }
7259
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DfAddonSlot, decorators: [{
5049
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfAddonSlot, decorators: [{
7260
5050
  type: Component,
7261
5051
  args: [{
7262
5052
  selector: 'df-addon-slot',
@@ -7276,12 +5066,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
7276
5066
  }], ctorParameters: () => [], propDecorators: { addon: [{ type: i0.Input, args: [{ isSignal: true, alias: "addon", required: true }] }], fieldInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldInputs", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }] } });
7277
5067
 
7278
5068
  class TextAddonComponent {
7279
- addon = input.required(...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
7280
- fieldInputs = input(...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
7281
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TextAddonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7282
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.14", type: TextAddonComponent, isStandalone: true, selector: "df-text-addon", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-hidden": "\"true\"" } }, ngImport: i0, template: `<span>{{ addon().text | dynamicText | async }}</span>`, isInline: true, dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7283
- }
7284
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TextAddonComponent, decorators: [{
5069
+ addon = input.required(/* @ts-ignore */
5070
+ ...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
5071
+ fieldInputs = input(/* @ts-ignore */
5072
+ ...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
5073
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: TextAddonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5074
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.0", type: TextAddonComponent, isStandalone: true, selector: "df-text-addon", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-hidden": "\"true\"" } }, ngImport: i0, template: `<span>{{ addon().text | dynamicText | async }}</span>`, isInline: true, dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5075
+ }
5076
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: TextAddonComponent, decorators: [{
7285
5077
  type: Component,
7286
5078
  args: [{
7287
5079
  selector: 'df-text-addon',
@@ -7302,14 +5094,18 @@ var textAddon_component = /*#__PURE__*/Object.freeze({
7302
5094
  class TemplateAddonComponent {
7303
5095
  templates = inject(DF_FIELD_TEMPLATES, { optional: true });
7304
5096
  logger = inject(DynamicFormLogger);
7305
- addon = input.required(...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
7306
- fieldInputs = input(...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
5097
+ addon = input.required(/* @ts-ignore */
5098
+ ...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
5099
+ fieldInputs = input(/* @ts-ignore */
5100
+ ...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
7307
5101
  template = computed(() => {
7308
5102
  const map = this.templates?.();
7309
5103
  const key = this.addon().templateKey;
7310
5104
  return map?.get(key) ?? null;
7311
- }, ...(ngDevMode ? [{ debugName: "template" }] : /* istanbul ignore next */ []));
7312
- outletContext = computed(() => ({ $implicit: this.fieldInputs() }), ...(ngDevMode ? [{ debugName: "outletContext" }] : /* istanbul ignore next */ []));
5105
+ }, /* @ts-ignore */
5106
+ ...(ngDevMode ? [{ debugName: "template" }] : /* istanbul ignore next */ []));
5107
+ outletContext = computed(() => ({ $implicit: this.fieldInputs() }), /* @ts-ignore */
5108
+ ...(ngDevMode ? [{ debugName: "outletContext" }] : /* istanbul ignore next */ []));
7313
5109
  constructor() {
7314
5110
  explicitEffect([this.template, this.addon], ([tpl, addon]) => {
7315
5111
  if (!tpl) {
@@ -7317,14 +5113,14 @@ class TemplateAddonComponent {
7317
5113
  }
7318
5114
  });
7319
5115
  }
7320
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TemplateAddonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7321
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: TemplateAddonComponent, isStandalone: true, selector: "df-template-addon", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
5116
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: TemplateAddonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5117
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: TemplateAddonComponent, isStandalone: true, selector: "df-template-addon", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
7322
5118
  @if (template(); as tpl) {
7323
5119
  <ng-container *ngTemplateOutlet="tpl; context: outletContext()" />
7324
5120
  }
7325
5121
  `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7326
5122
  }
7327
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TemplateAddonComponent, decorators: [{
5123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: TemplateAddonComponent, decorators: [{
7328
5124
  type: Component,
7329
5125
  args: [{
7330
5126
  selector: 'df-template-addon',
@@ -7345,15 +5141,20 @@ var templateAddon_component = /*#__PURE__*/Object.freeze({
7345
5141
 
7346
5142
  class ComponentAddonComponent {
7347
5143
  logger = inject(DynamicFormLogger);
7348
- addon = input.required(...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
7349
- fieldInputs = input(...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
7350
- inputs = computed(() => (this.addon().inputs ?? {}), ...(ngDevMode ? [{ debugName: "inputs" }] : /* istanbul ignore next */ []));
7351
- asyncLoaded = signal(undefined, ...(ngDevMode ? [{ debugName: "asyncLoaded" }] : /* istanbul ignore next */ []));
5144
+ addon = input.required(/* @ts-ignore */
5145
+ ...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
5146
+ fieldInputs = input(/* @ts-ignore */
5147
+ ...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
5148
+ inputs = computed(() => (this.addon().inputs ?? {}), /* @ts-ignore */
5149
+ ...(ngDevMode ? [{ debugName: "inputs" }] : /* istanbul ignore next */ []));
5150
+ asyncLoaded = signal(undefined, /* @ts-ignore */
5151
+ ...(ngDevMode ? [{ debugName: "asyncLoaded" }] : /* istanbul ignore next */ []));
7352
5152
  resolvedComponent = computed(() => {
7353
5153
  const current = this.addon();
7354
5154
  const loaded = this.asyncLoaded();
7355
5155
  return loaded?.addon === current ? loaded.component : undefined;
7356
- }, ...(ngDevMode ? [{ debugName: "resolvedComponent" }] : /* istanbul ignore next */ []));
5156
+ }, /* @ts-ignore */
5157
+ ...(ngDevMode ? [{ debugName: "resolvedComponent" }] : /* istanbul ignore next */ []));
7357
5158
  constructor() {
7358
5159
  explicitEffect([this.addon], ([addon]) => {
7359
5160
  Promise.resolve(addon.component())
@@ -7367,14 +5168,14 @@ class ComponentAddonComponent {
7367
5168
  });
7368
5169
  });
7369
5170
  }
7370
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ComponentAddonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7371
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ComponentAddonComponent, isStandalone: true, selector: "df-component-addon", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
5171
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ComponentAddonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5172
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: ComponentAddonComponent, isStandalone: true, selector: "df-component-addon", inputs: { addon: { classPropertyName: "addon", publicName: "addon", isSignal: true, isRequired: true, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
7372
5173
  @if (resolvedComponent(); as cmp) {
7373
5174
  <ng-container *ngComponentOutlet="cmp; inputs: inputs()" />
7374
5175
  }
7375
5176
  `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7376
5177
  }
7377
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ComponentAddonComponent, decorators: [{
5178
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ComponentAddonComponent, decorators: [{
7378
5179
  type: Component,
7379
5180
  args: [{
7380
5181
  selector: 'df-component-addon',
@@ -7620,5 +5421,5 @@ const field = createField;
7620
5421
 
7621
5422
 
7622
5423
 
7623
- export { sanitizeFormConfig as $, ADDON_ACTION_HANDLERS as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DfAddonSlot as D, EventDispatcher as E, FormClearEvent as F, formatAddonWarning as G, getFieldDefaultValue as H, InsertArrayItemEvent as I, getNormalizedArrayMetadata as J, injectAddonKindRegistry as K, injectFieldRegistry as L, MoveArrayItemEvent as M, NextPageEvent as N, injectFieldsSupportingAddons as O, PageChangeEvent as P, isSameWrapperChain as Q, RemoveAtIndexEvent as R, ShiftArrayItemEvent as S, TemplateAddonComponent as T, isWrappersBundle as U, logAddonWarnings as V, mapFieldToInputs as W, provideAddonActions as X, provideDynamicForm as Y, resolveWrappers as Z, runPresetAction as _, ADDON_ACTION_REGISTRY as a, sanitizeFormConfigPure as a0, validateFieldAddons as a1, walkAndValidateAddons as a2, withCustomAddon as a3, withEventFormValue as a4, withLegacyStatusClasses as a5, withLoggerConfig as a6, withValidationExecutionDefaults as a7, withValueExclusionDefaults as a8, wrapperProps as a9, ADDON_KIND_COMPONENT_CACHE as b, ADDON_KIND_DEFINITIONS as c, AppendArrayItemEvent as d, ArrayItemRegistryService as e, ComponentAddonComponent as f, ConsoleLogger as g, DfFieldOutlet as h, DfTemplate as i, DynamicForm as j, FormResetEvent as k, PopArrayItemEvent as l, PrependArrayItemEvent as m, PreviousPageEvent as n, SubmitEvent as o, TextAddonComponent as p, arrayEvent as q, createField as r, createFieldResolutionPipe as s, createHiddenSignal as t, createRenderReadySignal as u, createSchemaFromFields as v, createWrapperChainController as w, createWrappers as x, field as y, formConfig as z };
7624
- //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-CNc4a_Xv.mjs.map
5424
+ export { injectAddonKindRegistry as $, ArrayItemRegistryService as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DfFieldOutlet as D, EventDispatcher as E, FormStateManager as F, FormClearEvent as G, FormResetEvent as H, InsertArrayItemEvent as I, PageChangeEvent as J, PopArrayItemEvent as K, PrependArrayItemEvent as L, MoveArrayItemEvent as M, NextPageEvent as N, PreviousPageEvent as O, PROPERTY_OVERRIDE_STORE as P, SubmitEvent as Q, RemoveAtIndexEvent as R, ShiftArrayItemEvent as S, TemplateAddonComponent as T, TextAddonComponent as U, arrayEvent as V, createField as W, createWrappers as X, field as Y, formConfig as Z, formatAddonWarning as _, isSameWrapperChain as a, injectFieldsSupportingAddons as a0, isWrappersBundle as a1, logAddonWarnings as a2, provideAddonActions as a3, provideDynamicForm as a4, runPresetAction as a5, sanitizeFormConfig as a6, sanitizeFormConfigPure as a7, validateFieldAddons as a8, walkAndValidateAddons as a9, withCustomAddon as aa, withEventFormValue as ab, withLegacyStatusClasses as ac, withLoggerConfig as ad, withValidationExecutionDefaults as ae, withValueExclusionDefaults as af, wrapperProps as ag, createWrapperChainController as b, createFieldResolutionPipe as c, createSchemaFromFields as d, createHiddenSignal as e, createRenderReadySignal as f, getNormalizedArrayMetadata as g, getFieldDefaultValue as h, injectFieldRegistry as i, DEV_MODE as j, DEFAULT_DEBOUNCE_MS as k, DERIVATION_WARNING_TRACKER as l, mapFieldToInputs as m, DERIVATION_LOG_CONFIG as n, ADDON_ACTION_HANDLERS as o, ADDON_ACTION_REGISTRY as p, ADDON_KIND_COMPONENT_CACHE as q, resolveWrappers as r, ADDON_KIND_DEFINITIONS as s, traverseFieldsWithContext as t, AppendArrayItemEvent as u, ComponentAddonComponent as v, ConsoleLogger as w, DfAddonSlot as x, DfTemplate as y, DynamicForm as z };
5425
+ //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs.map