@ng-forge/dynamic-forms 1.0.0-rc.1 → 1.0.0-rc.3

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 (24) hide show
  1. package/README.md +16 -0
  2. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs → ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs} +2 -2
  3. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs.map → ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs.map} +1 -1
  4. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs} +2 -2
  5. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs.map} +1 -1
  6. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs → ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs} +2 -2
  7. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs.map → ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs.map} +1 -1
  8. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs → ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs} +2 -2
  9. package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs.map +1 -0
  10. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +6 -6
  11. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  12. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +281 -42
  13. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  14. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs} +86 -407
  15. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs.map +1 -0
  16. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs → ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs} +2 -2
  17. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs.map → ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs.map} +1 -1
  18. package/fesm2022/ng-forge-dynamic-forms.mjs +2 -2
  19. package/package.json +3 -3
  20. package/types/ng-forge-dynamic-forms-integration.d.ts +6 -10
  21. package/types/ng-forge-dynamic-forms-internal.d.ts +1951 -1750
  22. package/types/ng-forge-dynamic-forms.d.ts +61 -270
  23. package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs.map +0 -1
  24. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
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, 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';
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, isGenericContainerField, 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_TYPE_REGISTRY, deepMergeDefaults, derivedFromDeferred, createWarningTracker, RootFormRegistryService, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, EXTERNAL_DATA, DEPRECATION_WARNING_TRACKER, createAddonActionRegistry, ADDON_ACTION_REGISTRY, HttpConditionCache, HTTP_CONDITION_CACHE, HttpConditionFunctionCacheService, AsyncConditionFunctionCacheService, DynamicValueFunctionCacheService, LogicFunctionCacheService, setupInitializationTracking, ComponentInitializedEvent, DF_FIELD_TEMPLATES, rowFieldMapper, groupFieldMapper, arrayFieldMapper, pageFieldMapper, textFieldMapper, containerFieldMapper, isWrapperTypeDefinition, ADDON_TYPE_COMPONENT_CACHE, ADDON_TYPE_DEFINITIONS, createDefaultDerivationLogConfig, NoopLogger, EMIT_FORM_VALUE_ON_EVENTS, DynamicTextPipe, ADDON_ACTION_HANDLERS } from '@ng-forge/dynamic-forms/internal';
5
5
  import { takeUntilDestroyed, toObservable, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
6
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
- import { isPlatformBrowser, NgComponentOutlet, AsyncPipe, NgTemplateOutlet } from '@angular/common';
9
+ import { isPlatformBrowser, AsyncPipe, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
10
10
  import { NG_STATUS_CLASSES } from '@angular/forms/signals/compat';
11
11
 
12
12
  const EMPTY_WRAPPERS = Object.freeze([]);
@@ -422,7 +422,7 @@ function createSubmissionHandler(options) {
422
422
  }));
423
423
  }
424
424
 
425
- class SubmitEvent {
425
+ class FormSubmitEvent {
426
426
  type = 'submit';
427
427
  }
428
428
 
@@ -822,11 +822,11 @@ class PageOrchestratorComponent {
822
822
  }
823
823
  }
824
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)]] });
825
+ import('./ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs').then(m => m.default)], () => [/* @ts-ignore */
826
+ import('./ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs').then(m => m.default)]] });
827
827
  }
828
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: [{
829
+ import('./ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
830
830
  type: Component,
831
831
  args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
832
832
  @for (pageField of pageFields(); track pageField.key; let i = $index) {
@@ -1367,7 +1367,7 @@ function getNumberValidationConfig(fieldDef) {
1367
1367
  }
1368
1368
  function mapFieldToForm(fieldDef, fieldPath, inheritedContext = DEFAULT_FIELD_TREE_MAPPING_CONTEXT) {
1369
1369
  const ownContext = resolveFieldOwnContext(fieldDef, inheritedContext);
1370
- if (isPageField(fieldDef) || isRowField(fieldDef) || isContainerTypedField(fieldDef)) {
1370
+ if (isPageField(fieldDef) || isRowField(fieldDef) || isGenericContainerField(fieldDef)) {
1371
1371
  const descendantContext = resolveDescendantContext(fieldDef, ownContext);
1372
1372
  mapContainerChildren(fieldDef.fields, fieldPath, descendantContext);
1373
1373
  return;
@@ -1389,7 +1389,7 @@ function mapContainerChildren(fields, parentPath, inheritedContext) {
1389
1389
  return;
1390
1390
  const pathRecord = parentPath;
1391
1391
  for (const field of fields) {
1392
- if (isPageField(field) || isRowField(field) || isContainerTypedField(field)) {
1392
+ if (isPageField(field) || isRowField(field) || isGenericContainerField(field)) {
1393
1393
  const layoutOwn = resolveFieldOwnContext(field, inheritedContext);
1394
1394
  const layoutDescendant = resolveDescendantContext(field, layoutOwn);
1395
1395
  mapContainerChildren(field.fields, parentPath, layoutDescendant);
@@ -1510,7 +1510,7 @@ function mapArrayFieldToForm(arrayField, fieldPath, context) {
1510
1510
  }
1511
1511
  else if (isPageField(itemDef) ||
1512
1512
  isRowField(itemDef) ||
1513
- isContainerTypedField(itemDef)) {
1513
+ isGenericContainerField(itemDef)) {
1514
1514
  collectFieldsFromObjectItem([itemDef], allObjectFields);
1515
1515
  }
1516
1516
  else {
@@ -1526,7 +1526,7 @@ function mapArrayFieldToForm(arrayField, fieldPath, context) {
1526
1526
  const itemSchema = schema((itemPath) => {
1527
1527
  const pathRecord = itemPath;
1528
1528
  for (const templateField of allObjectFields) {
1529
- if (isRowField(templateField) || isPageField(templateField) || isContainerTypedField(templateField)) {
1529
+ if (isRowField(templateField) || isPageField(templateField) || isGenericContainerField(templateField)) {
1530
1530
  const layoutOwn = resolveFieldOwnContext(templateField, context);
1531
1531
  const layoutDescendant = resolveDescendantContext(templateField, layoutOwn);
1532
1532
  mapContainerChildren(templateField.fields, itemPath, layoutDescendant);
@@ -1561,7 +1561,7 @@ function mapArrayFieldToForm(arrayField, fieldPath, context) {
1561
1561
  function collectFieldsFromObjectItem(itemFields, allFields) {
1562
1562
  const seenKeys = new Set(allFields.map((f) => f.key).filter(Boolean));
1563
1563
  for (const field of itemFields) {
1564
- if (isRowField(field) || isPageField(field) || isContainerTypedField(field)) {
1564
+ if (isRowField(field) || isPageField(field) || isGenericContainerField(field)) {
1565
1565
  const containerKey = `__container_${field.type}_${JSON.stringify(field.fields?.map((f) => f.key))}`;
1566
1566
  if (!seenKeys.has(containerKey)) {
1567
1567
  seenKeys.add(containerKey);
@@ -2138,7 +2138,7 @@ function flattenFields(fields, registry, options = {}) {
2138
2138
  let autoKeyCounter = 0;
2139
2139
  for (const field of fields) {
2140
2140
  const valueHandling = getFieldValueHandling(field.type, registry);
2141
- if (options.preserveRows && (isRowField(field) || isContainerTypedField(field))) {
2141
+ if (options.preserveRows && (isRowField(field) || isGenericContainerField(field))) {
2142
2142
  if (field.fields) {
2143
2143
  const flattenedChildren = flattenFields(normalizeFieldsArray(field.fields), registry, options);
2144
2144
  const autoPrefix = isRowField(field) ? 'auto_row' : 'auto_container';
@@ -2801,7 +2801,7 @@ function validateFormConfig(fields, registry, logger) {
2801
2801
  }
2802
2802
  }
2803
2803
 
2804
- function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2804
+ function validateFieldAddons(field, fieldRegistry, typeRegistry, source) {
2805
2805
  const warnings = [];
2806
2806
  const incoming = field.addons;
2807
2807
  if (!incoming?.length) {
@@ -2819,8 +2819,8 @@ function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2819
2819
  return { addons: [], warnings };
2820
2820
  }
2821
2821
  const allowedSlots = addonSupport.slots;
2822
- const allowedKinds = addonSupport.allowedKinds;
2823
- const registeredKinds = Array.from(kindRegistry.keys());
2822
+ const allowedTypes = addonSupport.allowedTypes;
2823
+ const registeredTypes = Array.from(typeRegistry.keys());
2824
2824
  const survivors = [];
2825
2825
  for (const addon of incoming) {
2826
2826
  if (!allowedSlots.includes(addon.slot)) {
@@ -2833,31 +2833,31 @@ function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2833
2833
  });
2834
2834
  continue;
2835
2835
  }
2836
- const kindDef = kindRegistry.get(addon.kind);
2837
- if (!kindDef) {
2836
+ const typeDef = typeRegistry.get(addon.type);
2837
+ if (!typeDef) {
2838
2838
  warnings.push({
2839
- type: 'unknown-kind',
2839
+ type: 'unknown-type',
2840
2840
  fieldKey: field.key,
2841
- kind: addon.kind,
2842
- registeredKinds,
2841
+ addonType: addon.type,
2842
+ registeredTypes,
2843
2843
  });
2844
2844
  continue;
2845
2845
  }
2846
- if (allowedKinds && !allowedKinds.includes(kindDef.kind)) {
2846
+ if (allowedTypes && !allowedTypes.includes(typeDef.type)) {
2847
2847
  warnings.push({
2848
- type: 'kind-not-allowed',
2848
+ type: 'type-not-allowed',
2849
2849
  fieldKey: field.key,
2850
2850
  fieldType,
2851
- kind: kindDef.kind,
2852
- allowedKinds,
2851
+ addonType: typeDef.type,
2852
+ allowedTypes,
2853
2853
  });
2854
2854
  continue;
2855
2855
  }
2856
- if (source === 'json' && kindDef.jsonSafe === false) {
2856
+ if (source === 'json' && typeDef.jsonSafe === false) {
2857
2857
  warnings.push({
2858
- type: 'code-only-kind-in-json',
2858
+ type: 'code-only-type-in-json',
2859
2859
  fieldKey: field.key,
2860
- kind: kindDef.kind,
2860
+ addonType: typeDef.type,
2861
2861
  });
2862
2862
  continue;
2863
2863
  }
@@ -2877,7 +2877,7 @@ function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2877
2877
  warnings.push({
2878
2878
  type: 'code-only-action-in-json',
2879
2879
  fieldKey: field.key,
2880
- reason: `function '${key}' on kind '${kindDef.kind}' (use a signal/observable in code, or omit in JSON)`,
2880
+ reason: `function '${key}' on type '${typeDef.type}' (use a signal/observable in code, or omit in JSON)`,
2881
2881
  });
2882
2882
  }
2883
2883
  };
@@ -2887,7 +2887,7 @@ function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2887
2887
  warnings.push({
2888
2888
  type: 'code-only-action-in-json',
2889
2889
  fieldKey: field.key,
2890
- reason: `inline 'action' function on kind '${kindDef.kind}'`,
2890
+ reason: `inline 'action' function on type '${typeDef.type}'`,
2891
2891
  });
2892
2892
  }
2893
2893
  dropReactiveFn('hidden');
@@ -2901,22 +2901,22 @@ function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2901
2901
  warnings.push({
2902
2902
  type: 'code-only-action-in-json',
2903
2903
  fieldKey: field.key,
2904
- reason: `multiple click variants on kind '${kindDef.kind}' (${declaredVariants.join(', ')}); kept '${declaredVariants[0]}'`,
2904
+ reason: `multiple click variants on type '${typeDef.type}' (${declaredVariants.join(', ')}); kept '${declaredVariants[0]}'`,
2905
2905
  });
2906
2906
  }
2907
2907
  if (stripped) {
2908
2908
  survivors.push(sanitized);
2909
2909
  continue;
2910
2910
  }
2911
- if (kindDef.validate) {
2911
+ if (typeDef.validate) {
2912
2912
  try {
2913
- kindDef.validate(addon, field.key);
2913
+ typeDef.validate(addon, field.key);
2914
2914
  }
2915
2915
  catch (error) {
2916
2916
  warnings.push({
2917
2917
  type: 'shape-violation',
2918
2918
  fieldKey: field.key,
2919
- kind: kindDef.kind,
2919
+ addonType: typeDef.type,
2920
2920
  reason: error instanceof Error ? error.message : String(error),
2921
2921
  });
2922
2922
  continue;
@@ -2926,18 +2926,18 @@ function validateFieldAddons(field, fieldRegistry, kindRegistry, source) {
2926
2926
  }
2927
2927
  return { addons: survivors, warnings };
2928
2928
  }
2929
- function walkAndValidateAddons(fields, fieldRegistry, kindRegistry, source) {
2929
+ function walkAndValidateAddons(fields, fieldRegistry, typeRegistry, source) {
2930
2930
  const allWarnings = [];
2931
2931
  const sanitized = fields.map((field) => {
2932
2932
  let next = field;
2933
2933
  if (field.addons?.length) {
2934
- const { addons, warnings } = validateFieldAddons(field, fieldRegistry, kindRegistry, source);
2934
+ const { addons, warnings } = validateFieldAddons(field, fieldRegistry, typeRegistry, source);
2935
2935
  allWarnings.push(...warnings);
2936
2936
  next = { ...next, addons };
2937
2937
  }
2938
2938
  const children = next.fields;
2939
2939
  if (Array.isArray(children)) {
2940
- const { fields: visited, warnings } = walkAndValidateAddons(children, fieldRegistry, kindRegistry, source);
2940
+ const { fields: visited, warnings } = walkAndValidateAddons(children, fieldRegistry, typeRegistry, source);
2941
2941
  allWarnings.push(...warnings);
2942
2942
  next = { ...next, fields: visited };
2943
2943
  }
@@ -2954,14 +2954,14 @@ function addonWarningKey(w) {
2954
2954
  return `${w.type}|${w.fieldKey}|${w.fieldType}`;
2955
2955
  case 'unknown-slot':
2956
2956
  return `${w.type}|${w.fieldKey}|${w.fieldType}|${w.slot}`;
2957
- case 'unknown-kind':
2958
- return `${w.type}|${w.fieldKey}|${w.kind}`;
2959
- case 'kind-not-allowed':
2960
- return `${w.type}|${w.fieldKey}|${w.fieldType}|${w.kind}`;
2957
+ case 'unknown-type':
2958
+ return `${w.type}|${w.fieldKey}|${w.addonType}`;
2959
+ case 'type-not-allowed':
2960
+ return `${w.type}|${w.fieldKey}|${w.fieldType}|${w.addonType}`;
2961
2961
  case 'shape-violation':
2962
- return `${w.type}|${w.fieldKey}|${w.kind}|${w.reason}`;
2963
- case 'code-only-kind-in-json':
2964
- return `${w.type}|${w.fieldKey}|${w.kind}`;
2962
+ return `${w.type}|${w.fieldKey}|${w.addonType}|${w.reason}`;
2963
+ case 'code-only-type-in-json':
2964
+ return `${w.type}|${w.fieldKey}|${w.addonType}`;
2965
2965
  case 'code-only-action-in-json':
2966
2966
  return `${w.type}|${w.fieldKey}|${w.reason}`;
2967
2967
  }
@@ -2976,17 +2976,17 @@ function formatAddonWarning(w) {
2976
2976
  case 'unknown-slot':
2977
2977
  return (`Field '${w.fieldKey}' (type: '${w.fieldType}'): slot '${w.slot}' is not supported. ` +
2978
2978
  `Allowed: ${w.allowedSlots.join(', ')}. Addon dropped.`);
2979
- case 'unknown-kind':
2980
- return (`Field '${w.fieldKey}': addon kind '${w.kind}' is not registered. ` +
2981
- `Did you forget withCustomAddon({ kind: '${w.kind}', ... })? ` +
2982
- `Currently registered: ${w.registeredKinds.join(', ') || '(none)'}. Addon dropped.`);
2983
- case 'kind-not-allowed':
2984
- return (`Field '${w.fieldKey}' (type: '${w.fieldType}'): addon kind '${w.kind}' is not in the allowed list. ` +
2985
- `Allowed: ${w.allowedKinds.join(', ')}. Addon dropped.`);
2979
+ case 'unknown-type':
2980
+ return (`Field '${w.fieldKey}': addon type '${w.addonType}' is not registered. ` +
2981
+ `Did you forget withCustomAddon({ type: '${w.addonType}', ... })? ` +
2982
+ `Currently registered: ${w.registeredTypes.join(', ') || '(none)'}. Addon dropped.`);
2983
+ case 'type-not-allowed':
2984
+ return (`Field '${w.fieldKey}' (type: '${w.fieldType}'): addon type '${w.addonType}' is not in the allowed list. ` +
2985
+ `Allowed: ${w.allowedTypes.join(', ')}. Addon dropped.`);
2986
2986
  case 'shape-violation':
2987
- return `Field '${w.fieldKey}': addon kind '${w.kind}' shape invalid: ${w.reason}. Addon dropped.`;
2988
- case 'code-only-kind-in-json':
2989
- return `Field '${w.fieldKey}': addon kind '${w.kind}' is code-only and cannot be used with JSON-derived configs. Addon dropped.`;
2987
+ return `Field '${w.fieldKey}': addon type '${w.addonType}' shape invalid: ${w.reason}. Addon dropped.`;
2988
+ case 'code-only-type-in-json':
2989
+ return `Field '${w.fieldKey}': addon type '${w.addonType}' is code-only and cannot be used with JSON-derived configs. Addon dropped.`;
2990
2990
  case 'code-only-action-in-json':
2991
2991
  return `Field '${w.fieldKey}': ${w.reason}. Use 'preset' or 'actionRef' instead. Addon dropped.`;
2992
2992
  }
@@ -3537,7 +3537,7 @@ class FormStateManager {
3537
3537
  })();
3538
3538
  valueExclusionDefaults = inject(VALUE_EXCLUSION_DEFAULTS);
3539
3539
  fieldRegistry = injectFieldRegistry();
3540
- addonKindRegistry = inject(ADDON_KIND_REGISTRY);
3540
+ addonKindRegistry = inject(ADDON_TYPE_REGISTRY);
3541
3541
  lastAddonWarningKeys = new Set();
3542
3542
  scheduler = createSideEffectScheduler(this.injector);
3543
3543
  machine;
@@ -3944,7 +3944,7 @@ class FormStateManager {
3944
3944
  this.deps.value.set(emptyValue);
3945
3945
  }
3946
3946
  submit() {
3947
- this.eventBus.dispatch(SubmitEvent);
3947
+ this.eventBus.dispatch(FormSubmitEvent);
3948
3948
  }
3949
3949
  setupEffects() {
3950
3950
  explicitEffect([this.deps.config], ([config]) => {
@@ -4172,7 +4172,7 @@ function createDerivationRenderGate() {
4172
4172
  if (!has || engine() !== 'idle')
4173
4173
  return;
4174
4174
  engine.set('loading');
4175
- pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs')
4175
+ pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs')
4176
4176
  .then(({ bootstrapDerivationOrchestrator }) => {
4177
4177
  runInInjectionContext(injector, () => bootstrapDerivationOrchestrator());
4178
4178
  engine.set('wired');
@@ -4288,19 +4288,6 @@ const DERIVATION_WARNING_TRACKER = new InjectionToken('DerivationWarningTracker'
4288
4288
  factory: createWarningTracker,
4289
4289
  });
4290
4290
 
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);
4299
- }
4300
- }
4301
- return map;
4302
- }
4303
-
4304
4291
  function coreProviders() {
4305
4292
  return [
4306
4293
  EventBus,
@@ -4504,7 +4491,7 @@ class DynamicForm {
4504
4491
  }
4505
4492
  onNativeSubmit(event) {
4506
4493
  event.preventDefault();
4507
- this.eventBus.dispatch(SubmitEvent);
4494
+ this.eventBus.dispatch(FormSubmitEvent);
4508
4495
  }
4509
4496
  setupEffects() {
4510
4497
  explicitEffect([this.formModeDetection, this.pageFieldDefinitions], ([{ mode }, pages]) => {
@@ -4638,87 +4625,38 @@ function countContainersRecursive(fields) {
4638
4625
  return count;
4639
4626
  }
4640
4627
 
4641
- const ADDON_KIND_COMPONENT_CACHE = new InjectionToken('ADDON_KIND_COMPONENT_CACHE');
4642
- function injectAddonKindRegistry() {
4643
- const registry = inject(ADDON_KIND_REGISTRY);
4644
- const componentCache = inject(ADDON_KIND_COMPONENT_CACHE);
4645
- return {
4646
- getKind(kind) {
4647
- return registry.get(kind);
4648
- },
4649
- hasKind(kind) {
4650
- return registry.has(kind);
4651
- },
4652
- getKindNames() {
4653
- return Array.from(registry.keys());
4654
- },
4655
- async loadKindComponent(kind) {
4656
- const definition = registry.get(kind);
4657
- if (!definition) {
4658
- const known = Array.from(registry.keys()).join(', ') || '(none)';
4659
- throw new DynamicFormError(`Addon kind '${kind}' is not registered. Currently registered kinds: ${known}.`);
4660
- }
4661
- const cached = componentCache.get(kind);
4662
- if (cached) {
4663
- return cached;
4664
- }
4665
- try {
4666
- const component = resolveDefaultExport(await definition.loadComponent());
4667
- if (component) {
4668
- componentCache.set(kind, component);
4669
- return component;
4670
- }
4671
- throw new DynamicFormError(`Addon kind '${kind}' loadComponent resolved to null.`);
4672
- }
4673
- catch (error) {
4674
- if (error instanceof DynamicFormError)
4675
- throw error;
4676
- throw new DynamicFormError(`Failed to load component for addon kind '${kind}': ${error instanceof Error ? error.message : String(error)}`);
4677
- }
4678
- },
4679
- getLoadedKindComponent(kind) {
4680
- if (!registry.has(kind))
4681
- return undefined;
4682
- return componentCache.get(kind);
4683
- },
4684
- get raw() {
4685
- return registry;
4686
- },
4687
- };
4688
- }
4689
-
4690
- const BUILT_IN_ADDON_KINDS = [
4628
+ const BUILT_IN_ADDON_TYPES = [
4691
4629
  {
4692
- kind: 'text',
4630
+ type: 'text',
4693
4631
  loadComponent: () => Promise.resolve().then(function () { return textAddon_component; }).then((m) => m.TextAddonComponent),
4694
4632
  validate: (addon, fieldKey) => {
4695
4633
  const text = addon.text;
4696
4634
  if (text === undefined || text === null) {
4697
- throw new DynamicFormError(`Addon kind 'text' requires a 'text' field (field: '${fieldKey}').`);
4635
+ throw new DynamicFormError(`Addon type 'text' requires a 'text' field (field: '${fieldKey}').`);
4698
4636
  }
4699
4637
  if (typeof text === 'string' && text.length === 0) {
4700
- throw new DynamicFormError(`Addon kind 'text' requires a non-empty 'text' string (field: '${fieldKey}').`);
4638
+ throw new DynamicFormError(`Addon type 'text' requires a non-empty 'text' string (field: '${fieldKey}').`);
4701
4639
  }
4702
4640
  },
4703
4641
  },
4704
4642
  {
4705
- kind: 'template',
4643
+ type: 'template',
4706
4644
  loadComponent: () => Promise.resolve().then(function () { return templateAddon_component; }).then((m) => m.TemplateAddonComponent),
4707
4645
  validate: (addon, fieldKey) => {
4708
4646
  const key = addon.templateKey;
4709
4647
  if (typeof key !== 'string' || key.length === 0) {
4710
- throw new DynamicFormError(`Addon kind 'template' requires a non-empty 'templateKey' string (field: '${fieldKey}').`);
4648
+ throw new DynamicFormError(`Addon type 'template' requires a non-empty 'templateKey' string (field: '${fieldKey}').`);
4711
4649
  }
4712
4650
  },
4713
4651
  },
4714
4652
  {
4715
- kind: 'component',
4653
+ type: 'component',
4716
4654
  jsonSafe: false,
4717
4655
  loadComponent: () => Promise.resolve().then(function () { return componentAddon_component; }).then((m) => m.ComponentAddonComponent),
4718
4656
  validate: (addon, fieldKey) => {
4719
4657
  const loader = addon.component;
4720
4658
  if (typeof loader !== 'function') {
4721
- throw new DynamicFormError(`Addon kind 'component' requires a 'component' loader function (field: '${fieldKey}').`);
4659
+ throw new DynamicFormError(`Addon type 'component' requires a 'component' loader function (field: '${fieldKey}').`);
4722
4660
  }
4723
4661
  },
4724
4662
  },
@@ -4733,28 +4671,28 @@ const DISPLAY_FIELD_TYPES_BASE = {
4733
4671
  const BUILT_IN_FIELDS = [
4734
4672
  {
4735
4673
  name: 'row',
4736
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs'),
4674
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs'),
4737
4675
  mapper: rowFieldMapper,
4738
4676
  valueHandling: 'flatten',
4739
4677
  ...CONTAINER_FIELD_TYPES_BASE,
4740
4678
  },
4741
4679
  {
4742
4680
  name: 'group',
4743
- loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs'),
4681
+ loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs'),
4744
4682
  mapper: groupFieldMapper,
4745
4683
  valueHandling: 'include',
4746
4684
  ...CONTAINER_FIELD_TYPES_BASE,
4747
4685
  },
4748
4686
  {
4749
4687
  name: 'array',
4750
- loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs'),
4688
+ loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs'),
4751
4689
  mapper: arrayFieldMapper,
4752
4690
  valueHandling: 'include',
4753
4691
  ...CONTAINER_FIELD_TYPES_BASE,
4754
4692
  },
4755
4693
  {
4756
4694
  name: 'page',
4757
- loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs'),
4695
+ loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs'),
4758
4696
  mapper: pageFieldMapper,
4759
4697
  valueHandling: 'flatten',
4760
4698
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -4772,7 +4710,7 @@ const BUILT_IN_FIELDS = [
4772
4710
  },
4773
4711
  {
4774
4712
  name: 'container',
4775
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs'),
4713
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs'),
4776
4714
  mapper: containerFieldMapper,
4777
4715
  valueHandling: 'flatten',
4778
4716
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -4804,8 +4742,6 @@ function createFeature(kind, providers) {
4804
4742
  };
4805
4743
  }
4806
4744
 
4807
- const ADDON_KIND_DEFINITIONS = new InjectionToken('ADDON_KIND_DEFINITIONS');
4808
-
4809
4745
  class ConsoleLogger {
4810
4746
  prefix = '[Dynamic Forms]';
4811
4747
  debug(message, ...args) {
@@ -4902,24 +4838,24 @@ function provideDynamicForm(...items) {
4902
4838
  },
4903
4839
  },
4904
4840
  {
4905
- provide: ADDON_KIND_REGISTRY,
4841
+ provide: ADDON_TYPE_REGISTRY,
4906
4842
  useFactory: () => {
4907
4843
  const logger = inject(DynamicFormLogger);
4908
- const contributed = inject(ADDON_KIND_DEFINITIONS, { optional: true }) ?? [];
4844
+ const contributed = inject(ADDON_TYPE_DEFINITIONS, { optional: true }) ?? [];
4909
4845
  const registry = new Map();
4910
- for (const def of BUILT_IN_ADDON_KINDS) {
4911
- registry.set(def.kind, def);
4846
+ for (const def of BUILT_IN_ADDON_TYPES) {
4847
+ registry.set(def.type, def);
4912
4848
  }
4913
4849
  for (const def of contributed) {
4914
- if (registry.has(def.kind)) {
4915
- logger.warn(`Addon kind "${def.kind}" is already registered. Overwriting.`);
4850
+ if (registry.has(def.type)) {
4851
+ logger.warn(`Addon type "${def.type}" is already registered. Overwriting.`);
4916
4852
  }
4917
- registry.set(def.kind, def);
4853
+ registry.set(def.type, def);
4918
4854
  }
4919
4855
  return registry;
4920
4856
  },
4921
4857
  },
4922
- { provide: ADDON_KIND_COMPONENT_CACHE, useFactory: () => new Map() },
4858
+ { provide: ADDON_TYPE_COMPONENT_CACHE, useFactory: () => new Map() },
4923
4859
  ...featureProviders,
4924
4860
  ]);
4925
4861
  }
@@ -4974,97 +4910,6 @@ function wrapperProps() {
4974
4910
  return undefined;
4975
4911
  }
4976
4912
 
4977
- class DfAddonSlot {
4978
- registry = injectAddonKindRegistry();
4979
- logger = inject(DynamicFormLogger);
4980
- hostInjector = inject(Injector);
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 */ []));
4991
- _hiddenByValue = new WeakMap();
4992
- _resolvedHidden = signal(undefined, /* @ts-ignore */
4993
- ...(ngDevMode ? [{ debugName: "_resolvedHidden" }] : /* istanbul ignore next */ []));
4994
- isHidden = computed(() => {
4995
- const pre = this.hidden();
4996
- if (pre)
4997
- return pre();
4998
- const local = this._resolvedHidden();
4999
- return local ? local() : false;
5000
- }, /* @ts-ignore */
5001
- ...(ngDevMode ? [{ debugName: "isHidden" }] : /* istanbul ignore next */ []));
5002
- asyncLoaded = signal(undefined, /* @ts-ignore */
5003
- ...(ngDevMode ? [{ debugName: "asyncLoaded" }] : /* istanbul ignore next */ []));
5004
- resolvedComponent = computed(() => {
5005
- const kind = this.addon().kind;
5006
- const cached = this.registry.getLoadedKindComponent(kind);
5007
- if (cached)
5008
- return cached;
5009
- const loaded = this.asyncLoaded();
5010
- return loaded?.kind === kind ? loaded.component : undefined;
5011
- }, /* @ts-ignore */
5012
- ...(ngDevMode ? [{ debugName: "resolvedComponent" }] : /* istanbul ignore next */ []));
5013
- kindInputs = computed(() => ({
5014
- addon: this.addon(),
5015
- fieldInputs: this.fieldInputs(),
5016
- }), /* @ts-ignore */
5017
- ...(ngDevMode ? [{ debugName: "kindInputs" }] : /* istanbul ignore next */ []));
5018
- constructor() {
5019
- explicitEffect([this.addon], ([addon]) => {
5020
- const h = addon.hidden;
5021
- const valueKey = typeof h === 'object' && h !== null ? h : null;
5022
- let resolved = valueKey ? this._hiddenByValue.get(valueKey) : undefined;
5023
- if (!resolved) {
5024
- resolved = resolveDynamicValue(addon.hidden, false, this.hostInjector);
5025
- if (valueKey)
5026
- this._hiddenByValue.set(valueKey, resolved);
5027
- }
5028
- this._resolvedHidden.set(resolved);
5029
- });
5030
- explicitEffect([this.addon], ([addon]) => {
5031
- const kind = addon.kind;
5032
- if (this.registry.getLoadedKindComponent(kind))
5033
- return; this.registry
5034
- .loadKindComponent(kind)
5035
- .then((component) => this.asyncLoaded.set({ kind, component }))
5036
- .catch((error) => {
5037
- this.logger.warn(`Failed to load addon kind '${kind}': ${error instanceof Error ? error.message : String(error)}. ` +
5038
- `Registered kinds: ${this.registry.getKindNames().join(', ') || '(none)'}.`);
5039
- });
5040
- });
5041
- }
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: `
5044
- @if (resolvedComponent(); as cmp) {
5045
- <ng-container *ngComponentOutlet="cmp; inputs: kindInputs()" />
5046
- }
5047
- `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5048
- }
5049
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: DfAddonSlot, decorators: [{
5050
- type: Component,
5051
- args: [{
5052
- selector: 'df-addon-slot',
5053
- imports: [NgComponentOutlet],
5054
- template: `
5055
- @if (resolvedComponent(); as cmp) {
5056
- <ng-container *ngComponentOutlet="cmp; inputs: kindInputs()" />
5057
- }
5058
- `,
5059
- host: {
5060
- '[attr.slot]': 'slotAttr()',
5061
- '[class]': 'className()',
5062
- '[style.display]': 'isHidden() ? "none" : null',
5063
- },
5064
- changeDetection: ChangeDetectionStrategy.OnPush,
5065
- }]
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 }] }] } });
5067
-
5068
4913
  class TextAddonComponent {
5069
4914
  addon = input.required(/* @ts-ignore */
5070
4915
  ...(ngDevMode ? [{ debugName: "addon" }] : /* istanbul ignore next */ []));
@@ -5194,96 +5039,17 @@ var componentAddon_component = /*#__PURE__*/Object.freeze({
5194
5039
  ComponentAddonComponent: ComponentAddonComponent
5195
5040
  });
5196
5041
 
5197
- async function runPresetAction(preset, ctx, collaborators, adapterLabel, fieldLabel) {
5198
- if (ctx.form === null && preset !== 'copy' && preset !== 'paste') {
5199
- collaborators.logger.warn(`preset '${String(preset)}' fired without a host field context — ignoring.`);
5200
- return;
5201
- }
5202
- if (ctx.form !== null && (preset === 'clear' || preset === 'reset' || preset === 'paste') && ctx.form.disabled()) {
5203
- collaborators.logger.warn(`preset '${String(preset)}' skipped — host '${fieldLabel}' is disabled.`);
5204
- return;
5205
- }
5206
- switch (preset) {
5207
- case 'clear': {
5208
- const next = typeof ctx.value === 'string' ? '' : undefined;
5209
- collaborators.fieldValueSetter?.(next);
5210
- return;
5211
- }
5212
- case 'reset': {
5213
- const defaultValue = collaborators.fieldDefaultValueGetter?.();
5214
- collaborators.fieldValueSetter?.(defaultValue !== undefined ? defaultValue : typeof ctx.value === 'string' ? '' : undefined);
5215
- return;
5216
- }
5217
- case 'paste': {
5218
- if (typeof navigator === 'undefined' || !navigator.clipboard) {
5219
- collaborators.logger.warn(`preset 'paste' requires a browser clipboard API (not available in this environment).`);
5220
- return;
5221
- }
5222
- try {
5223
- const text = await navigator.clipboard.readText();
5224
- collaborators.fieldValueSetter?.(text);
5225
- }
5226
- catch (error) {
5227
- collaborators.logger.warn(`preset 'paste' clipboard read failed: ${error instanceof Error ? error.message : String(error)}`);
5228
- }
5229
- return;
5230
- }
5231
- case 'copy': {
5232
- if (typeof navigator === 'undefined' || !navigator.clipboard) {
5233
- collaborators.logger.warn(`preset 'copy' requires a browser clipboard API (not available in this environment).`);
5234
- return;
5235
- }
5236
- try {
5237
- const v = ctx.value;
5238
- await navigator.clipboard.writeText(v == null ? '' : String(v));
5239
- }
5240
- catch (error) {
5241
- collaborators.logger.warn(`preset 'copy' clipboard write failed: ${error instanceof Error ? error.message : String(error)}`);
5242
- }
5243
- return;
5244
- }
5245
- case 'toggle-password-visibility': {
5246
- const override = collaborators.typeOverride;
5247
- if (!override) {
5248
- collaborators.logger.warn(`preset 'toggle-password-visibility' has no effect outside a '${fieldLabel}' field.`);
5249
- return;
5250
- }
5251
- const baseline = collaborators.baselineType?.();
5252
- if (baseline !== undefined && baseline !== 'password') {
5253
- collaborators.logger.warn(`preset 'toggle-password-visibility' refused: host '${fieldLabel}' has type '${baseline}', not 'password'.`);
5254
- return;
5255
- }
5256
- const current = override();
5257
- override.set(current === 'text' ? 'password' : 'text');
5258
- return;
5259
- }
5260
- default:
5261
- collaborators.logger.warn(`preset '${String(preset)}' is not implemented in the ${adapterLabel} adapter.`);
5262
- }
5263
- }
5264
-
5265
- function injectFieldsSupportingAddons() {
5266
- const registry = inject(FIELD_REGISTRY);
5267
- const entries = [];
5268
- for (const [name, def] of registry.entries()) {
5269
- if (def.addons === undefined)
5270
- continue;
5271
- entries.push({ name, slots: def.addons.slots, allowedKinds: def.addons.allowedKinds });
5272
- }
5273
- return entries;
5274
- }
5275
-
5276
5042
  function withCustomAddon(definition) {
5277
5043
  return createFeature('addons', [
5278
5044
  {
5279
- provide: ADDON_KIND_DEFINITIONS,
5045
+ provide: ADDON_TYPE_DEFINITIONS,
5280
5046
  useValue: definition,
5281
5047
  multi: true,
5282
5048
  },
5283
5049
  ]);
5284
5050
  }
5285
5051
 
5286
- function provideAddonActions(handlers) {
5052
+ function withAddonActions(handlers) {
5287
5053
  return createFeature('addon-actions', [
5288
5054
  {
5289
5055
  provide: ADDON_ACTION_HANDLERS,
@@ -5295,9 +5061,9 @@ function provideAddonActions(handlers) {
5295
5061
 
5296
5062
  function sanitizeFormConfig(config, options = {}) {
5297
5063
  const fieldRegistry = inject(FIELD_REGISTRY);
5298
- const kindRegistry = inject(ADDON_KIND_REGISTRY);
5064
+ const typeRegistry = inject(ADDON_TYPE_REGISTRY);
5299
5065
  const source = options.source ?? 'inline';
5300
- const { fields, warnings } = walkAndValidateAddons((config.fields ?? []), fieldRegistry, kindRegistry, source);
5066
+ const { fields, warnings } = walkAndValidateAddons((config.fields ?? []), fieldRegistry, typeRegistry, source);
5301
5067
  return {
5302
5068
  sanitized: { ...config, fields: fields },
5303
5069
  warnings,
@@ -5313,9 +5079,9 @@ function logAddonWarnings(warnings, logger) {
5313
5079
  }
5314
5080
  }
5315
5081
  }
5316
- function sanitizeFormConfigPure(config, fieldRegistry, kindRegistry, options = {}) {
5082
+ function sanitizeFormConfigPure(config, fieldRegistry, typeRegistry, options = {}) {
5317
5083
  const source = options.source ?? 'inline';
5318
- const { fields, warnings } = walkAndValidateAddons((config.fields ?? []), fieldRegistry, kindRegistry, source);
5084
+ const { fields, warnings } = walkAndValidateAddons((config.fields ?? []), fieldRegistry, typeRegistry, source);
5319
5085
  return { sanitized: { ...config, fields: fields }, warnings };
5320
5086
  }
5321
5087
 
@@ -5332,94 +5098,7 @@ function arrayEvent(arrayKey) {
5332
5098
  }
5333
5099
 
5334
5100
 
5335
- function formConfig(config) {
5336
- return config;
5337
- }
5338
-
5339
- const CONTAINER_TYPES = ['group', 'row', 'array', 'container'];
5340
- const HIDDEN_ONLY_LOGIC_TYPES = ['group', 'row', 'array', 'container', 'page'];
5341
- const OPTION_FIELD_TYPES = ['select', 'radio', 'multi-checkbox'];
5342
- const SLIDER_TYPE = 'slider';
5343
- const HIDDEN_TYPE = 'hidden';
5344
- function createField(type, config) {
5345
- const configWithProps = config;
5346
- if (!configWithProps['key']) {
5347
- throw new DynamicFormError(`createField('${type}'): 'key' property is required`);
5348
- }
5349
- if (CONTAINER_TYPES.includes(type)) {
5350
- if ('label' in configWithProps && configWithProps['label'] !== undefined) {
5351
- throw new DynamicFormError(`createField('${type}'): Container fields (${CONTAINER_TYPES.join(', ')}) do NOT support 'label'. ` +
5352
- `Labels go on the child fields inside the container.`);
5353
- }
5354
- }
5355
- if (HIDDEN_ONLY_LOGIC_TYPES.includes(type)) {
5356
- if ('logic' in configWithProps && configWithProps['logic'] !== undefined) {
5357
- const logic = configWithProps['logic'];
5358
- if (Array.isArray(logic)) {
5359
- const nonHiddenLogic = logic.filter((l) => l.type !== 'hidden');
5360
- if (nonHiddenLogic.length > 0) {
5361
- throw new DynamicFormError(`createField('${type}'): Only 'hidden' logic type is supported. ` +
5362
- `Found unsupported logic types: ${nonHiddenLogic.map((l) => l.type).join(', ')}. ` +
5363
- `For other logic types, apply them to child fields instead.`);
5364
- }
5365
- }
5366
- }
5367
- }
5368
- if (OPTION_FIELD_TYPES.includes(type)) {
5369
- const props = configWithProps['props'];
5370
- if (props && 'options' in props) {
5371
- throw new DynamicFormError(`createField('${type}'): 'options' must be at FIELD level, NOT inside 'props'. ` +
5372
- `Move 'options' from props to the field root: { type: '${type}', key: '...', options: [...] }`);
5373
- }
5374
- }
5375
- if (type === SLIDER_TYPE) {
5376
- const props = configWithProps['props'];
5377
- if (props) {
5378
- if ('min' in props || 'max' in props) {
5379
- throw new DynamicFormError(`createField('slider'): Use 'minValue' and 'maxValue' at FIELD level, NOT 'min'/'max' in props. ` +
5380
- `Example: { type: 'slider', key: '...', minValue: 0, maxValue: 100, step: 1 }`);
5381
- }
5382
- if ('step' in props) {
5383
- throw new DynamicFormError(`createField('slider'): Use 'step' at FIELD level, NOT in props. ` +
5384
- `Example: { type: 'slider', key: '...', minValue: 0, maxValue: 100, step: 1 }`);
5385
- }
5386
- }
5387
- }
5388
- if (type === HIDDEN_TYPE) {
5389
- if ('logic' in configWithProps && configWithProps['logic'] !== undefined) {
5390
- throw new DynamicFormError(`createField('hidden'): Hidden fields do NOT support 'logic'. ` + `Hidden fields are purely for passing values through the form.`);
5391
- }
5392
- if ('validators' in configWithProps && configWithProps['validators'] !== undefined) {
5393
- throw new DynamicFormError(`createField('hidden'): Hidden fields do NOT support 'validators'. ` +
5394
- `Hidden fields are purely for passing values through the form.`);
5395
- }
5396
- if ('required' in configWithProps && configWithProps['required']) {
5397
- throw new DynamicFormError(`createField('hidden'): Hidden fields do NOT support 'required' validation. ` +
5398
- `Hidden fields are purely for passing values through the form.`);
5399
- }
5400
- if ('label' in configWithProps && configWithProps['label'] !== undefined) {
5401
- throw new DynamicFormError(`createField('hidden'): Hidden fields do NOT support 'label'. ` +
5402
- `Hidden fields are not rendered and have no visual representation.`);
5403
- }
5404
- }
5405
- if (type === 'array') {
5406
- if ('template' in configWithProps) {
5407
- throw new DynamicFormError(`createField('array'): Use 'fields' (NOT 'template') to define the array item structure. ` +
5408
- `Example: { type: 'array', key: '...', fields: [{ type: 'group', key: 'item', fields: [...] }] }`);
5409
- }
5410
- }
5411
- if (type === 'button') {
5412
- if (!('event' in configWithProps) || configWithProps['event'] === undefined) {
5413
- throw new DynamicFormError(`createField('button'): Generic buttons REQUIRE the 'event' property with a FormEventConstructor. ` +
5414
- `For common actions, use 'submit', 'next', or 'previous' instead which don't require event configuration. ` +
5415
- `Example: { type: 'submit', key: 'submit', label: 'Submit' }`);
5416
- }
5417
- }
5418
- return { type, ...config };
5419
- }
5420
- const field = createField;
5421
-
5422
5101
 
5423
5102
 
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
5103
+ export { withValueExclusionDefaults as $, ArrayItemRegistryService as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DfFieldOutlet as D, EventDispatcher as E, FormStateManager as F, PrependArrayItemEvent as G, PreviousPageEvent as H, InsertArrayItemEvent as I, TextAddonComponent as J, arrayEvent as K, createWrappers as L, MoveArrayItemEvent as M, NextPageEvent as N, isWrappersBundle as O, PROPERTY_OVERRIDE_STORE as P, provideDynamicForm as Q, RemoveAtIndexEvent as R, ShiftArrayItemEvent as S, TemplateAddonComponent as T, sanitizeFormConfig as U, withAddonActions as V, withCustomAddon as W, withEventFormValue as X, withLegacyStatusClasses as Y, withLoggerConfig as Z, withValidationExecutionDefaults as _, isSameWrapperChain as a, wrapperProps as a0, 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, AppendArrayItemEvent as o, ComponentAddonComponent as p, ConsoleLogger as q, resolveWrappers as r, DfTemplate as s, traverseFieldsWithContext as t, DynamicForm as u, FormClearEvent as v, FormResetEvent as w, FormSubmitEvent as x, PageChangeEvent as y, PopArrayItemEvent as z };
5104
+ //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs.map