@ng-forge/dynamic-forms 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/README.md +7 -5
  2. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +79 -6
  3. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  4. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-CZBdtTAU.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs} +375 -78
  5. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs.map +1 -0
  6. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs → ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs} +13 -7
  7. package/fesm2022/ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs.map +1 -0
  8. package/fesm2022/{ng-forge-dynamic-forms-testing-test-button.harness-CbctXjtc.mjs → ng-forge-dynamic-forms-testing-test-button.harness-0iXHLraC.mjs} +7 -7
  9. package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-0iXHLraC.mjs.map +1 -0
  10. package/fesm2022/ng-forge-dynamic-forms-testing.mjs +25 -25
  11. package/fesm2022/ng-forge-dynamic-forms-testing.mjs.map +1 -1
  12. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-C0I8jf9T.mjs → ng-forge-dynamic-forms-text-field.component-CfDZFTyf.mjs} +5 -5
  13. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-C0I8jf9T.mjs.map → ng-forge-dynamic-forms-text-field.component-CfDZFTyf.mjs.map} +1 -1
  14. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  15. package/package.json +4 -4
  16. package/types/ng-forge-dynamic-forms-integration.d.ts +225 -9
  17. package/types/ng-forge-dynamic-forms-testing.d.ts +32 -1
  18. package/types/ng-forge-dynamic-forms.d.ts +211 -18
  19. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-CZBdtTAU.mjs.map +0 -1
  20. package/fesm2022/ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs.map +0 -1
  21. package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-CbctXjtc.mjs.map +0 -1
@@ -1,11 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { isSignal, computed, runInInjectionContext, InjectionToken, inject, signal, Injectable, untracked, input, linkedSignal, ChangeDetectionStrategy, Component, DestroyRef, Injector, model, afterNextRender, makeEnvironmentProviders, Pipe } from '@angular/core';
3
3
  import { NgComponentOutlet } from '@angular/common';
4
- import { submit, email, min, max, minLength, maxLength, pattern, required, validate, validateAsync, validateHttp, disabled, readonly, hidden, applyEach, applyWhenValue, applyWhen, apply, schema, validateTree, form } from '@angular/forms/signals';
4
+ import { submit, email, min, max, minLength, maxLength, pattern, required, validate, validateAsync, validateHttp, disabled, readonly, hidden, applyEach, applyWhenValue, applyWhen, apply, schema, validateTree, form, provideSignalFormsConfig } from '@angular/forms/signals';
5
5
  import { toObservable, toSignal, takeUntilDestroyed, outputFromObservable } from '@angular/core/rxjs-interop';
6
6
  import { defer, combineLatest, from, map, catchError, of, pipe, switchMap, forkJoin, scan, isObservable, firstValueFrom, EMPTY, Subject, filter } from 'rxjs';
7
7
  import { scan as scan$1, map as map$1, filter as filter$1, take, switchMap as switchMap$1, shareReplay } from 'rxjs/operators';
8
8
  import { explicitEffect } from 'ngxtension/explicit-effect';
9
+ import { NG_STATUS_CLASSES } from '@angular/forms/signals/compat';
9
10
 
10
11
  /**
11
12
  * Type guard to check if a value is an array of Signals.
@@ -82,6 +83,48 @@ function getGridClassString(fieldDef) {
82
83
  }
83
84
  return '';
84
85
  }
86
+ /**
87
+ * Builds a combined className string from a field definition.
88
+ *
89
+ * Combines user-provided className with generated grid classes into a single string.
90
+ * Returns undefined if no classes are present (allowing conditional spreading in objects).
91
+ *
92
+ * @param fieldDef - Field definition containing className and col properties
93
+ * @returns Combined class string, or undefined if no classes
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * // With both className and col
98
+ * buildClassName({ key: 'test', type: 'group', className: 'my-class', col: 6 });
99
+ * // Returns: 'df-col-6 my-class'
100
+ *
101
+ * // With only className
102
+ * buildClassName({ key: 'test', type: 'group', className: 'my-class' });
103
+ * // Returns: 'my-class'
104
+ *
105
+ * // With only col
106
+ * buildClassName({ key: 'test', type: 'group', col: 6 });
107
+ * // Returns: 'df-col-6'
108
+ *
109
+ * // With neither
110
+ * buildClassName({ key: 'test', type: 'group' });
111
+ * // Returns: undefined
112
+ * ```
113
+ *
114
+ * @public
115
+ */
116
+ function buildClassName(fieldDef) {
117
+ const gridClass = getGridClassString(fieldDef);
118
+ const userClass = fieldDef.className;
119
+ const classes = [];
120
+ if (gridClass) {
121
+ classes.push(gridClass);
122
+ }
123
+ if (userClass) {
124
+ classes.push(userClass);
125
+ }
126
+ return classes.length > 0 ? classes.join(' ') : undefined;
127
+ }
85
128
 
86
129
  /**
87
130
  * Builds base input properties from a field definition.
@@ -93,7 +136,7 @@ function getGridClassString(fieldDef) {
93
136
  * @returns Record of input names to values
94
137
  */
95
138
  function buildBaseInputs(fieldDef) {
96
- const { key, label, className, tabIndex, props } = fieldDef;
139
+ const { key, label, className, tabIndex, props, meta } = fieldDef;
97
140
  const inputs = {};
98
141
  // Always include key - required by components for accessibility and identification
99
142
  inputs['key'] = key;
@@ -118,6 +161,9 @@ function buildBaseInputs(fieldDef) {
118
161
  if (props !== undefined) {
119
162
  inputs['props'] = props;
120
163
  }
164
+ if (meta !== undefined) {
165
+ inputs['meta'] = meta;
166
+ }
121
167
  return inputs;
122
168
  }
123
169
  /**
@@ -135,6 +181,43 @@ function baseFieldMapper(fieldDef) {
135
181
  return computed(() => buildBaseInputs(fieldDef));
136
182
  }
137
183
 
184
+ /**
185
+ * Merges forwarded props into meta, with meta taking precedence.
186
+ *
187
+ * @param inputs The current inputs record
188
+ * @param propsToMeta Array of prop keys to forward to meta
189
+ * @returns Updated inputs record with merged meta
190
+ */
191
+ function mergeForwardedPropsToMeta(inputs, propsToMeta) {
192
+ const props = inputs['props'];
193
+ if (!props || propsToMeta.length === 0) {
194
+ return inputs;
195
+ }
196
+ // Extract values to forward from props
197
+ // Values are typed as FieldMeta-compatible since they're forwarded attributes (type, rows, cols, etc.)
198
+ const forwardedValues = {};
199
+ for (const key of propsToMeta) {
200
+ const value = props[key];
201
+ if (value !== undefined && value !== null) {
202
+ // Props being forwarded are known HTML attributes (string, number, boolean)
203
+ forwardedValues[key] = value;
204
+ }
205
+ }
206
+ // If nothing to forward, return inputs unchanged
207
+ if (Object.keys(forwardedValues).length === 0) {
208
+ return inputs;
209
+ }
210
+ // Merge: forwarded props first, then meta (meta wins)
211
+ const existingMeta = inputs['meta'];
212
+ const mergedMeta = {
213
+ ...forwardedValues,
214
+ ...existingMeta,
215
+ };
216
+ return {
217
+ ...inputs,
218
+ meta: mergedMeta,
219
+ };
220
+ }
138
221
  /**
139
222
  * Main field mapper function that uses the field registry to get the appropriate mapper
140
223
  * based on the field's type property.
@@ -142,30 +225,49 @@ function baseFieldMapper(fieldDef) {
142
225
  * This function must be called within an injection context where FIELD_SIGNAL_CONTEXT
143
226
  * is provided, as mappers inject the context to access form state.
144
227
  *
228
+ * For componentless fields (no loadComponent and no mapper), returns undefined
229
+ * since there's no component to bind inputs to. Callers should check for undefined
230
+ * and skip rendering logic for such fields.
231
+ *
232
+ * If the field type definition specifies `propsToMeta`, the specified props
233
+ * will be merged into the meta object (with meta taking precedence).
234
+ *
145
235
  * @param fieldDef The field definition to map
146
236
  * @param fieldRegistry The registry of field type definitions
147
- * @returns Signal containing Record of input names to values for ngComponentOutlet
237
+ * @returns Signal containing Record of input names to values, or undefined for componentless fields
148
238
  */
149
239
  function mapFieldToInputs(fieldDef, fieldRegistry) {
150
240
  // Get the field type definition from registry
151
241
  const fieldType = fieldRegistry.get(fieldDef.type);
152
- if (fieldType?.mapper) {
153
- // Use the registered mapper for this field type
154
- // Mapper will inject FIELD_SIGNAL_CONTEXT internally
155
- return fieldType.mapper(fieldDef);
242
+ // Componentless field (no mapper and no loadComponent) - nothing to map
243
+ if (fieldType && !fieldType.loadComponent && !fieldType.mapper) {
244
+ return undefined;
156
245
  }
157
- // Fallback to base mapper
158
- // Mapper will inject FIELD_SIGNAL_CONTEXT internally
159
- return baseFieldMapper(fieldDef);
246
+ // Get the base mapper result
247
+ const mapperResult = fieldType?.mapper ? fieldType.mapper(fieldDef) : baseFieldMapper(fieldDef);
248
+ // If no props forwarding configured, return as-is
249
+ const propsToMeta = fieldType?.propsToMeta;
250
+ if (!propsToMeta || propsToMeta.length === 0) {
251
+ return mapperResult;
252
+ }
253
+ // Wrap in computed to merge forwarded props into meta
254
+ return computed(() => {
255
+ const inputs = mapperResult();
256
+ return mergeForwardedPropsToMeta(inputs, propsToMeta);
257
+ });
160
258
  }
161
259
 
162
260
  /**
163
261
  * Resolves a single field definition to a ResolvedField using RxJS.
164
262
  * Loads the component asynchronously and maps inputs in the injection context.
165
263
  *
264
+ * For componentless fields (e.g., hidden fields), returns undefined since
265
+ * there's nothing to render. These fields still contribute to form values
266
+ * through the form schema.
267
+ *
166
268
  * @param fieldDef - The field definition to resolve
167
269
  * @param context - The context containing dependencies for resolution
168
- * @returns Observable that emits ResolvedField or undefined on error
270
+ * @returns Observable that emits ResolvedField or undefined (for componentless fields or on error)
169
271
  */
170
272
  function resolveField(fieldDef, context) {
171
273
  return from(context.loadTypeComponent(fieldDef.type)).pipe(map((component) => {
@@ -173,8 +275,16 @@ function resolveField(fieldDef, context) {
173
275
  if (context.destroyRef.destroyed) {
174
276
  return undefined;
175
277
  }
278
+ // Componentless fields (e.g., hidden) return undefined - nothing to render
279
+ if (!component) {
280
+ return undefined;
281
+ }
176
282
  // Run mapper in injection context
177
283
  const inputs = runInInjectionContext(context.injector, () => mapFieldToInputs(fieldDef, context.registry));
284
+ // Fields with components should always have inputs (componentless fields are handled above)
285
+ if (!inputs) {
286
+ return undefined;
287
+ }
178
288
  return {
179
289
  key: fieldDef.key,
180
290
  component,
@@ -646,18 +756,20 @@ function injectFieldRegistry() {
646
756
  * Handles both synchronous component references and asynchronous
647
757
  * dynamic imports. Automatically extracts default exports from ES modules.
648
758
  *
759
+ * Returns `undefined` for componentless field types (e.g., hidden fields)
760
+ * that only contribute to form values without rendering UI.
761
+ *
649
762
  * @param name - The name of the field type to load
650
- * @returns Promise resolving to the component constructor
763
+ * @returns Promise resolving to the component constructor, or undefined for componentless fields
651
764
  * @throws {Error} When field type is not registered or loading fails
652
765
  *
653
766
  * @example
654
767
  * ```typescript
655
- * try {
656
- * const InputComponent = await fieldRegistry.loadTypeComponent('input');
657
- * const componentRef = vcr.createComponent(InputComponent);
658
- * } catch (error) {
659
- * console.error('Failed to load component:', error);
768
+ * const component = await fieldRegistry.loadTypeComponent('input');
769
+ * if (component) {
770
+ * const componentRef = vcr.createComponent(component);
660
771
  * }
772
+ * // For componentless fields like 'hidden', component will be undefined
661
773
  * ```
662
774
  */
663
775
  async loadTypeComponent(name) {
@@ -665,19 +777,20 @@ function injectFieldRegistry() {
665
777
  if (!fieldType) {
666
778
  throw new DynamicFormError(`Field type "${name}" is not registered`);
667
779
  }
780
+ // Componentless field types (e.g., hidden) don't have loadComponent
781
+ if (!fieldType.loadComponent) {
782
+ return undefined;
783
+ }
668
784
  // Handle async loading
669
- if (fieldType.loadComponent) {
670
- try {
671
- const result = await fieldType.loadComponent();
672
- // Handle ES module imports - extract default export if needed
673
- const moduleResult = result;
674
- return (typeof moduleResult === 'object' && 'default' in moduleResult && moduleResult.default) || result;
675
- }
676
- catch (error) {
677
- throw new DynamicFormError(`Failed to load component for field type "${name}": ${error}`);
678
- }
785
+ try {
786
+ const result = await fieldType.loadComponent();
787
+ // Handle ES module imports - extract default export if needed
788
+ const moduleResult = result;
789
+ return (typeof moduleResult === 'object' && 'default' in moduleResult && moduleResult.default) || result;
790
+ }
791
+ catch (error) {
792
+ throw new DynamicFormError(`Failed to load component for field type "${name}": ${error}`);
679
793
  }
680
- throw new DynamicFormError(`Field type "${name}" has no component or loadComponent function`);
681
794
  },
682
795
  /**
683
796
  * Gets all registered field type definitions.
@@ -901,10 +1014,10 @@ class RootFormRegistryService {
901
1014
  this._formValueSignals.set(new Map());
902
1015
  this.formContexts.clear();
903
1016
  }
904
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RootFormRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
905
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RootFormRegistryService });
1017
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: RootFormRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1018
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: RootFormRegistryService });
906
1019
  }
907
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RootFormRegistryService, decorators: [{
1020
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: RootFormRegistryService, decorators: [{
908
1021
  type: Injectable
909
1022
  }] });
910
1023
 
@@ -1028,10 +1141,10 @@ class FieldContextRegistryService {
1028
1141
  logger: this.logger,
1029
1142
  };
1030
1143
  }
1031
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldContextRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1032
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldContextRegistryService });
1144
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FieldContextRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1145
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FieldContextRegistryService });
1033
1146
  }
1034
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldContextRegistryService, decorators: [{
1147
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FieldContextRegistryService, decorators: [{
1035
1148
  type: Injectable
1036
1149
  }] });
1037
1150
 
@@ -1371,10 +1484,10 @@ class FunctionRegistryService {
1371
1484
  this.clearAsyncValidators();
1372
1485
  this.clearHttpValidators();
1373
1486
  }
1374
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FunctionRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1375
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FunctionRegistryService });
1487
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FunctionRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1488
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FunctionRegistryService });
1376
1489
  }
1377
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FunctionRegistryService, decorators: [{
1490
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FunctionRegistryService, decorators: [{
1378
1491
  type: Injectable
1379
1492
  }] });
1380
1493
 
@@ -3059,10 +3172,10 @@ class SchemaRegistryService {
3059
3172
  }
3060
3173
  return schema;
3061
3174
  }
3062
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3063
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaRegistryService });
3175
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SchemaRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3176
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SchemaRegistryService });
3064
3177
  }
3065
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaRegistryService, decorators: [{
3178
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SchemaRegistryService, decorators: [{
3066
3179
  type: Injectable
3067
3180
  }] });
3068
3181
 
@@ -3183,6 +3296,16 @@ function isArrayField(field) {
3183
3296
  return field.type === 'array' && 'fields' in field;
3184
3297
  }
3185
3298
 
3299
+ /**
3300
+ * Type guard to check if a field is a hidden field.
3301
+ *
3302
+ * @param field - The field to check
3303
+ * @returns True if the field is a HiddenField
3304
+ */
3305
+ function isHiddenField(field) {
3306
+ return field.type === 'hidden';
3307
+ }
3308
+
3186
3309
  /**
3187
3310
  * Type guard for RowField with proper type narrowing
3188
3311
  */
@@ -3190,6 +3313,36 @@ function isArrayField(field) {
3190
3313
  function isRowField(field) {
3191
3314
  return field.type === 'row' && 'fields' in field && Array.isArray(field.fields);
3192
3315
  }
3316
+ /**
3317
+ * Validates that a row field doesn't contain hidden fields.
3318
+ * Hidden fields are not allowed in rows because rows are for horizontal layouts,
3319
+ * and hidden fields don't render anything.
3320
+ *
3321
+ * @param rowField The row field to validate
3322
+ * @returns true if valid (no hidden fields), false otherwise
3323
+ */
3324
+ function validateRowNesting(rowField) {
3325
+ return !hasHiddenFields(rowField.fields);
3326
+ }
3327
+ /**
3328
+ * Recursively checks if fields contain any hidden fields
3329
+ * @param fields Array of field definitions to check
3330
+ * @returns true if hidden fields found, false otherwise
3331
+ */
3332
+ function hasHiddenFields(fields) {
3333
+ for (const field of fields) {
3334
+ if (isHiddenField(field)) {
3335
+ return true;
3336
+ }
3337
+ // Check group fields for nested hidden fields
3338
+ if (isGroupField(field)) {
3339
+ if (hasHiddenFields(field.fields)) {
3340
+ return true;
3341
+ }
3342
+ }
3343
+ }
3344
+ return false;
3345
+ }
3193
3346
 
3194
3347
  /**
3195
3348
  * Type guard for PageField with proper type narrowing
@@ -3993,10 +4146,10 @@ class EventBus {
3993
4146
  }
3994
4147
  return this.pipeline$.pipe(filter((event) => event.type === eventType));
3995
4148
  }
3996
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EventBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3997
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EventBus });
4149
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: EventBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4150
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: EventBus });
3998
4151
  }
3999
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EventBus, decorators: [{
4152
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: EventBus, decorators: [{
4000
4153
  type: Injectable
4001
4154
  }] });
4002
4155
 
@@ -4536,7 +4689,8 @@ function convertBuiltInToCustomValidator(config) {
4536
4689
  * Comprehensive form configuration validator that checks:
4537
4690
  * 1. Form mode consistency (paged vs non-paged)
4538
4691
  * 2. Page nesting rules
4539
- * 3. Field placement constraints
4692
+ * 3. Row nesting rules (no hidden fields in rows)
4693
+ * 4. Field placement constraints
4540
4694
  */
4541
4695
  class FormModeValidator {
4542
4696
  /**
@@ -4603,6 +4757,47 @@ class FormModeValidator {
4603
4757
  }
4604
4758
  }
4605
4759
  }
4760
+ // Warn about hidden fields in rows (they work but don't render, which may be confusing)
4761
+ const rowWarnings = this.collectRowHiddenFieldWarnings(fields);
4762
+ warnings.push(...rowWarnings);
4763
+ return warnings;
4764
+ }
4765
+ /**
4766
+ * Recursively collects warnings for hidden fields inside rows
4767
+ * @param fields The form field definitions to check
4768
+ * @param path Current path for warning messages
4769
+ * @returns Array of warning messages
4770
+ */
4771
+ static collectRowHiddenFieldWarnings(fields, path = '') {
4772
+ if (!fields) {
4773
+ return [];
4774
+ }
4775
+ const warnings = [];
4776
+ for (let i = 0; i < fields.length; i++) {
4777
+ const field = fields[i];
4778
+ const fieldPath = path ? `${path}.fields[${i}]` : `fields[${i}]`;
4779
+ const fieldKey = field.key || 'unknown';
4780
+ if (isRowField(field)) {
4781
+ if (!validateRowNesting(field)) {
4782
+ warnings.push(`Row field at ${fieldPath} (key: "${fieldKey}") contains hidden fields. ` +
4783
+ `Hidden fields in rows don't render anything - consider placing them outside the row.`);
4784
+ }
4785
+ // Continue checking nested rows within the row's children
4786
+ warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
4787
+ }
4788
+ else if (isPageField(field)) {
4789
+ // Check rows within pages
4790
+ warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
4791
+ }
4792
+ else if (isGroupField(field)) {
4793
+ // Check rows within groups
4794
+ warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
4795
+ }
4796
+ else if (isArrayField(field)) {
4797
+ // Check rows within array templates
4798
+ warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
4799
+ }
4800
+ }
4606
4801
  return warnings;
4607
4802
  }
4608
4803
  }
@@ -5074,8 +5269,8 @@ class PageOrchestratorComponent {
5074
5269
  }
5075
5270
  return false;
5076
5271
  }
5077
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: PageOrchestratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5078
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: PageOrchestratorComponent, isStandalone: true, selector: "div[page-orchestrator]", inputs: { pageFields: { classPropertyName: "pageFields", publicName: "pageFields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, fieldSignalContext: { classPropertyName: "fieldSignalContext", publicName: "fieldSignalContext", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-current-page": "state().currentPageIndex", "attr.data-total-pages": "state().totalPages" }, classAttribute: "df-page-orchestrator" }, providers: [
5272
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: PageOrchestratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5273
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: PageOrchestratorComponent, isStandalone: true, selector: "div[page-orchestrator]", inputs: { pageFields: { classPropertyName: "pageFields", publicName: "pageFields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, fieldSignalContext: { classPropertyName: "fieldSignalContext", publicName: "fieldSignalContext", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-current-page": "state().currentPageIndex", "attr.data-total-pages": "state().totalPages" }, classAttribute: "df-page-orchestrator" }, providers: [
5079
5274
  {
5080
5275
  provide: FIELD_SIGNAL_CONTEXT,
5081
5276
  useFactory: (orchestrator) => orchestrator.extendedFieldSignalContext(),
@@ -5105,9 +5300,9 @@ class PageOrchestratorComponent {
5105
5300
  }
5106
5301
  }
5107
5302
  }
5108
- `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs').then(m => m.default)], () => [import('./ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs').then(m => m.default)]] });
5303
+ `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs').then(m => m.default)], () => [import('./ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs').then(m => m.default)]] });
5109
5304
  }
5110
- i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.0.6", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [import('./ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
5305
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.0.8", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [import('./ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
5111
5306
  type: Component,
5112
5307
  args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
5113
5308
  @for (pageField of pageFields(); track pageField.key; let i = $index) {
@@ -5560,8 +5755,8 @@ class DynamicForm {
5560
5755
  ngOnDestroy() {
5561
5756
  this.rootFormRegistry.unregisterForm();
5562
5757
  }
5563
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DynamicForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
5564
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: DynamicForm, isStandalone: true, selector: "form[dynamic-form]", inputs: { config: { classPropertyName: "config", publicName: "dynamic-form", isSignal: true, isRequired: true, transformFunction: null }, formOptions: { classPropertyName: "formOptions", publicName: "formOptions", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", validityChange: "validityChange", dirtyChange: "dirtyChange", submitted: "submitted", reset: "reset", cleared: "cleared", events: "events", initialized: "initialized", onPageChange: "onPageChange", onPageNavigationStateChange: "onPageNavigationStateChange" }, host: { listeners: { "submit": "onNativeSubmit($event)" }, properties: { "class.disabled": "disabled()", "class.df-form-paged": "formModeDetection().mode === \"paged\"", "class.df-form-non-paged": "formModeDetection().mode === \"non-paged\"", "attr.data-form-mode": "formModeDetection().mode" }, classAttribute: "df-dynamic-form df-form" }, providers: [EventBus, SchemaRegistryService, FunctionRegistryService, RootFormRegistryService, FieldContextRegistryService], ngImport: i0, template: `
5758
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DynamicForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
5759
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: DynamicForm, isStandalone: true, selector: "form[dynamic-form]", inputs: { config: { classPropertyName: "config", publicName: "dynamic-form", isSignal: true, isRequired: true, transformFunction: null }, formOptions: { classPropertyName: "formOptions", publicName: "formOptions", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", validityChange: "validityChange", dirtyChange: "dirtyChange", submitted: "submitted", reset: "reset", cleared: "cleared", events: "events", initialized: "initialized", onPageChange: "onPageChange", onPageNavigationStateChange: "onPageNavigationStateChange" }, host: { attributes: { "novalidate": "" }, listeners: { "submit": "onNativeSubmit($event)" }, properties: { "class.disabled": "disabled()", "class.df-form-paged": "formModeDetection().mode === \"paged\"", "class.df-form-non-paged": "formModeDetection().mode === \"non-paged\"", "attr.data-form-mode": "formModeDetection().mode" }, classAttribute: "df-dynamic-form df-form" }, providers: [EventBus, SchemaRegistryService, FunctionRegistryService, RootFormRegistryService, FieldContextRegistryService], ngImport: i0, template: `
5565
5760
  @if (formModeDetection().mode === 'paged') {
5566
5761
  <div page-orchestrator [pageFields]="pageFieldDefinitions()" [form]="form()" [fieldSignalContext]="fieldSignalContext()"></div>
5567
5762
  } @else {
@@ -5571,7 +5766,7 @@ class DynamicForm {
5571
5766
  }
5572
5767
  `, isInline: true, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}:host>*{grid-column:1/-1}:host.df-form-spacing-custom{--df-grid-row-gap: var(--form-custom-spacing, 1.5rem)}:host.df-form-gap-none{--df-grid-row-gap: 0}:host.df-form-gap-xs{--df-grid-row-gap: .25rem}:host.df-form-gap-sm{--df-grid-row-gap: .5rem}:host.df-form-gap-md{--df-grid-row-gap: 1rem}:host.df-form-gap-lg{--df-grid-row-gap: 1.5rem}:host.df-form-gap-xl{--df-grid-row-gap: 2rem}:host.df-form-paged{--df-grid-row-gap: 0}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: PageOrchestratorComponent, selector: "div[page-orchestrator]", inputs: ["pageFields", "form", "fieldSignalContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5573
5768
  }
5574
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DynamicForm, decorators: [{
5769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DynamicForm, decorators: [{
5575
5770
  type: Component,
5576
5771
  args: [{ selector: 'form[dynamic-form]', imports: [NgComponentOutlet, PageOrchestratorComponent], template: `
5577
5772
  @if (formModeDetection().mode === 'paged') {
@@ -5583,6 +5778,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
5583
5778
  }
5584
5779
  `, providers: [EventBus, SchemaRegistryService, FunctionRegistryService, RootFormRegistryService, FieldContextRegistryService], host: {
5585
5780
  class: 'df-dynamic-form df-form',
5781
+ novalidate: '', // Disable browser validation - Angular Signal Forms handles validation
5586
5782
  '[class.disabled]': 'disabled()',
5587
5783
  '[class.df-form-paged]': 'formModeDetection().mode === "paged"',
5588
5784
  '[class.df-form-non-paged]': 'formModeDetection().mode === "non-paged"',
@@ -5602,10 +5798,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
5602
5798
  * @returns Signal containing Record of input names to values for ngComponentOutlet
5603
5799
  */
5604
5800
  function arrayFieldMapper(fieldDef) {
5801
+ const className = buildClassName(fieldDef);
5605
5802
  // Array inputs are static (no reactive dependencies)
5606
5803
  return computed(() => ({
5607
5804
  key: fieldDef.key,
5608
5805
  field: fieldDef,
5806
+ ...(className !== undefined && { className }),
5609
5807
  }));
5610
5808
  }
5611
5809
 
@@ -5620,10 +5818,12 @@ function arrayFieldMapper(fieldDef) {
5620
5818
  * @returns Signal containing Record of input names to values for ngComponentOutlet
5621
5819
  */
5622
5820
  function groupFieldMapper(fieldDef) {
5821
+ const className = buildClassName(fieldDef);
5623
5822
  // Group inputs are static (no reactive dependencies)
5624
5823
  return computed(() => ({
5625
5824
  key: fieldDef.key,
5626
5825
  field: fieldDef,
5826
+ ...(className !== undefined && { className }),
5627
5827
  }));
5628
5828
  }
5629
5829
 
@@ -5637,10 +5837,12 @@ function groupFieldMapper(fieldDef) {
5637
5837
  * @returns Signal containing Record of input names to values for ngComponentOutlet
5638
5838
  */
5639
5839
  function rowFieldMapper(fieldDef) {
5840
+ const className = buildClassName(fieldDef);
5640
5841
  // Row inputs are static (no reactive dependencies)
5641
5842
  return computed(() => ({
5642
5843
  key: fieldDef.key,
5643
5844
  field: fieldDef,
5845
+ ...(className !== undefined && { className }),
5644
5846
  }));
5645
5847
  }
5646
5848
 
@@ -5654,10 +5856,12 @@ function rowFieldMapper(fieldDef) {
5654
5856
  * @returns Signal containing Record of input names to values for ngComponentOutlet
5655
5857
  */
5656
5858
  function pageFieldMapper(fieldDef) {
5859
+ const className = buildClassName(fieldDef);
5657
5860
  // Page inputs are static (no reactive dependencies)
5658
5861
  return computed(() => ({
5659
5862
  key: fieldDef.key,
5660
5863
  field: fieldDef,
5864
+ ...(className !== undefined && { className }),
5661
5865
  }));
5662
5866
  }
5663
5867
 
@@ -5756,16 +5960,21 @@ const BUILT_IN_FIELDS = [
5756
5960
  },
5757
5961
  {
5758
5962
  name: 'page',
5759
- loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs'),
5963
+ loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs'),
5760
5964
  mapper: pageFieldMapper,
5761
5965
  valueHandling: 'flatten',
5762
5966
  },
5763
5967
  {
5764
5968
  name: 'text',
5765
- loadComponent: () => import('./ng-forge-dynamic-forms-text-field.component-C0I8jf9T.mjs'),
5969
+ loadComponent: () => import('./ng-forge-dynamic-forms-text-field.component-CfDZFTyf.mjs'),
5766
5970
  mapper: textFieldMapper,
5767
5971
  valueHandling: 'exclude',
5768
5972
  },
5973
+ {
5974
+ name: 'hidden',
5975
+ // Componentless field - no loadComponent or mapper needed
5976
+ valueHandling: 'include',
5977
+ },
5769
5978
  ];
5770
5979
 
5771
5980
  /**
@@ -5879,6 +6088,8 @@ function provideDynamicForm(...items) {
5879
6088
  const defaultLoggerProvider = hasLoggerFeature ? [] : [{ provide: DynamicFormLogger, useValue: new ConsoleLogger() }];
5880
6089
  return makeEnvironmentProviders([
5881
6090
  ...defaultLoggerProvider,
6091
+ // Always provide default Signal Forms classes (ng-touched, ng-invalid, etc.)
6092
+ provideSignalFormsConfig({ classes: NG_STATUS_CLASSES }),
5882
6093
  {
5883
6094
  provide: FIELD_REGISTRY,
5884
6095
  useFactory: () => {
@@ -6224,6 +6435,51 @@ function dynamicTextToObservable(value, injector) {
6224
6435
  return of(String(value));
6225
6436
  }
6226
6437
 
6438
+ /**
6439
+ * Applies meta attributes to a DOM element and tracks which attributes were applied.
6440
+ *
6441
+ * This utility handles:
6442
+ * - Removing previously applied attributes that are no longer in meta
6443
+ * - Setting new attributes from meta
6444
+ * - Converting all values to strings via String()
6445
+ *
6446
+ * @param element - The DOM element to apply attributes to
6447
+ * @param meta - The meta object containing attributes to apply
6448
+ * @param previouslyApplied - Set of attribute names that were previously applied
6449
+ * @returns A new Set containing the attribute names that were applied
6450
+ *
6451
+ * @example
6452
+ * ```typescript
6453
+ * private appliedAttrs = new Set<string>();
6454
+ *
6455
+ * explicitEffect([this.meta], ([meta]) => {
6456
+ * const input = this.el.nativeElement.querySelector('input');
6457
+ * if (input) {
6458
+ * this.appliedAttrs = applyMetaToElement(input, meta, this.appliedAttrs);
6459
+ * }
6460
+ * });
6461
+ * ```
6462
+ */
6463
+ function applyMetaToElement(element, meta, previouslyApplied) {
6464
+ const newApplied = new Set();
6465
+ // Remove old attributes no longer in meta
6466
+ for (const attr of previouslyApplied) {
6467
+ if (!meta || !(attr in meta) || meta[attr] === undefined) {
6468
+ element.removeAttribute(attr);
6469
+ }
6470
+ }
6471
+ if (!meta)
6472
+ return newApplied;
6473
+ // Apply new attributes
6474
+ for (const [key, value] of Object.entries(meta)) {
6475
+ if (value === undefined || value === null)
6476
+ continue;
6477
+ element.setAttribute(key, String(value));
6478
+ newApplied.add(key);
6479
+ }
6480
+ return newApplied;
6481
+ }
6482
+
6227
6483
  /**
6228
6484
  * Pipe that handles dynamic text resolution with support for static strings,
6229
6485
  * Observables, and Signals.
@@ -6264,10 +6520,10 @@ class DynamicTextPipe {
6264
6520
  }
6265
6521
  return of(value || '');
6266
6522
  }
6267
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DynamicTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
6268
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.6", ngImport: i0, type: DynamicTextPipe, isStandalone: true, name: "dynamicText" });
6523
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DynamicTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
6524
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.8", ngImport: i0, type: DynamicTextPipe, isStandalone: true, name: "dynamicText" });
6269
6525
  }
6270
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DynamicTextPipe, decorators: [{
6526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DynamicTextPipe, decorators: [{
6271
6527
  type: Pipe,
6272
6528
  args: [{
6273
6529
  name: 'dynamicText',
@@ -6319,9 +6575,15 @@ class RowFieldComponent {
6319
6575
  // ─────────────────────────────────────────────────────────────────────────────
6320
6576
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
6321
6577
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
6578
+ className = input(...(ngDevMode ? [undefined, { debugName: "className" }] : []));
6322
6579
  // ─────────────────────────────────────────────────────────────────────────────
6323
6580
  // Computed Signals
6324
6581
  // ─────────────────────────────────────────────────────────────────────────────
6582
+ hostClasses = computed(() => {
6583
+ const base = 'df-field df-row';
6584
+ const custom = this.className();
6585
+ return custom ? `${base} ${custom}` : base;
6586
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
6325
6587
  disabled = computed(() => {
6326
6588
  try {
6327
6589
  return this.field().disabled || false;
@@ -6370,26 +6632,26 @@ class RowFieldComponent {
6370
6632
  }
6371
6633
  });
6372
6634
  }
6373
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RowFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6374
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: RowFieldComponent, isStandalone: true, selector: "div[row-field]", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.disabled": "disabled()", "id": "`${key()}`", "attr.data-testid": "key()" }, classAttribute: "df-field df-row" }, ngImport: i0, template: `
6635
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: RowFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6636
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: RowFieldComponent, isStandalone: true, selector: "div[row-field]", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "class.disabled": "disabled()", "id": "`${key()}`", "attr.data-testid": "key()" } }, ngImport: i0, template: `
6375
6637
  @for (field of resolvedFields(); track field.key) {
6376
6638
  <ng-container *ngComponentOutlet="field.component; injector: field.injector; inputs: field.inputs()" />
6377
6639
  }
6378
6640
  `, isInline: true, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:flex;flex-wrap:wrap;gap:var(--df-grid-gap);align-items:flex-start;width:100%}:host ::ng-deep>*:not([class*=df-col-]){flex:0 0 auto}:host ::ng-deep>.df-col-1{flex:0 0 calc(8.3333333333% - var(--df-grid-gap) * .9166666667);max-width:calc(8.3333333333% - var(--df-grid-gap) * .9166666667)}:host ::ng-deep>.df-col-2{flex:0 0 calc(16.6666666667% - var(--df-grid-gap) * .8333333333);max-width:calc(16.6666666667% - var(--df-grid-gap) * .8333333333)}:host ::ng-deep>.df-col-3{flex:0 0 calc(25% - var(--df-grid-gap) * .75);max-width:calc(25% - var(--df-grid-gap) * .75)}:host ::ng-deep>.df-col-4{flex:0 0 calc(33.3333333333% - var(--df-grid-gap) * .6666666667);max-width:calc(33.3333333333% - var(--df-grid-gap) * .6666666667)}:host ::ng-deep>.df-col-5{flex:0 0 calc(41.6666666667% - var(--df-grid-gap) * .5833333333);max-width:calc(41.6666666667% - var(--df-grid-gap) * .5833333333)}:host ::ng-deep>.df-col-6{flex:0 0 calc(50% - var(--df-grid-gap) * .5);max-width:calc(50% - var(--df-grid-gap) * .5)}:host ::ng-deep>.df-col-7{flex:0 0 calc(58.3333333333% - var(--df-grid-gap) * .4166666667);max-width:calc(58.3333333333% - var(--df-grid-gap) * .4166666667)}:host ::ng-deep>.df-col-8{flex:0 0 calc(66.6666666667% - var(--df-grid-gap) * .3333333333);max-width:calc(66.6666666667% - var(--df-grid-gap) * .3333333333)}:host ::ng-deep>.df-col-9{flex:0 0 calc(75% - var(--df-grid-gap) * .25);max-width:calc(75% - var(--df-grid-gap) * .25)}:host ::ng-deep>.df-col-10{flex:0 0 calc(83.3333333333% - var(--df-grid-gap) * .1666666667);max-width:calc(83.3333333333% - var(--df-grid-gap) * .1666666667)}:host ::ng-deep>.df-col-11{flex:0 0 calc(91.6666666667% - var(--df-grid-gap) * .0833333333);max-width:calc(91.6666666667% - var(--df-grid-gap) * .0833333333)}:host ::ng-deep>.df-col-12{flex:0 0 calc(100% - var(--df-grid-gap) * 0);max-width:calc(100% - var(--df-grid-gap) * 0)}:host.df-gap-custom{--df-grid-gap: var(--row-custom-gap, 1rem)}@media(max-width:576px){:host.df-row-mobile-stack{flex-direction:column}:host.df-row-mobile-stack ::ng-deep>*{flex:0 0 100%!important;max-width:100%!important}}@media(min-width:577px)and (max-width:768px){:host.df-row-tablet-2col ::ng-deep>*{flex:0 0 calc(50% - var(--df-grid-gap) / 2);max-width:calc(50% - var(--df-grid-gap) / 2)}}@media(max-width:576px){:host{flex-direction:column}:host ::ng-deep>*{flex:0 0 100%!important;max-width:100%!important}:host.df-row-mobile-keep-cols{flex-direction:row}:host.df-row-mobile-keep-cols ::ng-deep>*:not([class*=df-col-]){flex:0 0 auto!important;max-width:none!important}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6379
6641
  }
6380
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RowFieldComponent, decorators: [{
6642
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: RowFieldComponent, decorators: [{
6381
6643
  type: Component,
6382
6644
  args: [{ selector: 'div[row-field]', imports: [NgComponentOutlet], template: `
6383
6645
  @for (field of resolvedFields(); track field.key) {
6384
6646
  <ng-container *ngComponentOutlet="field.component; injector: field.injector; inputs: field.inputs()" />
6385
6647
  }
6386
6648
  `, host: {
6387
- class: 'df-field df-row',
6649
+ '[class]': 'hostClasses()',
6388
6650
  '[class.disabled]': 'disabled()',
6389
6651
  '[id]': '`${key()}`',
6390
6652
  '[attr.data-testid]': 'key()',
6391
6653
  }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:flex;flex-wrap:wrap;gap:var(--df-grid-gap);align-items:flex-start;width:100%}:host ::ng-deep>*:not([class*=df-col-]){flex:0 0 auto}:host ::ng-deep>.df-col-1{flex:0 0 calc(8.3333333333% - var(--df-grid-gap) * .9166666667);max-width:calc(8.3333333333% - var(--df-grid-gap) * .9166666667)}:host ::ng-deep>.df-col-2{flex:0 0 calc(16.6666666667% - var(--df-grid-gap) * .8333333333);max-width:calc(16.6666666667% - var(--df-grid-gap) * .8333333333)}:host ::ng-deep>.df-col-3{flex:0 0 calc(25% - var(--df-grid-gap) * .75);max-width:calc(25% - var(--df-grid-gap) * .75)}:host ::ng-deep>.df-col-4{flex:0 0 calc(33.3333333333% - var(--df-grid-gap) * .6666666667);max-width:calc(33.3333333333% - var(--df-grid-gap) * .6666666667)}:host ::ng-deep>.df-col-5{flex:0 0 calc(41.6666666667% - var(--df-grid-gap) * .5833333333);max-width:calc(41.6666666667% - var(--df-grid-gap) * .5833333333)}:host ::ng-deep>.df-col-6{flex:0 0 calc(50% - var(--df-grid-gap) * .5);max-width:calc(50% - var(--df-grid-gap) * .5)}:host ::ng-deep>.df-col-7{flex:0 0 calc(58.3333333333% - var(--df-grid-gap) * .4166666667);max-width:calc(58.3333333333% - var(--df-grid-gap) * .4166666667)}:host ::ng-deep>.df-col-8{flex:0 0 calc(66.6666666667% - var(--df-grid-gap) * .3333333333);max-width:calc(66.6666666667% - var(--df-grid-gap) * .3333333333)}:host ::ng-deep>.df-col-9{flex:0 0 calc(75% - var(--df-grid-gap) * .25);max-width:calc(75% - var(--df-grid-gap) * .25)}:host ::ng-deep>.df-col-10{flex:0 0 calc(83.3333333333% - var(--df-grid-gap) * .1666666667);max-width:calc(83.3333333333% - var(--df-grid-gap) * .1666666667)}:host ::ng-deep>.df-col-11{flex:0 0 calc(91.6666666667% - var(--df-grid-gap) * .0833333333);max-width:calc(91.6666666667% - var(--df-grid-gap) * .0833333333)}:host ::ng-deep>.df-col-12{flex:0 0 calc(100% - var(--df-grid-gap) * 0);max-width:calc(100% - var(--df-grid-gap) * 0)}:host.df-gap-custom{--df-grid-gap: var(--row-custom-gap, 1rem)}@media(max-width:576px){:host.df-row-mobile-stack{flex-direction:column}:host.df-row-mobile-stack ::ng-deep>*{flex:0 0 100%!important;max-width:100%!important}}@media(min-width:577px)and (max-width:768px){:host.df-row-tablet-2col ::ng-deep>*{flex:0 0 calc(50% - var(--df-grid-gap) / 2);max-width:calc(50% - var(--df-grid-gap) / 2)}}@media(max-width:576px){:host{flex-direction:column}:host ::ng-deep>*{flex:0 0 100%!important;max-width:100%!important}:host.df-row-mobile-keep-cols{flex-direction:row}:host.df-row-mobile-keep-cols ::ng-deep>*:not([class*=df-col-]){flex:0 0 auto!important;max-width:none!important}}\n"] }]
6392
- }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }] } });
6654
+ }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }] } });
6393
6655
 
6394
6656
  var rowField_component = /*#__PURE__*/Object.freeze({
6395
6657
  __proto__: null,
@@ -6434,9 +6696,15 @@ class GroupFieldComponent {
6434
6696
  // ─────────────────────────────────────────────────────────────────────────────
6435
6697
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
6436
6698
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
6699
+ className = input(...(ngDevMode ? [undefined, { debugName: "className" }] : []));
6437
6700
  // ─────────────────────────────────────────────────────────────────────────────
6438
6701
  // Computed Signals
6439
6702
  // ─────────────────────────────────────────────────────────────────────────────
6703
+ hostClasses = computed(() => {
6704
+ const base = 'df-field df-group';
6705
+ const custom = this.className();
6706
+ return custom ? `${base} ${custom}` : base;
6707
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
6440
6708
  rawFieldRegistry = computed(() => this.fieldRegistry.raw, ...(ngDevMode ? [{ debugName: "rawFieldRegistry" }] : []));
6441
6709
  formSetup = computed(() => {
6442
6710
  const groupField = this.field();
@@ -6547,27 +6815,27 @@ class GroupFieldComponent {
6547
6815
  }
6548
6816
  });
6549
6817
  }
6550
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GroupFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6551
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: GroupFieldComponent, isStandalone: true, selector: "fieldset[group-field]", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { validityChange: "validityChange", dirtyChange: "dirtyChange", submitted: "submitted" }, host: { attributes: { "role": "group" }, properties: { "class.disabled": "disabled()", "id": "`${key()}`", "attr.data-testid": "key()" }, classAttribute: "df-field df-group" }, ngImport: i0, template: `
6818
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: GroupFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6819
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: GroupFieldComponent, isStandalone: true, selector: "fieldset[group-field]", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validityChange: "validityChange", dirtyChange: "dirtyChange", submitted: "submitted" }, host: { attributes: { "role": "group" }, properties: { "class": "hostClasses()", "class.disabled": "disabled()", "id": "`${key()}`", "attr.data-testid": "key()" } }, ngImport: i0, template: `
6552
6820
  @for (field of resolvedFields(); track field.key) {
6553
6821
  <ng-container *ngComponentOutlet="field.component; injector: field.injector; inputs: field.inputs()" />
6554
6822
  }
6555
6823
  `, isInline: true, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{border:none;margin:0;padding:0;min-width:0;display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}:host>*{grid-column:1/-1}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6556
6824
  }
6557
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GroupFieldComponent, decorators: [{
6825
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: GroupFieldComponent, decorators: [{
6558
6826
  type: Component,
6559
6827
  args: [{ selector: 'fieldset[group-field]', imports: [NgComponentOutlet], template: `
6560
6828
  @for (field of resolvedFields(); track field.key) {
6561
6829
  <ng-container *ngComponentOutlet="field.component; injector: field.injector; inputs: field.inputs()" />
6562
6830
  }
6563
6831
  `, host: {
6564
- class: 'df-field df-group',
6832
+ '[class]': 'hostClasses()',
6565
6833
  role: 'group',
6566
6834
  '[class.disabled]': 'disabled()',
6567
6835
  '[id]': '`${key()}`',
6568
6836
  '[attr.data-testid]': 'key()',
6569
6837
  }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{border:none;margin:0;padding:0;min-width:0;display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}:host>*{grid-column:1/-1}\n"] }]
6570
- }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }], submitted: [{ type: i0.Output, args: ["submitted"] }] } });
6838
+ }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }], submitted: [{ type: i0.Output, args: ["submitted"] }] } });
6571
6839
 
6572
6840
  var groupField_component = /*#__PURE__*/Object.freeze({
6573
6841
  __proto__: null,
@@ -6756,6 +7024,10 @@ function resolveArrayItem(options) {
6756
7024
  if (destroyRef.destroyed) {
6757
7025
  return undefined;
6758
7026
  }
7027
+ // Componentless fields (e.g., hidden) return undefined - nothing to render
7028
+ if (!component) {
7029
+ return undefined;
7030
+ }
6759
7031
  const itemId = generateArrayItemId();
6760
7032
  const indexSignal = linkedSignal(() => {
6761
7033
  const order = itemOrderSignal();
@@ -6771,9 +7043,13 @@ function resolveArrayItem(options) {
6771
7043
  registry,
6772
7044
  arrayField,
6773
7045
  });
7046
+ // Array item templates should always have inputs (componentless fields are handled above)
7047
+ if (!inputs) {
7048
+ return undefined;
7049
+ }
6774
7050
  return {
6775
7051
  id: itemId,
6776
- component: component,
7052
+ component,
6777
7053
  injector,
6778
7054
  inputs,
6779
7055
  };
@@ -6809,9 +7085,15 @@ class ArrayFieldComponent {
6809
7085
  // ─────────────────────────────────────────────────────────────────────────────
6810
7086
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
6811
7087
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
7088
+ className = input(...(ngDevMode ? [undefined, { debugName: "className" }] : []));
6812
7089
  // ─────────────────────────────────────────────────────────────────────────────
6813
7090
  // Computed Signals
6814
7091
  // ─────────────────────────────────────────────────────────────────────────────
7092
+ hostClasses = computed(() => {
7093
+ const base = 'df-field df-array';
7094
+ const custom = this.className();
7095
+ return custom ? `${base} ${custom}` : base;
7096
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
6815
7097
  rawFieldRegistry = computed(() => this.fieldRegistry.raw, ...(ngDevMode ? [{ debugName: "rawFieldRegistry" }] : []));
6816
7098
  fieldTemplate = computed(() => {
6817
7099
  const arrayField = this.field();
@@ -6979,25 +7261,25 @@ class ArrayFieldComponent {
6979
7261
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6980
7262
  parentForm().value.set({ ...currentValue, [arrayKey]: newArray });
6981
7263
  }
6982
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ArrayFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6983
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ArrayFieldComponent, isStandalone: true, selector: "array-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()" }, classAttribute: "df-field df-array" }, ngImport: i0, template: `
7264
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ArrayFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7265
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: ArrayFieldComponent, isStandalone: true, selector: "array-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "id": "`${key()}`", "attr.data-testid": "key()" } }, ngImport: i0, template: `
6984
7266
  @for (item of resolvedItems(); track item.id) {
6985
7267
  <ng-container *ngComponentOutlet="item.component; injector: item.injector; inputs: item.inputs()" />
6986
7268
  }
6987
7269
  `, isInline: true, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}:host>*{grid-column:1/-1}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6988
7270
  }
6989
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ArrayFieldComponent, decorators: [{
7271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ArrayFieldComponent, decorators: [{
6990
7272
  type: Component,
6991
7273
  args: [{ selector: 'array-field', imports: [NgComponentOutlet], template: `
6992
7274
  @for (item of resolvedItems(); track item.id) {
6993
7275
  <ng-container *ngComponentOutlet="item.component; injector: item.injector; inputs: item.inputs()" />
6994
7276
  }
6995
7277
  `, host: {
6996
- class: 'df-field df-array',
7278
+ '[class]': 'hostClasses()',
6997
7279
  '[id]': '`${key()}`',
6998
7280
  '[attr.data-testid]': 'key()',
6999
7281
  }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md);--df-grid-row-gap: var(--df-grid-row-gap-md)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}:host>*{grid-column:1/-1}\n"] }]
7000
- }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }] } });
7282
+ }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }] } });
7001
7283
 
7002
7284
  var arrayField_component = /*#__PURE__*/Object.freeze({
7003
7285
  __proto__: null,
@@ -7082,16 +7364,31 @@ function extractErrorParams(error) {
7082
7364
  params.min = error.min;
7083
7365
  if ('max' in error)
7084
7366
  params.max = error.max;
7085
- if ('requiredLength' in error)
7086
- params.requiredLength = error.requiredLength;
7087
- if ('actualLength' in error)
7088
- params.actualLength = error.actualLength;
7089
7367
  if ('pattern' in error)
7090
7368
  params.pattern = error.pattern;
7091
7369
  if ('actual' in error)
7092
7370
  params.actual = error.actual;
7093
7371
  if ('expected' in error)
7094
7372
  params.expected = error.expected;
7373
+ // Handle length validation parameters
7374
+ // Angular Signal Forms uses 'minLength'/'maxLength' properties
7375
+ // Angular Classic Forms uses 'requiredLength'/'actualLength' properties
7376
+ // We support both formats and normalize to 'requiredLength' for message templates
7377
+ if ('requiredLength' in error) {
7378
+ params.requiredLength = error.requiredLength;
7379
+ }
7380
+ else if ('minLength' in error) {
7381
+ // Angular Signal Forms: minLength property maps to requiredLength for templates
7382
+ params.requiredLength = error.minLength;
7383
+ params.minLength = error.minLength;
7384
+ }
7385
+ else if ('maxLength' in error) {
7386
+ // Angular Signal Forms: maxLength property maps to requiredLength for templates
7387
+ params.requiredLength = error.maxLength;
7388
+ params.maxLength = error.maxLength;
7389
+ }
7390
+ if ('actualLength' in error)
7391
+ params.actualLength = error.actualLength;
7095
7392
  // Include all custom properties from error object (for custom validators)
7096
7393
  // Skip 'kind' as it's the error type identifier, not a parameter
7097
7394
  Object.keys(error).forEach((key) => {
@@ -7133,5 +7430,5 @@ function extractErrorParams(error) {
7133
7430
  * Generated bundle index. Do not edit.
7134
7431
  */
7135
7432
 
7136
- export { BUILT_IN_FIELDS as $, AddArrayItemEvent as A, baseFieldMapper as B, ConsoleLogger as C, DynamicFormLogger as D, EventBus as E, FormClearEvent as F, buildBaseInputs as G, arrayFieldMapper as H, groupFieldMapper as I, pageFieldMapper as J, rowFieldMapper as K, textFieldMapper as L, FIELD_REGISTRY as M, NoopLogger as N, ARRAY_CONTEXT as O, PageChangeEvent as P, FIELD_SIGNAL_CONTEXT as Q, RemoveArrayItemEvent as R, SubmitEvent as S, dynamicTextToObservable as T, ArrayFieldComponent as U, GroupFieldComponent as V, RowFieldComponent as W, applyValidator as X, applyValidators as Y, getArrayLength as Z, resolveTokens as _, DynamicTextPipe as a, omit as a0, interpolateParams as a1, DynamicForm as b, createFieldResolutionPipe as c, derivedFromDeferred as d, emitComponentInitialized as e, isFormStateCondition as f, resolveNextButtonDisabled as g, isCheckedField as h, injectFieldRegistry as i, isValueField as j, isRowField as k, isArrayField as l, isContainerField as m, isDisplayOnlyField as n, isGroupField as o, provideDynamicForm as p, isLeafField as q, resolveSubmitButtonDisabled as r, isPageField as s, isValueBearingField as t, FormResetEvent as u, validatePageNesting as v, withLoggerConfig as w, NextPageEvent as x, PreviousPageEvent as y, DynamicFormError as z };
7137
- //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-CZBdtTAU.mjs.map
7433
+ export { BUILT_IN_FIELDS as $, AddArrayItemEvent as A, baseFieldMapper as B, ConsoleLogger as C, DynamicFormLogger as D, EventBus as E, FormClearEvent as F, buildBaseInputs as G, arrayFieldMapper as H, groupFieldMapper as I, pageFieldMapper as J, rowFieldMapper as K, textFieldMapper as L, FIELD_REGISTRY as M, NoopLogger as N, ARRAY_CONTEXT as O, PageChangeEvent as P, FIELD_SIGNAL_CONTEXT as Q, RemoveArrayItemEvent as R, SubmitEvent as S, dynamicTextToObservable as T, ArrayFieldComponent as U, GroupFieldComponent as V, RowFieldComponent as W, applyValidator as X, applyValidators as Y, getArrayLength as Z, resolveTokens as _, DynamicTextPipe as a, omit as a0, interpolateParams as a1, applyMetaToElement as a2, DynamicForm as b, createFieldResolutionPipe as c, derivedFromDeferred as d, emitComponentInitialized as e, isFormStateCondition as f, resolveNextButtonDisabled as g, isCheckedField as h, injectFieldRegistry as i, isValueField as j, isRowField as k, isArrayField as l, isContainerField as m, isDisplayOnlyField as n, isGroupField as o, provideDynamicForm as p, isLeafField as q, resolveSubmitButtonDisabled as r, isPageField as s, isValueBearingField as t, FormResetEvent as u, validatePageNesting as v, withLoggerConfig as w, NextPageEvent as x, PreviousPageEvent as y, DynamicFormError as z };
7434
+ //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs.map