@ng-forge/dynamic-forms 1.1.0 → 1.2.0-next.10

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 (50) hide show
  1. package/README.md +11 -11
  2. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-CvjDqYyq.mjs → ng-forge-dynamic-forms-array-field.component-CSCKq_1K.mjs} +9 -13
  3. package/fesm2022/ng-forge-dynamic-forms-array-field.component-CSCKq_1K.mjs.map +1 -0
  4. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CcoUnroD.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CTOTwzzw.mjs} +29 -7
  5. package/fesm2022/ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CTOTwzzw.mjs.map +1 -0
  6. package/fesm2022/ng-forge-dynamic-forms-bootstrap-web-mcp-BtjqeJOj.mjs +1054 -0
  7. package/fesm2022/ng-forge-dynamic-forms-bootstrap-web-mcp-BtjqeJOj.mjs.map +1 -0
  8. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-DZfVWjiM.mjs → ng-forge-dynamic-forms-container-field.component-Dc3ROhHL.mjs} +14 -17
  9. package/fesm2022/ng-forge-dynamic-forms-container-field.component-Dc3ROhHL.mjs.map +1 -0
  10. package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-D_yRuLpu.mjs → ng-forge-dynamic-forms-css-wrapper.component-BzgX8lAD.mjs} +5 -5
  11. package/fesm2022/ng-forge-dynamic-forms-css-wrapper.component-BzgX8lAD.mjs.map +1 -0
  12. package/fesm2022/ng-forge-dynamic-forms-debounce-C9F4v1Ke.mjs +17 -0
  13. package/fesm2022/ng-forge-dynamic-forms-debounce-C9F4v1Ke.mjs.map +1 -0
  14. package/fesm2022/ng-forge-dynamic-forms-field-errors-wrapper.component-CIKbWqYA.mjs +25 -0
  15. package/fesm2022/ng-forge-dynamic-forms-field-errors-wrapper.component-CIKbWqYA.mjs.map +1 -0
  16. package/fesm2022/ng-forge-dynamic-forms-form-schema.service-Dx5Dlb15.mjs +24 -0
  17. package/fesm2022/ng-forge-dynamic-forms-form-schema.service-Dx5Dlb15.mjs.map +1 -0
  18. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-CPFgu3pM.mjs → ng-forge-dynamic-forms-group-field.component-DAC3P9DC.mjs} +9 -13
  19. package/fesm2022/ng-forge-dynamic-forms-group-field.component-DAC3P9DC.mjs.map +1 -0
  20. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +49 -107
  21. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  22. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +434 -139
  23. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  24. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-Du3V5AOb.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-CXQe_5td.mjs} +1930 -1847
  25. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-CXQe_5td.mjs.map +1 -0
  26. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-amWhCdHL.mjs → ng-forge-dynamic-forms-page-field.component-DPKJcwUO.mjs} +94 -15
  27. package/fesm2022/ng-forge-dynamic-forms-page-field.component-DPKJcwUO.mjs.map +1 -0
  28. package/fesm2022/{ng-forge-dynamic-forms-row-wrapper.component-BBWmqQA_.mjs → ng-forge-dynamic-forms-row-wrapper.component-DMEeKZny.mjs} +5 -5
  29. package/fesm2022/ng-forge-dynamic-forms-row-wrapper.component-DMEeKZny.mjs.map +1 -0
  30. package/fesm2022/ng-forge-dynamic-forms-schema-builder-BvDTzfdM.mjs +570 -0
  31. package/fesm2022/ng-forge-dynamic-forms-schema-builder-BvDTzfdM.mjs.map +1 -0
  32. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-C-f80sbk.mjs → ng-forge-dynamic-forms-text-field.component-BB-jutBq.mjs} +4 -4
  33. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-C-f80sbk.mjs.map → ng-forge-dynamic-forms-text-field.component-BB-jutBq.mjs.map} +1 -1
  34. package/fesm2022/ng-forge-dynamic-forms.mjs +2 -2
  35. package/package.json +2 -2
  36. package/types/ng-forge-dynamic-forms-integration.d.ts +15 -33
  37. package/types/ng-forge-dynamic-forms-internal.d.ts +705 -292
  38. package/types/ng-forge-dynamic-forms.d.ts +400 -46
  39. package/fesm2022/ng-forge-dynamic-forms-array-field.component-CvjDqYyq.mjs.map +0 -1
  40. package/fesm2022/ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CcoUnroD.mjs.map +0 -1
  41. package/fesm2022/ng-forge-dynamic-forms-container-field.component-DZfVWjiM.mjs.map +0 -1
  42. package/fesm2022/ng-forge-dynamic-forms-container-utils-BZFz6ztF.mjs +0 -24
  43. package/fesm2022/ng-forge-dynamic-forms-container-utils-BZFz6ztF.mjs.map +0 -1
  44. package/fesm2022/ng-forge-dynamic-forms-css-wrapper.component-D_yRuLpu.mjs.map +0 -1
  45. package/fesm2022/ng-forge-dynamic-forms-emit-initialization-DhHwU6FJ.mjs +0 -17
  46. package/fesm2022/ng-forge-dynamic-forms-emit-initialization-DhHwU6FJ.mjs.map +0 -1
  47. package/fesm2022/ng-forge-dynamic-forms-group-field.component-CPFgu3pM.mjs.map +0 -1
  48. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-Du3V5AOb.mjs.map +0 -1
  49. package/fesm2022/ng-forge-dynamic-forms-page-field.component-amWhCdHL.mjs.map +0 -1
  50. package/fesm2022/ng-forge-dynamic-forms-row-wrapper.component-BBWmqQA_.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, computed, isSignal, inject, Injector, input, signal, ChangeDetectionStrategy, Component, untracked, Injectable, linkedSignal, resourceFromSnapshots, Pipe } from '@angular/core';
2
+ import { InjectionToken, computed, isSignal, inject, Injector, input, signal, ChangeDetectionStrategy, Component, untracked, Injectable, linkedSignal, resourceFromSnapshots, Pipe, viewChild, ViewContainerRef, Directive, forwardRef } from '@angular/core';
3
3
  import { NgComponentOutlet } from '@angular/common';
4
4
  import { explicitEffect } from 'ngxtension/explicit-effect';
5
5
  import { toSignal, toObservable, rxResource } from '@angular/core/rxjs-interop';
6
6
  import { isObservable, defer, combineLatest, pipe, debounceTime, distinctUntilChanged, map, tap, catchError, of, from, startWith, Subject, filter, TimeoutError, throwError } from 'rxjs';
7
7
  import { HttpClient } from '@angular/common/http';
8
- import { email, min, max, minLength, maxLength, pattern, required, validate, validateAsync, validateHttp } from '@angular/forms/signals';
9
- import { scan, map as map$1, filter as filter$1, take, switchMap, timeout, catchError as catchError$1, shareReplay } from 'rxjs/operators';
8
+ import { switchMap, map as map$1, scan, filter as filter$1, take, timeout, catchError as catchError$1, shareReplay } from 'rxjs/operators';
9
+ import { email, min, max, minLength, maxLength, pattern, required, validateTree, validate, validateAsync, validateHttp } from '@angular/forms/signals';
10
10
 
11
11
  const ADDON_TYPE_DEFINITIONS = new InjectionToken('ADDON_TYPE_DEFINITIONS');
12
12
 
@@ -155,14 +155,14 @@ class DfAddonSlot {
155
155
  });
156
156
  });
157
157
  }
158
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: DfAddonSlot, deps: [], target: i0.ɵɵFactoryTarget.Component });
159
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", 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: `
158
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DfAddonSlot, deps: [], target: i0.ɵɵFactoryTarget.Component });
159
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", 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: `
160
160
  @if (resolvedComponent(); as cmp) {
161
161
  <ng-container *ngComponentOutlet="cmp; inputs: typeInputs()" />
162
162
  }
163
163
  `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
164
164
  }
165
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: DfAddonSlot, decorators: [{
165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DfAddonSlot, decorators: [{
166
166
  type: Component,
167
167
  args: [{
168
168
  selector: 'df-addon-slot',
@@ -295,7 +295,11 @@ function hasTargetProperty(config) {
295
295
  }
296
296
 
297
297
  const FORM_VALUE_ACCESS_PATTERN = /\bformValue\s*(?:\.|\[)/;
298
- const FORM_VALUE_PATTERN = /\bformValue\s*(?:\.([\w.]+)|\[\s*'([\w.-]+)'\s*\]|\[\s*"([\w.-]+)"\s*\])/g;
298
+ const ID_START = String.raw `[\p{ID_Start}$_]`;
299
+ const ID_PART = String.raw `[\p{ID_Continue}$]`;
300
+ const DOTTED_PATH = String.raw `${ID_START}${ID_PART}*(?:\.${ID_START}${ID_PART}*)*`;
301
+ const BRACKET_KEY = String.raw `[\p{ID_Continue}$.\-]+`;
302
+ const FORM_VALUE_PATTERN = new RegExp(String.raw `\bformValue\s*(?:\.(${DOTTED_PATH})|\[\s*'(${BRACKET_KEY})'\s*\]|\[\s*"(${BRACKET_KEY})"\s*\])`, 'gu');
299
303
  function isCrossFieldExpression(expr, context) {
300
304
  if (expr === undefined || typeof expr === 'boolean' || isFormStateCondition(expr)) {
301
305
  return false;
@@ -392,15 +396,6 @@ function hasCrossFieldWhenCondition(config, context) {
392
396
  }
393
397
  return isCrossFieldExpression(config.when, context);
394
398
  }
395
- function requiresTreeValidation(config) {
396
- if (isResourceBasedValidator(config)) {
397
- return false;
398
- }
399
- if (config.type === 'custom') {
400
- return isCrossFieldValidator(config);
401
- }
402
- return isCrossFieldBuiltInValidator(config);
403
- }
404
399
  function isCrossFieldStateLogic(config, context) {
405
400
  return isCrossFieldExpression(config.condition, context);
406
401
  }
@@ -585,6 +580,8 @@ class ExpressionParserError extends DynamicFormError {
585
580
  }
586
581
  }
587
582
 
583
+ const IDENTIFIER_START = /[\p{ID_Start}$_]/u;
584
+ const IDENTIFIER_PART = /[\p{ID_Continue}$]/u;
588
585
  class Tokenizer {
589
586
  position = 0;
590
587
  expression;
@@ -617,7 +614,7 @@ class Tokenizer {
617
614
  if (/[0-9]/.test(char)) {
618
615
  return this.readNumber();
619
616
  }
620
- if (/[a-zA-Z_$]/.test(char)) {
617
+ if (IDENTIFIER_START.test(this.codePointAt(this.position))) {
621
618
  return this.readIdentifierOrKeyword();
622
619
  }
623
620
  return this.readOperatorOrPunctuation();
@@ -676,12 +673,20 @@ class Tokenizer {
676
673
  readIdentifierOrKeyword() {
677
674
  const start = this.position;
678
675
  let value = '';
679
- while (this.position < this.expression.length && /[a-zA-Z0-9_$]/.test(this.expression[this.position])) {
680
- value += this.expression[this.position];
681
- this.position++;
676
+ while (this.position < this.expression.length) {
677
+ const char = this.codePointAt(this.position);
678
+ if (!IDENTIFIER_PART.test(char)) {
679
+ break;
680
+ }
681
+ value += char;
682
+ this.position += char.length;
682
683
  }
683
684
  const type = this.getKeywordType(value);
684
685
  return { type, value, position: start };
686
+ }
687
+ codePointAt(position) {
688
+ const codePoint = this.expression.codePointAt(position);
689
+ return codePoint === undefined ? '' : String.fromCodePoint(codePoint);
685
690
  }
686
691
  getKeywordType(value) {
687
692
  switch (value) {
@@ -1570,6 +1575,54 @@ function safeReadPathKeys(fieldContext) {
1570
1575
  return untracked(() => fieldContext.pathKeys());
1571
1576
  }
1572
1577
 
1578
+ function createFieldValueProxy(getRootForm, getRootFormValue) {
1579
+ const resolveAccessor = (key) => {
1580
+ const root = getRootForm();
1581
+ const accessor = root?.[key];
1582
+ return typeof accessor === 'function' ? accessor : undefined;
1583
+ };
1584
+ const readField = (key) => {
1585
+ const accessor = resolveAccessor(key);
1586
+ if (accessor) {
1587
+ const state = untracked(() => accessor());
1588
+ const valueSig = state && state.value;
1589
+ if (typeof valueSig === 'function') {
1590
+ return { hit: true, value: valueSig() };
1591
+ }
1592
+ }
1593
+ return { hit: false, value: undefined };
1594
+ };
1595
+ return new Proxy({}, {
1596
+ get(_target, prop) {
1597
+ if (typeof prop === 'symbol')
1598
+ return undefined;
1599
+ const { hit, value } = readField(prop);
1600
+ return hit ? value : getRootFormValue()[prop];
1601
+ },
1602
+ has(_target, prop) {
1603
+ if (typeof prop === 'symbol')
1604
+ return false;
1605
+ if (resolveAccessor(prop))
1606
+ return true;
1607
+ return prop in getRootFormValue();
1608
+ },
1609
+ ownKeys() {
1610
+ return Reflect.ownKeys(getRootFormValue());
1611
+ },
1612
+ getOwnPropertyDescriptor(_target, prop) {
1613
+ if (typeof prop === 'symbol')
1614
+ return undefined;
1615
+ const whole = getRootFormValue();
1616
+ if (!(prop in whole))
1617
+ return undefined;
1618
+ const { hit, value } = readField(prop);
1619
+ return { value: hit ? value : whole[prop], enumerable: true, configurable: true, writable: false };
1620
+ },
1621
+ set() {
1622
+ return false; },
1623
+ });
1624
+ }
1625
+
1573
1626
  function isChildFieldContext(context) {
1574
1627
  return 'key' in context && isSignal(context.key);
1575
1628
  }
@@ -1580,6 +1633,17 @@ function extractFieldState(fieldContext) {
1580
1633
  return fieldContext.state;
1581
1634
  });
1582
1635
  }
1636
+ function navigateArrayItemTree(root, arrayKey, index) {
1637
+ let node = root;
1638
+ for (const segment of arrayKey.split('.')) {
1639
+ if (node == null)
1640
+ return undefined;
1641
+ node = node[segment];
1642
+ }
1643
+ if (node == null)
1644
+ return undefined;
1645
+ return node[index];
1646
+ }
1583
1647
  function detectArrayScope(pathKeys) {
1584
1648
  if (pathKeys.length < 3)
1585
1649
  return undefined;
@@ -1693,6 +1757,65 @@ class FieldContextRegistryService {
1693
1757
  return formFieldStateGetter();
1694
1758
  },
1695
1759
  };
1760
+ }
1761
+ buildReactiveArrayScopedContext(arrayScope, fieldValue, customFunctions, fieldContext) {
1762
+ const { arrayKey, index, localKey } = arrayScope;
1763
+ const rootFormSignal = this.rootFormRegistry.rootForm;
1764
+ const resolveExternalData = () => this.resolveExternalData();
1765
+ const fieldStateGetter = fieldContext ? () => readFieldStateInfo(extractFieldState(fieldContext), true) : () => undefined;
1766
+ const formFieldStateGetter = () => createFormFieldStateMap(rootFormSignal(), true);
1767
+ const hasValidItem = untracked(() => {
1768
+ const arrayData = getNestedValue(this.rootFormRegistry.formValue(), arrayKey);
1769
+ if (!Array.isArray(arrayData) || index < 0 || index >= arrayData.length)
1770
+ return false;
1771
+ const item = arrayData[index];
1772
+ return item != null && typeof item === 'object';
1773
+ });
1774
+ const rootFormValueProxy = createFieldValueProxy(() => rootFormSignal(), () => this.rootFormRegistry.formValue());
1775
+ if (!hasValidItem) {
1776
+ return {
1777
+ fieldValue,
1778
+ formValue: rootFormValueProxy,
1779
+ fieldPath: localKey,
1780
+ customFunctions: customFunctions || {},
1781
+ logger: this.logger,
1782
+ deprecationTracker: this.deprecationTracker ?? undefined,
1783
+ get externalData() {
1784
+ return resolveExternalData();
1785
+ },
1786
+ get fieldState() {
1787
+ return fieldStateGetter();
1788
+ },
1789
+ get formFieldState() {
1790
+ return formFieldStateGetter();
1791
+ },
1792
+ };
1793
+ }
1794
+ const itemFormValueProxy = createFieldValueProxy(() => navigateArrayItemTree(rootFormSignal(), arrayKey, index), () => {
1795
+ const arrayData = getNestedValue(this.rootFormRegistry.formValue(), arrayKey);
1796
+ const item = Array.isArray(arrayData) ? arrayData[index] : undefined;
1797
+ return item != null && typeof item === 'object' ? item : {};
1798
+ });
1799
+ return {
1800
+ fieldValue,
1801
+ formValue: itemFormValueProxy,
1802
+ rootFormValue: rootFormValueProxy,
1803
+ arrayIndex: index,
1804
+ arrayPath: arrayKey,
1805
+ fieldPath: `${arrayKey}.${index}.${localKey}`,
1806
+ customFunctions: customFunctions || {},
1807
+ logger: this.logger,
1808
+ deprecationTracker: this.deprecationTracker ?? undefined,
1809
+ get externalData() {
1810
+ return resolveExternalData();
1811
+ },
1812
+ get fieldState() {
1813
+ return fieldStateGetter();
1814
+ },
1815
+ get formFieldState() {
1816
+ return formFieldStateGetter();
1817
+ },
1818
+ };
1696
1819
  }
1697
1820
  resolveExternalData() {
1698
1821
  const externalDataSignal = this.externalDataSignal;
@@ -1702,29 +1825,48 @@ class FieldContextRegistryService {
1702
1825
  if (!externalDataRecord) {
1703
1826
  return undefined;
1704
1827
  }
1705
- const resolved = {};
1706
- for (const [key, value] of Object.entries(externalDataRecord)) {
1828
+ const readKey = (key) => {
1829
+ const value = externalDataRecord[key];
1707
1830
  if (!isSignal(value)) {
1708
1831
  throw new DynamicFormError(`externalData["${key}"] must be a Signal. Got: ${typeof value}. Wrap it with signal(yourValue).`);
1709
1832
  }
1710
- resolved[key] = value();
1711
- }
1712
- return resolved;
1833
+ return value();
1834
+ };
1835
+ return new Proxy({}, {
1836
+ get(_target, prop) {
1837
+ if (typeof prop === 'symbol' || !(prop in externalDataRecord))
1838
+ return undefined;
1839
+ return readKey(prop);
1840
+ },
1841
+ has(_target, prop) {
1842
+ return typeof prop === 'string' && prop in externalDataRecord;
1843
+ },
1844
+ ownKeys() {
1845
+ return Reflect.ownKeys(externalDataRecord);
1846
+ },
1847
+ getOwnPropertyDescriptor(_target, prop) {
1848
+ if (typeof prop !== 'string' || !(prop in externalDataRecord))
1849
+ return undefined;
1850
+ return { value: readKey(prop), enumerable: true, configurable: true, writable: false };
1851
+ },
1852
+ set() {
1853
+ return false; },
1854
+ });
1713
1855
  }
1714
1856
  createReactiveEvaluationContext(fieldContext, customFunctions) {
1715
1857
  const fieldValue = fieldContext.value();
1716
- const rootFormValue = this.rootFormRegistry.formValue();
1717
1858
  const pathKeys = safeReadPathKeys(fieldContext);
1718
1859
  const arrayScope = detectArrayScope(pathKeys);
1719
1860
  if (arrayScope) {
1720
- return this.buildArrayScopedContext(rootFormValue, arrayScope, fieldValue, customFunctions, true, fieldContext);
1861
+ return this.buildReactiveArrayScopedContext(arrayScope, fieldValue, customFunctions, fieldContext);
1721
1862
  }
1722
1863
  const localKey = this.extractFieldPath(fieldContext);
1723
1864
  const rootFormSignal = this.rootFormRegistry.rootForm;
1724
1865
  const resolveExternalData = () => this.resolveExternalData();
1866
+ const formValueProxy = createFieldValueProxy(() => rootFormSignal(), () => this.rootFormRegistry.formValue());
1725
1867
  return {
1726
1868
  fieldValue,
1727
- formValue: rootFormValue,
1869
+ formValue: formValueProxy,
1728
1870
  fieldPath: localKey,
1729
1871
  customFunctions: customFunctions || {},
1730
1872
  logger: this.logger,
@@ -1741,15 +1883,15 @@ class FieldContextRegistryService {
1741
1883
  };
1742
1884
  }
1743
1885
  createDisplayOnlyContext(fieldPath, customFunctions, arrayScope) {
1744
- const rootFormValue = this.rootFormRegistry.formValue();
1745
1886
  if (arrayScope) {
1746
- return this.buildArrayScopedContext(rootFormValue, arrayScope, undefined, customFunctions, true);
1887
+ return this.buildReactiveArrayScopedContext(arrayScope, undefined, customFunctions);
1747
1888
  }
1748
1889
  const rootFormSignal = this.rootFormRegistry.rootForm;
1749
1890
  const resolveExternalData = () => this.resolveExternalData();
1891
+ const formValueProxy = createFieldValueProxy(() => rootFormSignal(), () => this.rootFormRegistry.formValue());
1750
1892
  return {
1751
1893
  fieldValue: undefined,
1752
- formValue: rootFormValue,
1894
+ formValue: formValueProxy,
1753
1895
  fieldPath,
1754
1896
  customFunctions: customFunctions || {},
1755
1897
  logger: this.logger,
@@ -1762,10 +1904,10 @@ class FieldContextRegistryService {
1762
1904
  },
1763
1905
  };
1764
1906
  }
1765
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FieldContextRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1766
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FieldContextRegistryService });
1907
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FieldContextRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1908
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FieldContextRegistryService });
1767
1909
  }
1768
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FieldContextRegistryService, decorators: [{
1910
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FieldContextRegistryService, decorators: [{
1769
1911
  type: Injectable
1770
1912
  }] });
1771
1913
 
@@ -1894,10 +2036,10 @@ class FunctionRegistryService {
1894
2036
  this.clearAsyncValidators();
1895
2037
  this.clearHttpValidators();
1896
2038
  }
1897
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FunctionRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1898
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FunctionRegistryService });
2039
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FunctionRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2040
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FunctionRegistryService });
1899
2041
  }
1900
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FunctionRegistryService, decorators: [{
2042
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FunctionRegistryService, decorators: [{
1901
2043
  type: Injectable
1902
2044
  }] });
1903
2045
 
@@ -2523,6 +2665,187 @@ function injectNonFieldEvaluationContext(fieldDef, options = {}) {
2523
2665
  };
2524
2666
  }
2525
2667
 
2668
+ function dynamicTextToObservable(value, injector) {
2669
+ if (value === undefined) {
2670
+ return of('');
2671
+ }
2672
+ if (isObservable(value)) {
2673
+ return value;
2674
+ }
2675
+ if (isSignal(value)) {
2676
+ return untracked(() => toObservable(value, { injector }));
2677
+ }
2678
+ return of(String(value));
2679
+ }
2680
+
2681
+ const PLACEHOLDER_PATTERN = /\{\{([^{}]*)\}\}/g;
2682
+ function interpolateParams(message, error) {
2683
+ const params = extractErrorParams(error);
2684
+ return message.replace(PLACEHOLDER_PATTERN, (placeholder, rawKey) => {
2685
+ const key = rawKey.trim();
2686
+ return Object.hasOwn(params, key) ? safeToString(params[key]) : placeholder;
2687
+ });
2688
+ }
2689
+ function safeToString(value) {
2690
+ if (value === null || value === undefined) {
2691
+ return '';
2692
+ }
2693
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
2694
+ return String(value);
2695
+ }
2696
+ if (value instanceof RegExp) {
2697
+ return value.toString();
2698
+ }
2699
+ if (value instanceof Date) {
2700
+ return value.toISOString();
2701
+ }
2702
+ if (Array.isArray(value)) {
2703
+ return value.join(', ');
2704
+ }
2705
+ try {
2706
+ if (typeof value === 'object' && value.toString !== Object.prototype.toString) {
2707
+ return value.toString();
2708
+ }
2709
+ return JSON.stringify(value);
2710
+ }
2711
+ catch {
2712
+ return '[object]';
2713
+ }
2714
+ }
2715
+ function extractErrorParams(error) {
2716
+ const params = {};
2717
+ if ('min' in error)
2718
+ params.min = error.min;
2719
+ if ('max' in error)
2720
+ params.max = error.max;
2721
+ if ('pattern' in error)
2722
+ params.pattern = error.pattern;
2723
+ if ('actual' in error)
2724
+ params.actual = error.actual;
2725
+ if ('expected' in error)
2726
+ params.expected = error.expected;
2727
+ if ('requiredLength' in error) {
2728
+ params.requiredLength = error.requiredLength;
2729
+ }
2730
+ else if ('minLength' in error) {
2731
+ params.requiredLength = error.minLength;
2732
+ params.minLength = error.minLength;
2733
+ }
2734
+ else if ('maxLength' in error) {
2735
+ params.requiredLength = error.maxLength;
2736
+ params.maxLength = error.maxLength;
2737
+ }
2738
+ if ('actualLength' in error)
2739
+ params.actualLength = error.actualLength;
2740
+ Object.keys(error).forEach((key) => {
2741
+ if (key !== 'kind' && !(key in params)) {
2742
+ params[key] = error[key];
2743
+ }
2744
+ });
2745
+ return params;
2746
+ }
2747
+
2748
+ function createResolvedErrorsSignal(field, validationMessages, defaultValidationMessages = signal(undefined), injector = inject(Injector)) {
2749
+ const logger = injector.get(DynamicFormLogger);
2750
+ const messages = computed(() => validationMessages() ?? {}, /* @ts-ignore */
2751
+ ...(ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []));
2752
+ const defaultMessages = computed(() => defaultValidationMessages() ?? {}, /* @ts-ignore */
2753
+ ...(ngDevMode ? [{ debugName: "defaultMessages" }] : /* istanbul ignore next */ []));
2754
+ const errors = computed(() => field()?.().errors() ?? [], /* @ts-ignore */
2755
+ ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
2756
+ const errors$ = toObservable(errors, { injector });
2757
+ const messages$ = toObservable(messages, { injector });
2758
+ const defaultMessages$ = toObservable(defaultMessages, { injector });
2759
+ const resolvedErrors$ = combineLatest([errors$, messages$, defaultMessages$]).pipe(switchMap(([currentErrors, msgs, defaultMsgs]) => {
2760
+ if (!currentErrors || currentErrors.length === 0) {
2761
+ return of([]);
2762
+ }
2763
+ const errorResolvers = currentErrors.map((error) => resolveErrorMessage(error, msgs, defaultMsgs, injector, logger));
2764
+ return errorResolvers.length > 0
2765
+ ? combineLatest(errorResolvers).pipe(map$1((errors) => errors.filter((e) => e !== null)))
2766
+ : of([]);
2767
+ }));
2768
+ return toSignal(resolvedErrors$, { initialValue: [], injector });
2769
+ }
2770
+ function isMessageResolver(message) {
2771
+ return typeof message === 'function' && !isSignal(message);
2772
+ }
2773
+ function resolveMessageFunction(resolver, error, logger) {
2774
+ try {
2775
+ return resolver(error) ?? error.message ?? '';
2776
+ }
2777
+ catch (err) {
2778
+ logger.error(`Validation message resolver for error kind "${error.kind}" threw; falling back to error.message.`, err);
2779
+ return error.message ?? '';
2780
+ }
2781
+ }
2782
+ function resolveErrorMessage(error, fieldMessages, defaultMessages, injector, logger) {
2783
+ const fieldMessage = fieldMessages[error.kind];
2784
+ const defaultMessage = defaultMessages[error.kind];
2785
+ const messageToUse = fieldMessage ?? defaultMessage ?? error.message;
2786
+ if (!messageToUse) {
2787
+ logger.warn(`No validation message found for error kind "${error.kind}". ` +
2788
+ `Please provide a message via field-level validationMessages or form-level defaultValidationMessages.`);
2789
+ return of(null);
2790
+ }
2791
+ const isSchemaMessage = fieldMessage === undefined && defaultMessage === undefined;
2792
+ const messageText = isMessageResolver(messageToUse) ? resolveMessageFunction(messageToUse, error, logger) : messageToUse;
2793
+ const messageObservable = isSchemaMessage
2794
+ ? of(messageToUse) : dynamicTextToObservable(messageText, injector);
2795
+ return messageObservable.pipe(map$1((msg) => ({
2796
+ kind: error.kind,
2797
+ message: interpolateParams(msg, error),
2798
+ })));
2799
+ }
2800
+
2801
+ function shouldShowErrors(field) {
2802
+ return computed(() => {
2803
+ const control = field()?.();
2804
+ if (!control)
2805
+ return false;
2806
+ return control.invalid() && control.touched() && control.errors().length > 0;
2807
+ });
2808
+ }
2809
+
2810
+ const FIELD_ERROR_DISPLAY = new InjectionToken('FIELD_ERROR_DISPLAY');
2811
+ function injectFieldErrors(options) {
2812
+ const injector = options.injector ?? inject(Injector);
2813
+ const defaultValidationMessages = inject(DEFAULT_VALIDATION_MESSAGES, { optional: true });
2814
+ const fieldSignalContext = inject(FIELD_SIGNAL_CONTEXT, { optional: true });
2815
+ const fieldState = computed(() => {
2816
+ const inputs = options.fieldInputs();
2817
+ if (!inputs)
2818
+ return undefined;
2819
+ if (inputs.field)
2820
+ return inputs.field;
2821
+ const parentTree = fieldSignalContext?.form;
2822
+ const node = inputs.key ? parentTree?.[inputs.key] : undefined;
2823
+ return node ? node() : undefined;
2824
+ }, /* @ts-ignore */
2825
+ ...(ngDevMode ? [{ debugName: "fieldState" }] : /* istanbul ignore next */ []));
2826
+ const fieldTree = computed(() => {
2827
+ const state = fieldState();
2828
+ return state ? (() => state) : undefined;
2829
+ }, /* @ts-ignore */
2830
+ ...(ngDevMode ? [{ debugName: "fieldTree" }] : /* istanbul ignore next */ []));
2831
+ const messages = computed(() => options.validationMessages?.() ?? options.fieldInputs()?.validationMessages, /* @ts-ignore */
2832
+ ...(ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []));
2833
+ const errors = createResolvedErrorsSignal(fieldTree, messages, computed(() => defaultValidationMessages?.()), injector);
2834
+ const showErrors = shouldShowErrors(fieldTree);
2835
+ return {
2836
+ errors,
2837
+ showErrors,
2838
+ errorsToDisplay: computed(() => (showErrors() ? errors() : [])),
2839
+ errorId: computed(() => `${options.fieldInputs()?.key ?? ''}-error`),
2840
+ };
2841
+ }
2842
+
2843
+ function rowError(ctx, index, key, error) {
2844
+ const rows = ctx.fieldTree;
2845
+ const fieldTree = rows?.[index]?.[key];
2846
+ return fieldTree ? { ...error, fieldTree } : error;
2847
+ }
2848
+
2526
2849
  function isFunctionHttpValidator(config) {
2527
2850
  const c = config;
2528
2851
  return typeof c.functionName === 'string' || (c.fn !== null && typeof c.fn === 'object');
@@ -2570,9 +2893,9 @@ function createDynamicValueFunction(expression) {
2570
2893
  return cached;
2571
2894
  }
2572
2895
  const fn = (ctx) => {
2573
- const evaluationContext = fieldContextRegistry.createEvaluationContext(ctx);
2896
+ const evaluationContext = fieldContextRegistry.createReactiveEvaluationContext(ctx);
2574
2897
  try {
2575
- return ExpressionParser.evaluate(expression, evaluationContext);
2898
+ return (ExpressionParser.evaluate(expression, evaluationContext) ?? undefined);
2576
2899
  }
2577
2900
  catch (error) {
2578
2901
  logger.error('Error evaluating dynamic expression:', expression, error);
@@ -2634,11 +2957,9 @@ function applyPatternValidator(path, value, expression, when) {
2634
2957
  function createConditionalLogic(when) {
2635
2958
  return when ? createLogicFunction(when) : undefined;
2636
2959
  }
2637
- function applyValidator(config, fieldPath) {
2960
+ function applyValidator(config,
2961
+ fieldPath, attachment = 'field') {
2638
2962
  const path = fieldPath;
2639
- if (requiresTreeValidation(config)) {
2640
- return;
2641
- }
2642
2963
  switch (config.type) {
2643
2964
  case 'required':
2644
2965
  required(path, config.when ? { when: createConditionalLogic(config.when) } : undefined);
@@ -2684,7 +3005,7 @@ function applyValidator(config, fieldPath) {
2684
3005
  }
2685
3006
  break;
2686
3007
  case 'custom':
2687
- applyCustomValidator(config, path);
3008
+ applyCustomValidator(config, path, attachment);
2688
3009
  break;
2689
3010
  case 'async':
2690
3011
  applyAsyncValidator(config, path);
@@ -2694,7 +3015,7 @@ function applyValidator(config, fieldPath) {
2694
3015
  break;
2695
3016
  }
2696
3017
  }
2697
- function applyCustomValidator(config, fieldPath) {
3018
+ function applyCustomValidator(config, fieldPath, attachment = 'field') {
2698
3019
  let validatorFn;
2699
3020
  if (config.expression) {
2700
3021
  validatorFn = createExpressionValidator(config);
@@ -2706,11 +3027,16 @@ function applyCustomValidator(config, fieldPath) {
2706
3027
  throw new DynamicFormError('Custom validator requires one of "expression", "functionName", or "fn".');
2707
3028
  }
2708
3029
  const whenLogic = createConditionalLogic(config.when);
2709
- validate(fieldPath, (ctx) => {
3030
+ const run = (ctx) => {
2710
3031
  if (whenLogic && !whenLogic(ctx))
2711
3032
  return null;
2712
3033
  return validatorFn(ctx);
2713
- });
3034
+ };
3035
+ if (attachment === 'tree') {
3036
+ validateTree(fieldPath, run);
3037
+ return;
3038
+ }
3039
+ validate(fieldPath, run);
2714
3040
  }
2715
3041
  function createFunctionValidator(config) {
2716
3042
  const logger = inject(DynamicFormLogger);
@@ -2742,7 +3068,7 @@ function createExpressionValidator(config) {
2742
3068
  const functionRegistry = inject(FunctionRegistryService);
2743
3069
  return (ctx) => {
2744
3070
  try {
2745
- const evaluationContext = fieldContextRegistry.createEvaluationContext(ctx, functionRegistry.getCustomFunctions());
3071
+ const evaluationContext = fieldContextRegistry.createReactiveEvaluationContext(ctx, functionRegistry.getCustomFunctions());
2746
3072
  const result = ExpressionParser.evaluate(expression, evaluationContext);
2747
3073
  if (result) {
2748
3074
  return null;
@@ -2862,8 +3188,9 @@ function applyDeclarativeHttpValidator(config, fieldPath) {
2862
3188
  },
2863
3189
  });
2864
3190
  }
2865
- function applyValidators(configs, fieldPath) {
2866
- configs.forEach((config) => applyValidator(config, fieldPath));
3191
+ function applyValidators(configs,
3192
+ fieldPath, attachment = 'field') {
3193
+ configs.forEach((config) => applyValidator(config, fieldPath, attachment));
2867
3194
  }
2868
3195
 
2869
3196
  function isCheckedField(field) {
@@ -3019,10 +3346,10 @@ class EventBus {
3019
3346
  }
3020
3347
  return this.pipeline$.pipe(filter((event) => event.type === eventType));
3021
3348
  }
3022
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: EventBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3023
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: EventBus });
3349
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EventBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3350
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EventBus });
3024
3351
  }
3025
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: EventBus, decorators: [{
3352
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EventBus, decorators: [{
3026
3353
  type: Injectable
3027
3354
  }] });
3028
3355
 
@@ -3079,7 +3406,6 @@ function applyHiddenLogic(inputs, fieldDef, rootFormRegistry, evaluationContext)
3079
3406
  form: rootForm,
3080
3407
  fieldLogic: fieldDef.logic,
3081
3408
  explicitValue: fieldDef.hidden,
3082
- formValue: rootFormRegistry.formValue(),
3083
3409
  evaluationContext,
3084
3410
  });
3085
3411
  }
@@ -3237,6 +3563,10 @@ const WRAPPER_COMPONENT_CACHE = new InjectionToken('WRAPPER_COMPONENT_CACHE', {
3237
3563
  providedIn: 'root',
3238
3564
  factory: () => new Map(),
3239
3565
  });
3566
+ const WRAPPER_COMPONENT_LOAD_CACHE = new InjectionToken('WRAPPER_COMPONENT_LOAD_CACHE', {
3567
+ providedIn: 'root',
3568
+ factory: () => new Map(),
3569
+ });
3240
3570
  const WRAPPER_AUTO_ASSOCIATIONS = new InjectionToken('WRAPPER_AUTO_ASSOCIATIONS', {
3241
3571
  providedIn: 'root',
3242
3572
  factory: () => new Map(),
@@ -3350,28 +3680,15 @@ function isDisplayOnlyField(field) {
3350
3680
  }
3351
3681
 
3352
3682
 
3353
- function dynamicTextToObservable(value, injector) {
3354
- if (value === undefined) {
3355
- return of('');
3356
- }
3357
- if (isObservable(value)) {
3358
- return value;
3359
- }
3360
- if (isSignal(value)) {
3361
- return untracked(() => toObservable(value, { injector }));
3362
- }
3363
- return of(String(value));
3364
- }
3365
-
3366
3683
  class DynamicTextPipe {
3367
3684
  injector = inject(Injector);
3368
3685
  transform(value) {
3369
3686
  return dynamicTextToObservable(value ?? undefined, this.injector);
3370
3687
  }
3371
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: DynamicTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
3372
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.1", ngImport: i0, type: DynamicTextPipe, isStandalone: true, name: "dynamicText" });
3688
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DynamicTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
3689
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.5", ngImport: i0, type: DynamicTextPipe, isStandalone: true, name: "dynamicText" });
3373
3690
  }
3374
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: DynamicTextPipe, decorators: [{
3691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DynamicTextPipe, decorators: [{
3375
3692
  type: Pipe,
3376
3693
  args: [{
3377
3694
  name: 'dynamicText',
@@ -3424,75 +3741,15 @@ function setupInitializationTracking(options) {
3424
3741
  }), shareReplay({ bufferSize: 1, refCount: false }));
3425
3742
  }
3426
3743
 
3427
- function interpolateParams(message, error) {
3428
- let result = message;
3429
- const params = extractErrorParams(error);
3430
- Object.entries(params).forEach(([key, value]) => {
3431
- const placeholder = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
3432
- result = result.replace(placeholder, safeToString(value));
3433
- });
3434
- return result;
3435
- }
3436
- function safeToString(value) {
3437
- if (value === null || value === undefined) {
3438
- return '';
3439
- }
3440
- if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
3441
- return String(value);
3442
- }
3443
- if (value instanceof RegExp) {
3444
- return value.toString();
3445
- }
3446
- if (value instanceof Date) {
3447
- return value.toISOString();
3448
- }
3449
- if (Array.isArray(value)) {
3450
- return value.join(', ');
3451
- }
3452
- try {
3453
- if (typeof value === 'object' && value.toString !== Object.prototype.toString) {
3454
- return value.toString();
3455
- }
3456
- return JSON.stringify(value);
3457
- }
3458
- catch {
3459
- return '[object]';
3460
- }
3461
- }
3462
- function extractErrorParams(error) {
3463
- const params = {};
3464
- if ('min' in error)
3465
- params.min = error.min;
3466
- if ('max' in error)
3467
- params.max = error.max;
3468
- if ('pattern' in error)
3469
- params.pattern = error.pattern;
3470
- if ('actual' in error)
3471
- params.actual = error.actual;
3472
- if ('expected' in error)
3473
- params.expected = error.expected;
3474
- if ('requiredLength' in error) {
3475
- params.requiredLength = error.requiredLength;
3476
- }
3477
- else if ('minLength' in error) {
3478
- params.requiredLength = error.minLength;
3479
- params.minLength = error.minLength;
3480
- }
3481
- else if ('maxLength' in error) {
3482
- params.requiredLength = error.maxLength;
3483
- params.maxLength = error.maxLength;
3484
- }
3485
- if ('actualLength' in error)
3486
- params.actualLength = error.actualLength;
3487
- Object.keys(error).forEach((key) => {
3488
- if (key !== 'kind' && !(key in params)) {
3489
- params[key] = error[key];
3490
- }
3491
- });
3492
- return params;
3493
- }
3494
-
3495
3744
  function isEqual(a, b) {
3745
+ if (a === b)
3746
+ return true;
3747
+ if (typeof a === 'number' && typeof b === 'number')
3748
+ return Object.is(a, b);
3749
+ if (a == null || b == null)
3750
+ return false;
3751
+ if (typeof a !== 'object' || typeof b !== 'object')
3752
+ return Object.is(a, b);
3496
3753
  return isEqualInternal(a, b, new WeakMap(), new WeakMap());
3497
3754
  }
3498
3755
  function isEqualInternal(a, b, seenA, seenB) {
@@ -3654,6 +3911,22 @@ function memoize(fn, resolverOrOptions) {
3654
3911
  function normalizeFieldsArray(fields) {
3655
3912
  return Array.isArray(fields) ? [...fields] : Object.values(fields);
3656
3913
  }
3914
+ function getChangedKeysWithin(previous, current, keys) {
3915
+ const changed = new Set();
3916
+ if (keys.size === 0)
3917
+ return changed;
3918
+ const before = previous ?? {};
3919
+ const after = current ?? {};
3920
+ for (const key of keys) {
3921
+ const inBefore = key in before;
3922
+ const inAfter = key in after;
3923
+ if (!inBefore && !inAfter)
3924
+ continue;
3925
+ if (inBefore !== inAfter || !isEqual(before[key], after[key]))
3926
+ changed.add(key);
3927
+ }
3928
+ return changed;
3929
+ }
3657
3930
  function getChangedKeys(previous, current) {
3658
3931
  const changedKeys = new Set();
3659
3932
  if (!previous && !current)
@@ -3686,7 +3959,29 @@ function createWarningTracker() {
3686
3959
  return { warnedKeys: new Set() };
3687
3960
  }
3688
3961
 
3962
+ class FieldErrorsWrapperBase {
3963
+ fieldComponent = viewChild.required('fieldComponent', { ...(ngDevMode ? { debugName: "fieldComponent" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
3964
+ validationMessages = input(/* @ts-ignore */
3965
+ ...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : /* istanbul ignore next */ []));
3966
+ fieldInputs = input(/* @ts-ignore */
3967
+ ...(ngDevMode ? [undefined, { debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
3968
+ claimedKey = computed(() => this.fieldInputs()?.key, /* @ts-ignore */
3969
+ ...(ngDevMode ? [{ debugName: "claimedKey" }] : /* istanbul ignore next */ []));
3970
+ ngf = injectFieldErrors({
3971
+ fieldInputs: this.fieldInputs,
3972
+ validationMessages: this.validationMessages,
3973
+ });
3974
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FieldErrorsWrapperBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3975
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.1.5", type: FieldErrorsWrapperBase, isStandalone: true, inputs: { validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, fieldInputs: { classPropertyName: "fieldInputs", publicName: "fieldInputs", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "fieldComponent", first: true, predicate: ["fieldComponent"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 });
3976
+ }
3977
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: FieldErrorsWrapperBase, decorators: [{
3978
+ type: Directive
3979
+ }], propDecorators: { fieldComponent: [{ type: i0.ViewChild, args: ['fieldComponent', { ...{ read: ViewContainerRef }, isSignal: true }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], fieldInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldInputs", required: false }] }] } });
3980
+ function provideFieldErrorDisplay(wrapper) {
3981
+ return { provide: FIELD_ERROR_DISPLAY, useExisting: forwardRef(wrapper) };
3982
+ }
3983
+
3689
3984
 
3690
3985
 
3691
- export { ADDON_ACTION_HANDLERS, ADDON_ACTION_REGISTRY, ADDON_TYPE_COMPONENT_CACHE, ADDON_TYPE_DEFINITIONS, ADDON_TYPE_REGISTRY, ARRAY_CONTEXT, AsyncConditionFunctionCacheService, ComponentInitializedEvent, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DEFAULT_WRAPPERS, DEPRECATION_WARNING_TRACKER, DF_FIELD_TEMPLATES, DfAddonSlot, DynamicFormError, DynamicFormLogger, DynamicTextPipe, DynamicValueFunctionCacheService, EMIT_FORM_VALUE_ON_EVENTS, EXTERNAL_DATA, EventBus, ExpressionParser, ExpressionParserError, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_ID_PREFIX, FORM_OPTIONS, FieldContextRegistryService, FunctionRegistryService, GROUP_CONTEXT, HTTP_CONDITION_CACHE, HttpConditionCache, HttpConditionFunctionCacheService, INITIALIZATION_TIMEOUT_MS, LogicFunctionCacheService, NoopLogger, READONLY_FIELD_TREE_CACHE, RootFormRegistryService, TokenType, WRAPPER_AUTO_ASSOCIATIONS, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, applyMetaToElement, applyValidator, applyValidators, arrayFieldMapper, assertNever, baseFieldMapper, buildBaseInputs, buildClassName, compareValues, containerFieldMapper, createAddonActionRegistry, createDebouncedLogicFunction, createDefaultDerivationLogConfig, createDynamicValueFunction, createFormFieldStateMap, createFormStateLogicFunction, createInitializationTracker, createLogicFunction, createWarningTracker, deepMergeDefaults, derivedFromDeferred, detectFormMode, dynamicTextToObservable, evaluateCondition, evaluateNonFieldDisabled, evaluateNonFieldHidden, extractExpressionDependencies, extractStringDependencies, getArrayLength, getChangedKeys, getFieldValueHandling, getGridClassString, getNestedValue, groupFieldMapper, hasChildFields, hasCrossFieldWhenCondition, hasFormValue, hasNestedProperty, hasTargetProperty, injectAddonTypeRegistry, injectFieldSignalContext, injectFieldsSupportingAddons, injectNonFieldEvaluationContext, interpolateParams, isArrayField, isCheckedField, isContainerField, isCrossFieldBuiltInValidator, isCrossFieldExpression, isCrossFieldSchema, isCrossFieldStateLogic, isCrossFieldValidator, isDerivationLogicConfig, isDisplayOnlyField, isEqual, isFieldBoundContext, isFormStateCondition, isFunctionHttpValidator, isGenericContainerField, isGroupField, isHiddenField, isLeafField, isNonPagedForm, isPageField, isPagedForm, isResourceBasedValidator, isRowField, isSimplifiedArrayField, isStateLogicConfig, isValidNonPagedForm, isValidPagedForm, isValueBearingField, isValueField, isWrapperTypeDefinition, keyBy, mapValues, memoize, normalizeFieldsArray, omit, pageFieldMapper, readFieldStateInfo, requiresTreeValidation, resolveDynamicValue, resolveHttpRequest, resolveNextButtonDisabled, resolveNonFieldDisabled, resolveNonFieldHidden, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, runPresetAction, setupInitializationTracking, shouldLog, textFieldMapper, toReadonlyFieldTree, toReadonlyFieldTreeCached, validatePageNesting, withPreviousValue, writeToFieldValue };
3986
+ export { ADDON_ACTION_HANDLERS, ADDON_ACTION_REGISTRY, ADDON_TYPE_COMPONENT_CACHE, ADDON_TYPE_DEFINITIONS, ADDON_TYPE_REGISTRY, ARRAY_CONTEXT, AsyncConditionFunctionCacheService, ComponentInitializedEvent, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DEFAULT_WRAPPERS, DEPRECATION_WARNING_TRACKER, DF_FIELD_TEMPLATES, DfAddonSlot, DynamicFormError, DynamicFormLogger, DynamicTextPipe, DynamicValueFunctionCacheService, EMIT_FORM_VALUE_ON_EVENTS, EXTERNAL_DATA, EventBus, ExpressionParser, ExpressionParserError, FIELD_ERROR_DISPLAY, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_ID_PREFIX, FORM_OPTIONS, FieldContextRegistryService, FieldErrorsWrapperBase, FunctionRegistryService, GROUP_CONTEXT, HTTP_CONDITION_CACHE, HttpConditionCache, HttpConditionFunctionCacheService, INITIALIZATION_TIMEOUT_MS, LogicFunctionCacheService, NoopLogger, READONLY_FIELD_TREE_CACHE, RootFormRegistryService, TokenType, WRAPPER_AUTO_ASSOCIATIONS, WRAPPER_COMPONENT_CACHE, WRAPPER_COMPONENT_LOAD_CACHE, WRAPPER_REGISTRY, applyMetaToElement, applyValidator, applyValidators, arrayFieldMapper, assertNever, baseFieldMapper, buildBaseInputs, buildClassName, compareValues, containerFieldMapper, createAddonActionRegistry, createDebouncedLogicFunction, createDefaultDerivationLogConfig, createDynamicValueFunction, createFieldValueProxy, createFormFieldStateMap, createFormStateLogicFunction, createInitializationTracker, createLogicFunction, createResolvedErrorsSignal, createWarningTracker, deepMergeDefaults, derivedFromDeferred, detectFormMode, dynamicTextToObservable, evaluateCondition, evaluateNonFieldDisabled, evaluateNonFieldHidden, extractExpressionDependencies, extractStringDependencies, getArrayLength, getChangedKeys, getChangedKeysWithin, getFieldValueHandling, getGridClassString, getNestedValue, groupFieldMapper, hasChildFields, hasCrossFieldWhenCondition, hasFormValue, hasNestedProperty, hasTargetProperty, injectAddonTypeRegistry, injectFieldErrors, injectFieldSignalContext, injectFieldsSupportingAddons, injectNonFieldEvaluationContext, interpolateParams, isArrayField, isCheckedField, isContainerField, isCrossFieldBuiltInValidator, isCrossFieldExpression, isCrossFieldSchema, isCrossFieldStateLogic, isCrossFieldValidator, isDerivationLogicConfig, isDisplayOnlyField, isEqual, isFieldBoundContext, isFormStateCondition, isFunctionHttpValidator, isGenericContainerField, isGroupField, isHiddenField, isLeafField, isNonPagedForm, isPageField, isPagedForm, isResourceBasedValidator, isRowField, isSimplifiedArrayField, isStateLogicConfig, isValidNonPagedForm, isValidPagedForm, isValueBearingField, isValueField, isWrapperTypeDefinition, keyBy, mapValues, memoize, normalizeFieldsArray, omit, pageFieldMapper, provideFieldErrorDisplay, readFieldStateInfo, resolveDynamicValue, resolveHttpRequest, resolveNextButtonDisabled, resolveNonFieldDisabled, resolveNonFieldHidden, resolveSubmitButtonDisabled, resolveTokens, rowError, rowFieldMapper, runPresetAction, setupInitializationTracking, shouldLog, shouldShowErrors, textFieldMapper, toReadonlyFieldTree, toReadonlyFieldTreeCached, validatePageNesting, withPreviousValue, writeToFieldValue };
3692
3987
  //# sourceMappingURL=ng-forge-dynamic-forms-internal.mjs.map