@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.
- package/README.md +16 -0
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs → ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs.map → ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs → ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs.map → ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs → ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs} +2 -2
- package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs.map +1 -0
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs +6 -6
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
- package/fesm2022/ng-forge-dynamic-forms-internal.mjs +281 -42
- package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs} +86 -407
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs → ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs.map → ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +2 -2
- package/package.json +3 -3
- package/types/ng-forge-dynamic-forms-integration.d.ts +6 -10
- package/types/ng-forge-dynamic-forms-internal.d.ts +1951 -1750
- package/types/ng-forge-dynamic-forms.d.ts +61 -270
- package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs.map +0 -1
- 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,
|
|
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,
|
|
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
|
|
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-
|
|
826
|
-
import('./ng-forge-dynamic-forms-page-field.component-
|
|
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-
|
|
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) ||
|
|
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) ||
|
|
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
|
-
|
|
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) ||
|
|
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) ||
|
|
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) ||
|
|
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,
|
|
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
|
|
2823
|
-
const
|
|
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
|
|
2837
|
-
if (!
|
|
2836
|
+
const typeDef = typeRegistry.get(addon.type);
|
|
2837
|
+
if (!typeDef) {
|
|
2838
2838
|
warnings.push({
|
|
2839
|
-
type: 'unknown-
|
|
2839
|
+
type: 'unknown-type',
|
|
2840
2840
|
fieldKey: field.key,
|
|
2841
|
-
|
|
2842
|
-
|
|
2841
|
+
addonType: addon.type,
|
|
2842
|
+
registeredTypes,
|
|
2843
2843
|
});
|
|
2844
2844
|
continue;
|
|
2845
2845
|
}
|
|
2846
|
-
if (
|
|
2846
|
+
if (allowedTypes && !allowedTypes.includes(typeDef.type)) {
|
|
2847
2847
|
warnings.push({
|
|
2848
|
-
type: '
|
|
2848
|
+
type: 'type-not-allowed',
|
|
2849
2849
|
fieldKey: field.key,
|
|
2850
2850
|
fieldType,
|
|
2851
|
-
|
|
2852
|
-
|
|
2851
|
+
addonType: typeDef.type,
|
|
2852
|
+
allowedTypes,
|
|
2853
2853
|
});
|
|
2854
2854
|
continue;
|
|
2855
2855
|
}
|
|
2856
|
-
if (source === 'json' &&
|
|
2856
|
+
if (source === 'json' && typeDef.jsonSafe === false) {
|
|
2857
2857
|
warnings.push({
|
|
2858
|
-
type: 'code-only-
|
|
2858
|
+
type: 'code-only-type-in-json',
|
|
2859
2859
|
fieldKey: field.key,
|
|
2860
|
-
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
2911
|
+
if (typeDef.validate) {
|
|
2912
2912
|
try {
|
|
2913
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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-
|
|
2958
|
-
return `${w.type}|${w.fieldKey}|${w.
|
|
2959
|
-
case '
|
|
2960
|
-
return `${w.type}|${w.fieldKey}|${w.fieldType}|${w.
|
|
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.
|
|
2963
|
-
case 'code-only-
|
|
2964
|
-
return `${w.type}|${w.fieldKey}|${w.
|
|
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-
|
|
2980
|
-
return (`Field '${w.fieldKey}': addon
|
|
2981
|
-
`Did you forget withCustomAddon({
|
|
2982
|
-
`Currently registered: ${w.
|
|
2983
|
-
case '
|
|
2984
|
-
return (`Field '${w.fieldKey}' (type: '${w.fieldType}'): addon
|
|
2985
|
-
`Allowed: ${w.
|
|
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
|
|
2988
|
-
case 'code-only-
|
|
2989
|
-
return `Field '${w.fieldKey}': addon
|
|
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(
|
|
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(
|
|
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-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
4638
|
+
throw new DynamicFormError(`Addon type 'text' requires a non-empty 'text' string (field: '${fieldKey}').`);
|
|
4701
4639
|
}
|
|
4702
4640
|
},
|
|
4703
4641
|
},
|
|
4704
4642
|
{
|
|
4705
|
-
|
|
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
|
|
4648
|
+
throw new DynamicFormError(`Addon type 'template' requires a non-empty 'templateKey' string (field: '${fieldKey}').`);
|
|
4711
4649
|
}
|
|
4712
4650
|
},
|
|
4713
4651
|
},
|
|
4714
4652
|
{
|
|
4715
|
-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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:
|
|
4841
|
+
provide: ADDON_TYPE_REGISTRY,
|
|
4906
4842
|
useFactory: () => {
|
|
4907
4843
|
const logger = inject(DynamicFormLogger);
|
|
4908
|
-
const contributed = inject(
|
|
4844
|
+
const contributed = inject(ADDON_TYPE_DEFINITIONS, { optional: true }) ?? [];
|
|
4909
4845
|
const registry = new Map();
|
|
4910
|
-
for (const def of
|
|
4911
|
-
registry.set(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.
|
|
4915
|
-
logger.warn(`Addon
|
|
4850
|
+
if (registry.has(def.type)) {
|
|
4851
|
+
logger.warn(`Addon type "${def.type}" is already registered. Overwriting.`);
|
|
4916
4852
|
}
|
|
4917
|
-
registry.set(def.
|
|
4853
|
+
registry.set(def.type, def);
|
|
4918
4854
|
}
|
|
4919
4855
|
return registry;
|
|
4920
4856
|
},
|
|
4921
4857
|
},
|
|
4922
|
-
{ provide:
|
|
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:
|
|
5045
|
+
provide: ADDON_TYPE_DEFINITIONS,
|
|
5280
5046
|
useValue: definition,
|
|
5281
5047
|
multi: true,
|
|
5282
5048
|
},
|
|
5283
5049
|
]);
|
|
5284
5050
|
}
|
|
5285
5051
|
|
|
5286
|
-
function
|
|
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
|
|
5064
|
+
const typeRegistry = inject(ADDON_TYPE_REGISTRY);
|
|
5299
5065
|
const source = options.source ?? 'inline';
|
|
5300
|
-
const { fields, warnings } = walkAndValidateAddons((config.fields ?? []), fieldRegistry,
|
|
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,
|
|
5082
|
+
function sanitizeFormConfigPure(config, fieldRegistry, typeRegistry, options = {}) {
|
|
5317
5083
|
const source = options.source ?? 'inline';
|
|
5318
|
-
const { fields, warnings } = walkAndValidateAddons((config.fields ?? []), fieldRegistry,
|
|
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 {
|
|
5425
|
-
//# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-
|
|
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
|