@ng-forge/dynamic-forms 1.1.0 → 1.2.0-next.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 (23) hide show
  1. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-CvjDqYyq.mjs → ng-forge-dynamic-forms-array-field.component-BVnXnaNw.mjs} +2 -2
  2. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-CvjDqYyq.mjs.map → ng-forge-dynamic-forms-array-field.component-BVnXnaNw.mjs.map} +1 -1
  3. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CcoUnroD.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CkqvXXs_.mjs} +2 -2
  4. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CcoUnroD.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CkqvXXs_.mjs.map} +1 -1
  5. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-DZfVWjiM.mjs → ng-forge-dynamic-forms-container-field.component-CM1pY9v5.mjs} +2 -2
  6. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-DZfVWjiM.mjs.map → ng-forge-dynamic-forms-container-field.component-CM1pY9v5.mjs.map} +1 -1
  7. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-CPFgu3pM.mjs → ng-forge-dynamic-forms-group-field.component-D4JhDffB.mjs} +2 -2
  8. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-CPFgu3pM.mjs.map → ng-forge-dynamic-forms-group-field.component-D4JhDffB.mjs.map} +1 -1
  9. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +6 -2
  10. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  11. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +149 -28
  12. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  13. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-Du3V5AOb.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-ZiNaCWHl.mjs} +148 -304
  14. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-ZiNaCWHl.mjs.map +1 -0
  15. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-amWhCdHL.mjs → ng-forge-dynamic-forms-page-field.component-Wbz6S8iH.mjs} +47 -9
  16. package/fesm2022/ng-forge-dynamic-forms-page-field.component-Wbz6S8iH.mjs.map +1 -0
  17. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  18. package/package.json +1 -1
  19. package/types/ng-forge-dynamic-forms-integration.d.ts +8 -2
  20. package/types/ng-forge-dynamic-forms-internal.d.ts +63 -11
  21. package/types/ng-forge-dynamic-forms.d.ts +124 -24
  22. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-Du3V5AOb.mjs.map +0 -1
  23. package/fesm2022/ng-forge-dynamic-forms-page-field.component-amWhCdHL.mjs.map +0 -1
@@ -392,15 +392,6 @@ function hasCrossFieldWhenCondition(config, context) {
392
392
  }
393
393
  return isCrossFieldExpression(config.when, context);
394
394
  }
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
395
  function isCrossFieldStateLogic(config, context) {
405
396
  return isCrossFieldExpression(config.condition, context);
406
397
  }
@@ -1570,6 +1561,51 @@ function safeReadPathKeys(fieldContext) {
1570
1561
  return untracked(() => fieldContext.pathKeys());
1571
1562
  }
1572
1563
 
1564
+ function createFieldValueProxy(getRootForm, getRootFormValue) {
1565
+ const readField = (key) => {
1566
+ const root = getRootForm();
1567
+ const accessor = root?.[key];
1568
+ if (typeof accessor === 'function') {
1569
+ const state = untracked(() => accessor());
1570
+ const valueSig = state && state.value;
1571
+ if (typeof valueSig === 'function') {
1572
+ return { hit: true, value: valueSig() };
1573
+ }
1574
+ }
1575
+ return { hit: false, value: undefined };
1576
+ };
1577
+ return new Proxy({}, {
1578
+ get(_target, prop) {
1579
+ if (typeof prop === 'symbol')
1580
+ return undefined;
1581
+ const { hit, value } = readField(prop);
1582
+ return hit ? value : getRootFormValue()[prop];
1583
+ },
1584
+ has(_target, prop) {
1585
+ if (typeof prop === 'symbol')
1586
+ return false;
1587
+ const root = getRootForm();
1588
+ if (root && prop in root)
1589
+ return true;
1590
+ return prop in getRootFormValue();
1591
+ },
1592
+ ownKeys() {
1593
+ return Reflect.ownKeys(getRootFormValue());
1594
+ },
1595
+ getOwnPropertyDescriptor(_target, prop) {
1596
+ if (typeof prop === 'symbol')
1597
+ return undefined;
1598
+ const whole = getRootFormValue();
1599
+ if (!(prop in whole))
1600
+ return undefined;
1601
+ const { hit, value } = readField(prop);
1602
+ return { value: hit ? value : whole[prop], enumerable: true, configurable: true, writable: false };
1603
+ },
1604
+ set() {
1605
+ return false; },
1606
+ });
1607
+ }
1608
+
1573
1609
  function isChildFieldContext(context) {
1574
1610
  return 'key' in context && isSignal(context.key);
1575
1611
  }
@@ -1580,6 +1616,17 @@ function extractFieldState(fieldContext) {
1580
1616
  return fieldContext.state;
1581
1617
  });
1582
1618
  }
1619
+ function navigateArrayItemTree(root, arrayKey, index) {
1620
+ let node = root;
1621
+ for (const segment of arrayKey.split('.')) {
1622
+ if (node == null)
1623
+ return undefined;
1624
+ node = node[segment];
1625
+ }
1626
+ if (node == null)
1627
+ return undefined;
1628
+ return node[index];
1629
+ }
1583
1630
  function detectArrayScope(pathKeys) {
1584
1631
  if (pathKeys.length < 3)
1585
1632
  return undefined;
@@ -1693,6 +1740,65 @@ class FieldContextRegistryService {
1693
1740
  return formFieldStateGetter();
1694
1741
  },
1695
1742
  };
1743
+ }
1744
+ buildReactiveArrayScopedContext(arrayScope, fieldValue, customFunctions, fieldContext) {
1745
+ const { arrayKey, index, localKey } = arrayScope;
1746
+ const rootFormSignal = this.rootFormRegistry.rootForm;
1747
+ const resolveExternalData = () => this.resolveExternalData();
1748
+ const fieldStateGetter = fieldContext ? () => readFieldStateInfo(extractFieldState(fieldContext), true) : () => undefined;
1749
+ const formFieldStateGetter = () => createFormFieldStateMap(rootFormSignal(), true);
1750
+ const hasValidItem = untracked(() => {
1751
+ const arrayData = getNestedValue(this.rootFormRegistry.formValue(), arrayKey);
1752
+ if (!Array.isArray(arrayData) || index < 0 || index >= arrayData.length)
1753
+ return false;
1754
+ const item = arrayData[index];
1755
+ return item != null && typeof item === 'object';
1756
+ });
1757
+ const rootFormValueProxy = createFieldValueProxy(() => rootFormSignal(), () => this.rootFormRegistry.formValue());
1758
+ if (!hasValidItem) {
1759
+ return {
1760
+ fieldValue,
1761
+ formValue: rootFormValueProxy,
1762
+ fieldPath: localKey,
1763
+ customFunctions: customFunctions || {},
1764
+ logger: this.logger,
1765
+ deprecationTracker: this.deprecationTracker ?? undefined,
1766
+ get externalData() {
1767
+ return resolveExternalData();
1768
+ },
1769
+ get fieldState() {
1770
+ return fieldStateGetter();
1771
+ },
1772
+ get formFieldState() {
1773
+ return formFieldStateGetter();
1774
+ },
1775
+ };
1776
+ }
1777
+ const itemFormValueProxy = createFieldValueProxy(() => navigateArrayItemTree(rootFormSignal(), arrayKey, index), () => {
1778
+ const arrayData = getNestedValue(this.rootFormRegistry.formValue(), arrayKey);
1779
+ const item = Array.isArray(arrayData) ? arrayData[index] : undefined;
1780
+ return item != null && typeof item === 'object' ? item : {};
1781
+ });
1782
+ return {
1783
+ fieldValue,
1784
+ formValue: itemFormValueProxy,
1785
+ rootFormValue: rootFormValueProxy,
1786
+ arrayIndex: index,
1787
+ arrayPath: arrayKey,
1788
+ fieldPath: `${arrayKey}.${index}.${localKey}`,
1789
+ customFunctions: customFunctions || {},
1790
+ logger: this.logger,
1791
+ deprecationTracker: this.deprecationTracker ?? undefined,
1792
+ get externalData() {
1793
+ return resolveExternalData();
1794
+ },
1795
+ get fieldState() {
1796
+ return fieldStateGetter();
1797
+ },
1798
+ get formFieldState() {
1799
+ return formFieldStateGetter();
1800
+ },
1801
+ };
1696
1802
  }
1697
1803
  resolveExternalData() {
1698
1804
  const externalDataSignal = this.externalDataSignal;
@@ -1702,29 +1808,48 @@ class FieldContextRegistryService {
1702
1808
  if (!externalDataRecord) {
1703
1809
  return undefined;
1704
1810
  }
1705
- const resolved = {};
1706
- for (const [key, value] of Object.entries(externalDataRecord)) {
1811
+ const readKey = (key) => {
1812
+ const value = externalDataRecord[key];
1707
1813
  if (!isSignal(value)) {
1708
1814
  throw new DynamicFormError(`externalData["${key}"] must be a Signal. Got: ${typeof value}. Wrap it with signal(yourValue).`);
1709
1815
  }
1710
- resolved[key] = value();
1711
- }
1712
- return resolved;
1816
+ return value();
1817
+ };
1818
+ return new Proxy({}, {
1819
+ get(_target, prop) {
1820
+ if (typeof prop === 'symbol' || !(prop in externalDataRecord))
1821
+ return undefined;
1822
+ return readKey(prop);
1823
+ },
1824
+ has(_target, prop) {
1825
+ return typeof prop === 'string' && prop in externalDataRecord;
1826
+ },
1827
+ ownKeys() {
1828
+ return Reflect.ownKeys(externalDataRecord);
1829
+ },
1830
+ getOwnPropertyDescriptor(_target, prop) {
1831
+ if (typeof prop !== 'string' || !(prop in externalDataRecord))
1832
+ return undefined;
1833
+ return { value: readKey(prop), enumerable: true, configurable: true, writable: false };
1834
+ },
1835
+ set() {
1836
+ return false; },
1837
+ });
1713
1838
  }
1714
1839
  createReactiveEvaluationContext(fieldContext, customFunctions) {
1715
1840
  const fieldValue = fieldContext.value();
1716
- const rootFormValue = this.rootFormRegistry.formValue();
1717
1841
  const pathKeys = safeReadPathKeys(fieldContext);
1718
1842
  const arrayScope = detectArrayScope(pathKeys);
1719
1843
  if (arrayScope) {
1720
- return this.buildArrayScopedContext(rootFormValue, arrayScope, fieldValue, customFunctions, true, fieldContext);
1844
+ return this.buildReactiveArrayScopedContext(arrayScope, fieldValue, customFunctions, fieldContext);
1721
1845
  }
1722
1846
  const localKey = this.extractFieldPath(fieldContext);
1723
1847
  const rootFormSignal = this.rootFormRegistry.rootForm;
1724
1848
  const resolveExternalData = () => this.resolveExternalData();
1849
+ const formValueProxy = createFieldValueProxy(() => rootFormSignal(), () => this.rootFormRegistry.formValue());
1725
1850
  return {
1726
1851
  fieldValue,
1727
- formValue: rootFormValue,
1852
+ formValue: formValueProxy,
1728
1853
  fieldPath: localKey,
1729
1854
  customFunctions: customFunctions || {},
1730
1855
  logger: this.logger,
@@ -1741,15 +1866,15 @@ class FieldContextRegistryService {
1741
1866
  };
1742
1867
  }
1743
1868
  createDisplayOnlyContext(fieldPath, customFunctions, arrayScope) {
1744
- const rootFormValue = this.rootFormRegistry.formValue();
1745
1869
  if (arrayScope) {
1746
- return this.buildArrayScopedContext(rootFormValue, arrayScope, undefined, customFunctions, true);
1870
+ return this.buildReactiveArrayScopedContext(arrayScope, undefined, customFunctions);
1747
1871
  }
1748
1872
  const rootFormSignal = this.rootFormRegistry.rootForm;
1749
1873
  const resolveExternalData = () => this.resolveExternalData();
1874
+ const formValueProxy = createFieldValueProxy(() => rootFormSignal(), () => this.rootFormRegistry.formValue());
1750
1875
  return {
1751
1876
  fieldValue: undefined,
1752
- formValue: rootFormValue,
1877
+ formValue: formValueProxy,
1753
1878
  fieldPath,
1754
1879
  customFunctions: customFunctions || {},
1755
1880
  logger: this.logger,
@@ -2570,9 +2695,9 @@ function createDynamicValueFunction(expression) {
2570
2695
  return cached;
2571
2696
  }
2572
2697
  const fn = (ctx) => {
2573
- const evaluationContext = fieldContextRegistry.createEvaluationContext(ctx);
2698
+ const evaluationContext = fieldContextRegistry.createReactiveEvaluationContext(ctx);
2574
2699
  try {
2575
- return ExpressionParser.evaluate(expression, evaluationContext);
2700
+ return (ExpressionParser.evaluate(expression, evaluationContext) ?? undefined);
2576
2701
  }
2577
2702
  catch (error) {
2578
2703
  logger.error('Error evaluating dynamic expression:', expression, error);
@@ -2636,9 +2761,6 @@ function createConditionalLogic(when) {
2636
2761
  }
2637
2762
  function applyValidator(config, fieldPath) {
2638
2763
  const path = fieldPath;
2639
- if (requiresTreeValidation(config)) {
2640
- return;
2641
- }
2642
2764
  switch (config.type) {
2643
2765
  case 'required':
2644
2766
  required(path, config.when ? { when: createConditionalLogic(config.when) } : undefined);
@@ -2742,7 +2864,7 @@ function createExpressionValidator(config) {
2742
2864
  const functionRegistry = inject(FunctionRegistryService);
2743
2865
  return (ctx) => {
2744
2866
  try {
2745
- const evaluationContext = fieldContextRegistry.createEvaluationContext(ctx, functionRegistry.getCustomFunctions());
2867
+ const evaluationContext = fieldContextRegistry.createReactiveEvaluationContext(ctx, functionRegistry.getCustomFunctions());
2746
2868
  const result = ExpressionParser.evaluate(expression, evaluationContext);
2747
2869
  if (result) {
2748
2870
  return null;
@@ -3079,7 +3201,6 @@ function applyHiddenLogic(inputs, fieldDef, rootFormRegistry, evaluationContext)
3079
3201
  form: rootForm,
3080
3202
  fieldLogic: fieldDef.logic,
3081
3203
  explicitValue: fieldDef.hidden,
3082
- formValue: rootFormRegistry.formValue(),
3083
3204
  evaluationContext,
3084
3205
  });
3085
3206
  }
@@ -3688,5 +3809,5 @@ function createWarningTracker() {
3688
3809
 
3689
3810
 
3690
3811
 
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 };
3812
+ 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, createFieldValueProxy, 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, resolveDynamicValue, resolveHttpRequest, resolveNextButtonDisabled, resolveNonFieldDisabled, resolveNonFieldHidden, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, runPresetAction, setupInitializationTracking, shouldLog, textFieldMapper, toReadonlyFieldTree, toReadonlyFieldTreeCached, validatePageNesting, withPreviousValue, writeToFieldValue };
3692
3813
  //# sourceMappingURL=ng-forge-dynamic-forms-internal.mjs.map