@ng-forge/dynamic-forms 0.8.0-next.4 → 0.8.0

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 (29) hide show
  1. package/README.md +2 -0
  2. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-CJ_OclbR.mjs → ng-forge-dynamic-forms-array-field.component-CWxCWVdz.mjs} +3 -3
  3. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-CJ_OclbR.mjs.map → ng-forge-dynamic-forms-array-field.component-CWxCWVdz.mjs.map} +1 -1
  4. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-DQ_OQLtx.mjs → ng-forge-dynamic-forms-container-field.component-PozYj2JC.mjs} +4 -9
  5. package/fesm2022/ng-forge-dynamic-forms-container-field.component-PozYj2JC.mjs.map +1 -0
  6. package/fesm2022/{ng-forge-dynamic-forms-container-utils-zQSTe7Jk.mjs → ng-forge-dynamic-forms-container-utils-DW_P7w-b.mjs} +4 -5
  7. package/fesm2022/ng-forge-dynamic-forms-container-utils-DW_P7w-b.mjs.map +1 -0
  8. package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-2fdmbtL7.mjs → ng-forge-dynamic-forms-css-wrapper.component-DrtHSaVV.mjs} +2 -2
  9. package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-2fdmbtL7.mjs.map → ng-forge-dynamic-forms-css-wrapper.component-DrtHSaVV.mjs.map} +1 -1
  10. package/fesm2022/{ng-forge-dynamic-forms-emit-initialization-pCNwBRRm.mjs → ng-forge-dynamic-forms-emit-initialization-CSx0gwFc.mjs} +3 -3
  11. package/fesm2022/ng-forge-dynamic-forms-emit-initialization-CSx0gwFc.mjs.map +1 -0
  12. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-BdLdSEHj.mjs → ng-forge-dynamic-forms-group-field.component-2yRmHAUp.mjs} +3 -3
  13. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-BdLdSEHj.mjs.map → ng-forge-dynamic-forms-group-field.component-2yRmHAUp.mjs.map} +1 -1
  14. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +3 -39
  15. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  16. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-BdMxsqmk.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-Ll4W2Z_n.mjs} +517 -396
  17. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-Ll4W2Z_n.mjs.map +1 -0
  18. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-C5rUo80O.mjs → ng-forge-dynamic-forms-page-field.component-B_CxX0T-.mjs} +3 -3
  19. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-C5rUo80O.mjs.map → ng-forge-dynamic-forms-page-field.component-B_CxX0T-.mjs.map} +1 -1
  20. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-lvuyTM1r.mjs → ng-forge-dynamic-forms-text-field.component-rJMtKX2X.mjs} +2 -2
  21. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-lvuyTM1r.mjs.map → ng-forge-dynamic-forms-text-field.component-rJMtKX2X.mjs.map} +1 -1
  22. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  23. package/package.json +2 -2
  24. package/types/ng-forge-dynamic-forms-integration.d.ts +3 -4
  25. package/types/ng-forge-dynamic-forms.d.ts +68 -27
  26. package/fesm2022/ng-forge-dynamic-forms-container-field.component-DQ_OQLtx.mjs.map +0 -1
  27. package/fesm2022/ng-forge-dynamic-forms-container-utils-zQSTe7Jk.mjs.map +0 -1
  28. package/fesm2022/ng-forge-dynamic-forms-emit-initialization-pCNwBRRm.mjs.map +0 -1
  29. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BdMxsqmk.mjs.map +0 -1
@@ -1318,13 +1318,11 @@ function setupInitializationTracking(options) {
1318
1318
  }
1319
1319
 
1320
1320
  /**
1321
- * Type guard to check if a field is a hidden field.
1322
- *
1323
- * @param field - The field to check
1324
- * @returns True if the field is a HiddenField
1321
+ * Type guard for RowField with proper type narrowing
1325
1322
  */
1326
- function isHiddenField(field) {
1327
- return field.type === 'hidden';
1323
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Type guard must accept any field type
1324
+ function isRowField(field) {
1325
+ return field.type === 'row' && 'fields' in field && Array.isArray(field.fields);
1328
1326
  }
1329
1327
 
1330
1328
  /**
@@ -1336,41 +1334,20 @@ function isGroupField(field) {
1336
1334
  }
1337
1335
 
1338
1336
  /**
1339
- * Type guard for RowField with proper type narrowing
1340
- */
1341
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Type guard must accept any field type
1342
- function isRowField(field) {
1343
- return field.type === 'row' && 'fields' in field && Array.isArray(field.fields);
1344
- }
1345
- /**
1346
- * Validates that a row field doesn't contain hidden fields.
1347
- * Hidden fields are not allowed in rows because rows are for horizontal layouts,
1348
- * and hidden fields don't render anything.
1337
+ * Type guard for ContainerField with proper type narrowing.
1349
1338
  *
1350
- * @param rowField The row field to validate
1351
- * @returns true if valid (no hidden fields), false otherwise
1339
+ * `wrappers` is part of the type but optional in practice — many configs use
1340
+ * containers purely as flex/layout wrappers without any wrapper components.
1341
+ * Match on `type === 'container'` and the `fields` shape only, mirroring
1342
+ * `isPageField` / `isRowField`.
1352
1343
  */
1353
- function validateRowNesting(rowField) {
1354
- return !hasHiddenFields(rowField.fields);
1355
- }
1356
- /**
1357
- * Recursively checks if fields contain any hidden fields
1358
- * @param fields Array of field definitions to check
1359
- * @returns true if hidden fields found, false otherwise
1360
- */
1361
- function hasHiddenFields(fields) {
1362
- for (const field of fields) {
1363
- if (isHiddenField(field)) {
1364
- return true;
1365
- }
1366
- // Check group fields for nested hidden fields
1367
- if (isGroupField(field)) {
1368
- if (hasHiddenFields(field.fields)) {
1369
- return true;
1370
- }
1371
- }
1372
- }
1373
- return false;
1344
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Type guard must accept any field type
1345
+ function isContainerTypedField(field) {
1346
+ return (field.type === 'container' &&
1347
+ 'wrappers' in field &&
1348
+ 'fields' in field &&
1349
+ Array.isArray(field.wrappers) &&
1350
+ Array.isArray(field.fields));
1374
1351
  }
1375
1352
 
1376
1353
  /**
@@ -1391,7 +1368,9 @@ function validatePageNesting(pageField) {
1391
1368
  * Type guard to check if a field is a container with fields property
1392
1369
  */
1393
1370
  function isContainerWithFields$1(field) {
1394
- return (isRowField(field) || isGroupField(field)) && 'fields' in field && Array.isArray(field.fields);
1371
+ return ((isRowField(field) || isGroupField(field) || isContainerTypedField(field)) &&
1372
+ 'fields' in field &&
1373
+ Array.isArray(field.fields));
1395
1374
  }
1396
1375
  /**
1397
1376
  * Recursively checks if fields contain any nested page fields
@@ -1431,14 +1410,6 @@ function isSimplifiedArrayField(field) {
1431
1410
  return field.type === 'array' && 'template' in field;
1432
1411
  }
1433
1412
 
1434
- /**
1435
- * Type guard for ContainerField with proper type narrowing
1436
- */
1437
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Type guard must accept any field type
1438
- function isContainerTypedField(field) {
1439
- return field.type === 'container' && 'fields' in field && 'wrappers' in field;
1440
- }
1441
-
1442
1413
  /**
1443
1414
  * Type guard to check if a field definition has child fields.
1444
1415
  * This is a looser check that works with FieldDef<unknown> without requiring RegisteredFieldTypes.
@@ -4170,9 +4141,9 @@ class PageOrchestratorComponent {
4170
4141
  }
4171
4142
  }
4172
4143
  }
4173
- `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ng-forge-dynamic-forms-page-field.component-C5rUo80O.mjs').then(m => m.default)], () => [import('./ng-forge-dynamic-forms-page-field.component-C5rUo80O.mjs').then(m => m.default)]] });
4144
+ `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ng-forge-dynamic-forms-page-field.component-B_CxX0T-.mjs').then(m => m.default)], () => [import('./ng-forge-dynamic-forms-page-field.component-B_CxX0T-.mjs').then(m => m.default)]] });
4174
4145
  }
4175
- i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.8", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [import('./ng-forge-dynamic-forms-page-field.component-C5rUo80O.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
4146
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.8", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [import('./ng-forge-dynamic-forms-page-field.component-B_CxX0T-.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
4176
4147
  type: Component,
4177
4148
  args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
4178
4149
  @for (pageField of pageFields(); track pageField.key; let i = $index) {
@@ -4558,7 +4529,7 @@ function hasAnyPageFields(fields) {
4558
4529
  return true;
4559
4530
  }
4560
4531
  // Check nested fields in container types
4561
- if (isContainerWithFields(field) && (field.type === 'row' || field.type === 'group')) {
4532
+ if (!isPageField(field) && isContainerWithFields(field)) {
4562
4533
  if (hasAnyPageFields(field.fields)) {
4563
4534
  return true;
4564
4535
  }
@@ -4581,7 +4552,7 @@ function hasNestedPageFields(fields) {
4581
4552
  }
4582
4553
  }
4583
4554
  // Check other container types for nested pages
4584
- if (isContainerWithFields(field) && (field.type === 'row' || field.type === 'group')) {
4555
+ if (!isPageField(field) && isContainerWithFields(field)) {
4585
4556
  if (hasNestedPageFields(field.fields)) {
4586
4557
  return true;
4587
4558
  }
@@ -6318,12 +6289,22 @@ function mapFieldToForm(fieldDef, fieldPath) {
6318
6289
  }
6319
6290
  /**
6320
6291
  * Maps children of a container field (page, row, group) to the form schema.
6292
+ *
6293
+ * Layout containers (page/row/container) flatten into `parentPath` and are
6294
+ * recursed through without consuming a key — same contract as `mapFieldToForm`'s
6295
+ * top-level layout branch, so any depth of layout-container nesting reaches its
6296
+ * leaf descendants. Group/array fields consume their key and look up their own
6297
+ * child path on `parentPath`.
6321
6298
  */
6322
6299
  function mapContainerChildren(fields, parentPath) {
6323
6300
  if (!fields)
6324
6301
  return;
6325
6302
  const pathRecord = parentPath;
6326
6303
  for (const field of fields) {
6304
+ if (isPageField(field) || isRowField(field) || isContainerTypedField(field)) {
6305
+ mapContainerChildren(field.fields, parentPath);
6306
+ continue;
6307
+ }
6327
6308
  if (!field.key)
6328
6309
  continue;
6329
6310
  const childPath = pathRecord[field.key];
@@ -6419,9 +6400,21 @@ function mapArrayFieldToForm(arrayField, fieldPath) {
6419
6400
  maxLength(fieldPath, arrayField.maxLength);
6420
6401
  }
6421
6402
  // Fields can be either FieldDef (primitive) or FieldDef[] (object)
6422
- const itemDefinitions = arrayField.fields;
6423
- // Empty array is valid - items will be added via buttons with their own templates
6424
- // Create a minimal schema that just accepts any value
6403
+ let itemDefinitions = arrayField.fields;
6404
+ // Simplified arrays initialized without `value` have empty `fields`; their
6405
+ // item shape only lives in Symbol metadata. Fall back to that template so
6406
+ // validators and logic declared inside it still apply when items are
6407
+ // materialized from a programmatically-set form value.
6408
+ if (!itemDefinitions || itemDefinitions.length === 0) {
6409
+ const metadataTemplate = getNormalizedArrayMetadata(arrayField)?.template;
6410
+ if (metadataTemplate) {
6411
+ itemDefinitions = [
6412
+ Array.isArray(metadataTemplate) ? [...metadataTemplate] : metadataTemplate,
6413
+ ];
6414
+ }
6415
+ }
6416
+ // Empty array with no template metadata - items will be added via buttons with
6417
+ // their own templates. Create a minimal schema that just accepts any value.
6425
6418
  if (!itemDefinitions || itemDefinitions.length === 0) {
6426
6419
  const emptyItemSchema = schema(() => {
6427
6420
  // No fields to map - items will be added dynamically via buttons
@@ -6433,14 +6426,22 @@ function mapArrayFieldToForm(arrayField, fieldPath) {
6433
6426
  let hasPrimitiveItems = false;
6434
6427
  const allObjectFields = [];
6435
6428
  for (const itemDef of itemDefinitions) {
6436
- if (!Array.isArray(itemDef)) {
6437
- // Primitive item: single FieldDef
6438
- hasPrimitiveItems = true;
6439
- }
6440
- else {
6429
+ if (Array.isArray(itemDef)) {
6441
6430
  // Object item: collect fields for superset schema
6442
6431
  collectFieldsFromObjectItem(itemDef, allObjectFields);
6443
6432
  }
6433
+ else if (isPageField(itemDef) ||
6434
+ isRowField(itemDef) ||
6435
+ isContainerTypedField(itemDef)) {
6436
+ // Layout container as a single-template item: its descendants describe
6437
+ // the item's object shape. Hand it to the object-item collector wrapped
6438
+ // as a 1-element array so the structured-item mapping path runs.
6439
+ collectFieldsFromObjectItem([itemDef], allObjectFields);
6440
+ }
6441
+ else {
6442
+ // Primitive item: single FieldDef
6443
+ hasPrimitiveItems = true;
6444
+ }
6444
6445
  }
6445
6446
  // For pure primitive arrays, use a simple schema
6446
6447
  if (hasPrimitiveItems && allObjectFields.length === 0) {
@@ -6580,7 +6581,7 @@ function getFieldDefaultValue(field, registry) {
6580
6581
  if (valueHandling === 'exclude') {
6581
6582
  return undefined;
6582
6583
  }
6583
- // Flatten fields (row/page) return flattened object of children's values
6584
+ // Flatten fields (row/page/container) return flattened object of children's values
6584
6585
  // This is used by array fields to get the template structure
6585
6586
  // Note: fieldsToDefaultValues will skip these at top-level since they have keys and return objects
6586
6587
  if (valueHandling === 'flatten' && 'fields' in field && field.fields) {
@@ -6588,11 +6589,18 @@ function getFieldDefaultValue(field, registry) {
6588
6589
  // Collect only fields that contribute values (exclude buttons, text, etc.)
6589
6590
  const flattenedValues = {};
6590
6591
  for (const childField of childFields) {
6591
- if ('key' in childField && childField.key) {
6592
- const childValue = getFieldDefaultValue(childField, registry);
6593
- if (childValue !== undefined) {
6594
- flattenedValues[childField.key] = childValue;
6595
- }
6592
+ const childValueHandling = getFieldValueHandling(childField.type, registry);
6593
+ if (childValueHandling === 'exclude')
6594
+ continue;
6595
+ const childValue = getFieldDefaultValue(childField, registry);
6596
+ if (childValue === undefined)
6597
+ continue;
6598
+ if (childValueHandling === 'flatten' && childValue && typeof childValue === 'object' && !Array.isArray(childValue)) {
6599
+ // Nested flatten field — its value is already flat; spread it up.
6600
+ Object.assign(flattenedValues, childValue);
6601
+ }
6602
+ else if ('key' in childField && childField.key) {
6603
+ flattenedValues[childField.key] = childValue;
6596
6604
  }
6597
6605
  }
6598
6606
  // Return flattened object if there are any values, otherwise undefined
@@ -6607,20 +6615,17 @@ function getFieldDefaultValue(field, registry) {
6607
6615
  const groupDefaults = {};
6608
6616
  for (const childField of fields) {
6609
6617
  const childValueHandling = getFieldValueHandling(childField.type, registry);
6610
- // Flatten row/page fields into the group (they are presentational containers)
6611
- if (childValueHandling === 'flatten' && 'fields' in childField && childField.fields) {
6612
- const nestedFields = childField.fields;
6613
- for (const nestedField of nestedFields) {
6614
- if ('key' in nestedField && nestedField.key) {
6615
- const nestedValue = getFieldDefaultValue(nestedField, registry);
6616
- if (nestedValue !== undefined) {
6617
- groupDefaults[nestedField.key] = nestedValue;
6618
- }
6619
- }
6618
+ if (childValueHandling === 'exclude')
6619
+ continue;
6620
+ const childValue = getFieldDefaultValue(childField, registry);
6621
+ if (childValueHandling === 'flatten') {
6622
+ // Flatten container/row/page values into the group (they are presentational containers).
6623
+ // The recursive call already returns a flat object — spread it directly.
6624
+ if (childValue && typeof childValue === 'object' && !Array.isArray(childValue)) {
6625
+ Object.assign(groupDefaults, childValue);
6620
6626
  }
6621
6627
  }
6622
6628
  else if ('key' in childField && childField.key) {
6623
- const childValue = getFieldDefaultValue(childField, registry);
6624
6629
  if (childValue !== undefined) {
6625
6630
  groupDefaults[childField.key] = childValue;
6626
6631
  }
@@ -7438,10 +7443,10 @@ function createEmptyCollection() {
7438
7443
  /** Traverses field definitions and collects cross-field entries (validators, logic, schemas). */
7439
7444
  function collectCrossFieldEntries(fields) {
7440
7445
  const collection = createEmptyCollection();
7441
- traverseFields$2(fields, collection, '');
7446
+ traverseFields(fields, collection, '');
7442
7447
  return collection;
7443
7448
  }
7444
- function traverseFields$2(fields, collection, pathPrefix) {
7449
+ function traverseFields(fields, collection, pathPrefix) {
7445
7450
  for (const field of fields) {
7446
7451
  collectFromField$2(field, collection, pathPrefix);
7447
7452
  // Recursively process container fields (page, row, group, array)
@@ -7453,7 +7458,7 @@ function traverseFields$2(fields, collection, pathPrefix) {
7453
7458
  // be built for them.
7454
7459
  const groupKey = isGroupField(field) ? field.key : undefined;
7455
7460
  const childPrefix = groupKey ? (pathPrefix ? `${pathPrefix}.${groupKey}` : groupKey) : pathPrefix;
7456
- traverseFields$2(normalizeFieldsArray(field.fields), collection, childPrefix);
7461
+ traverseFields(normalizeFieldsArray(field.fields), collection, childPrefix);
7457
7462
  }
7458
7463
  }
7459
7464
  }
@@ -8168,6 +8173,29 @@ function buildPropertyOverrideKey(arrayKey, index, fieldKey) {
8168
8173
  return fieldKey;
8169
8174
  }
8170
8175
 
8176
+ /**
8177
+ * Returns true if the field has any property-derivation logic entries
8178
+ * (type: 'derivation' with a non-empty targetProperty). Mirrors the inclusion
8179
+ * rule used by `collectPropertyDerivations`, so the mapper and orchestrator
8180
+ * agree on which fields participate in property overrides — without depending
8181
+ * on whether the orchestrator's registration effect has run yet (which it
8182
+ * hasn't on the resolveFieldSync path with a warm COMPONENT_CACHE).
8183
+ */
8184
+ function fieldHasPropertyDerivations(fieldDef) {
8185
+ // Match the collector's keyless guard (property-derivation-collector.ts):
8186
+ // keyless fields are never registered in the store, so the mapper must skip
8187
+ // them too — otherwise getOverrides() would be called with an undefined key.
8188
+ if (!fieldDef.key)
8189
+ return false;
8190
+ const logic = fieldDef.logic;
8191
+ if (!logic || logic.length === 0)
8192
+ return false;
8193
+ for (const entry of logic) {
8194
+ if (isDerivationLogicConfig(entry) && hasTargetProperty(entry))
8195
+ return true;
8196
+ }
8197
+ return false;
8198
+ }
8171
8199
  /**
8172
8200
  * Merges forwarded props into meta, with meta taking precedence.
8173
8201
  *
@@ -8269,11 +8297,13 @@ function mapFieldToInputs(fieldDef, fieldRegistry) {
8269
8297
  // Check that arrayContext exists and has a valid index signal (guards against mock injectors)
8270
8298
  const indexSignal = arrayContext?.index;
8271
8299
  const hasArrayContext = indexSignal !== undefined && isSignal(indexSignal);
8272
- // Fast-path check for property overrides: only fields with registered derivations
8273
- // enter the computed() wrapper for overrides. hasField() is a non-reactive Map.has() — O(1).
8274
- // Uses PLACEHOLDER_INDEX to produce the wildcard format (e.g., 'items.$.endDate') matching
8275
- // what the collector/orchestrator registers. The computed block below uses a concrete index instead.
8276
- const hasOverrides = store?.hasField(buildPropertyOverrideKey(arrayContext?.arrayKey, arrayContext ? PLACEHOLDER_INDEX : undefined, fieldDef.key)) ?? false;
8300
+ // Fast-path check for property overrides: only fields whose definition declares
8301
+ // a property-derivation enter the computed() wrapper. We inspect the FieldDef
8302
+ // directly rather than asking the store, because the store's registration
8303
+ // effect may not have fired yet when the mapper runs in the resolveFieldSync
8304
+ // path (warm COMPONENT_CACHE). Both the mapper and the orchestrator's
8305
+ // collector apply the same inclusion rule, so the answers always agree.
8306
+ const hasOverrides = fieldHasPropertyDerivations(fieldDef);
8277
8307
  // Fast path: no transformations needed
8278
8308
  if (!hasPropsForwarding && !hasArrayContext && !hasOverrides) {
8279
8309
  return mapperResult;
@@ -8427,8 +8457,7 @@ function createFieldResolutionPipe(getContext) {
8427
8457
  * Comprehensive form configuration validator that checks:
8428
8458
  * 1. Form mode consistency (paged vs non-paged)
8429
8459
  * 2. Page nesting rules
8430
- * 3. Row nesting rules (no hidden fields in rows)
8431
- * 4. Field placement constraints
8460
+ * 3. Field placement constraints
8432
8461
  */
8433
8462
  class FormModeValidator {
8434
8463
  /**
@@ -8495,57 +8524,6 @@ class FormModeValidator {
8495
8524
  }
8496
8525
  }
8497
8526
  }
8498
- // Warn about hidden fields in rows (they work but don't render, which may be confusing)
8499
- const rowWarnings = this.collectRowHiddenFieldWarnings(fields);
8500
- warnings.push(...rowWarnings);
8501
- return warnings;
8502
- }
8503
- /**
8504
- * Recursively collects warnings for hidden fields inside rows
8505
- * @param fields The form field definitions to check
8506
- * @param path Current path for warning messages
8507
- * @returns Array of warning messages
8508
- */
8509
- static collectRowHiddenFieldWarnings(fields, path = '') {
8510
- if (!fields) {
8511
- return [];
8512
- }
8513
- const warnings = [];
8514
- for (let i = 0; i < fields.length; i++) {
8515
- const field = fields[i];
8516
- const fieldPath = path ? `${path}.fields[${i}]` : `fields[${i}]`;
8517
- const fieldKey = field.key || 'unknown';
8518
- if (isRowField(field)) {
8519
- if (!validateRowNesting(field)) {
8520
- warnings.push(`Row field at ${fieldPath} (key: "${fieldKey}") contains hidden fields. ` +
8521
- `Hidden fields in rows don't render anything - consider placing them outside the row.`);
8522
- }
8523
- // Continue checking nested rows within the row's children
8524
- warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
8525
- }
8526
- else if (isPageField(field)) {
8527
- // Check rows within pages
8528
- warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
8529
- }
8530
- else if (isGroupField(field)) {
8531
- // Check rows within groups
8532
- warnings.push(...this.collectRowHiddenFieldWarnings(field.fields, fieldPath));
8533
- }
8534
- else if (isSimplifiedArrayField(field)) {
8535
- // Simplified arrays are normalized later; check template fields if present
8536
- const templateFields = Array.isArray(field.template) ? [...field.template] : [field.template];
8537
- warnings.push(...this.collectRowHiddenFieldWarnings(templateFields, fieldPath));
8538
- }
8539
- else if (isArrayField(field)) {
8540
- // Check rows within array templates — items may be single FieldDef (primitive) or FieldDef[] (object)
8541
- const itemTemplates = field.fields;
8542
- for (let j = 0; j < itemTemplates.length; j++) {
8543
- const itemFields = itemTemplates[j];
8544
- const fieldsArray = Array.isArray(itemFields) ? [...itemFields] : [itemFields];
8545
- warnings.push(...this.collectRowHiddenFieldWarnings(fieldsArray, `${fieldPath}.fields[${j}]`));
8546
- }
8547
- }
8548
- }
8549
8527
  return warnings;
8550
8528
  }
8551
8529
  }
@@ -10532,6 +10510,71 @@ function parseDerivationKey(key) {
10532
10510
  return { fieldKey: key };
10533
10511
  }
10534
10512
 
10513
+ /**
10514
+ * Single dispatch over `value` / `expression` / `functionName` shared by both
10515
+ * the value-derivation and property-derivation applicators.
10516
+ *
10517
+ * Throws {@link DynamicFormError} on missing function or missing value source
10518
+ * so both pipelines surface the library's standard error type.
10519
+ *
10520
+ * @internal
10521
+ */
10522
+ function computeValueFromEntry(entry, evalContext, options) {
10523
+ if (entry.value !== undefined) {
10524
+ return entry.value;
10525
+ }
10526
+ if (entry.expression) {
10527
+ return ExpressionParser.evaluate(entry.expression, evalContext);
10528
+ }
10529
+ if (entry.functionName) {
10530
+ const fn = options.derivationFunctions?.[entry.functionName];
10531
+ if (!fn) {
10532
+ const kind = options.functionKind ?? 'Derivation function';
10533
+ throw new DynamicFormError(`${kind} '${entry.functionName}' not found in customFnConfig.derivations`);
10534
+ }
10535
+ return fn(evalContext);
10536
+ }
10537
+ throw new DynamicFormError(`Derivation for ${options.subject} has no value source. Specify 'value', 'expression', or 'functionName'.`);
10538
+ }
10539
+
10540
+ /**
10541
+ * Returns the path to the parent of the given field path. Drops the last
10542
+ * `.`-delimited segment. Returns `undefined` when the field has no parent
10543
+ * in scope (single-segment root key).
10544
+ *
10545
+ * - `'address.state'` → `'address'`
10546
+ * - `'org.address.state'` → `'org.address'`
10547
+ * - `'state'` → `undefined`
10548
+ *
10549
+ * Used by the non-array evaluation context to populate `groupValue` from
10550
+ * the field's parent group on `formValue`.
10551
+ *
10552
+ * @internal
10553
+ */
10554
+ function getParentPathInScope(fieldKey) {
10555
+ const lastDot = fieldKey.lastIndexOf('.');
10556
+ if (lastDot <= 0)
10557
+ return undefined;
10558
+ return fieldKey.slice(0, lastDot);
10559
+ }
10560
+ /**
10561
+ * Resolves the per-array-item scope shared by both derivation applicators.
10562
+ *
10563
+ * Both `derivation-applicator.ts` and `property-derivation-applicator.ts`
10564
+ * need the same fan-out from `(pathInfo, arrayItem)` to `fieldValue`,
10565
+ * `groupValue`, and `relativePath` when building an evaluation context for
10566
+ * an array item. Centralising here keeps the two pipelines from drifting.
10567
+ *
10568
+ * @internal
10569
+ */
10570
+ function resolveArrayItemScope(pathInfo, arrayItem) {
10571
+ const relativePath = pathInfo.isArrayPath ? pathInfo.relativePath : '';
10572
+ const innerParentPath = relativePath.includes('.') ? relativePath.slice(0, relativePath.lastIndexOf('.')) : '';
10573
+ const groupValue = innerParentPath ? getNestedValue(arrayItem, innerParentPath) : arrayItem;
10574
+ const fieldValue = relativePath ? getNestedValue(arrayItem, relativePath) : arrayItem;
10575
+ return { relativePath, groupValue, fieldValue };
10576
+ }
10577
+
10535
10578
  /**
10536
10579
  * Centralized constants for the derivation system.
10537
10580
  *
@@ -11101,10 +11144,15 @@ function createEvaluationContext$1(entry, formValue, context, chainContext) {
11101
11144
  // Create field state snapshot for this specific field (non-reactive)
11102
11145
  const fieldAccessor = context.rootForm[entry.fieldKey];
11103
11146
  const fieldState = fieldAccessor ? readFieldStateInfo(fieldAccessor, false) : undefined;
11147
+ // Parent group value: the absolute path with the trailing field segment
11148
+ // dropped. `undefined` when the field is at form root.
11149
+ const parentPath = getParentPathInScope(entry.fieldKey);
11150
+ const groupValue = parentPath ? getNestedValue(formValue, parentPath) : undefined;
11104
11151
  return {
11105
11152
  fieldValue,
11106
11153
  formValue,
11107
11154
  fieldPath: entry.fieldKey,
11155
+ groupValue,
11108
11156
  customFunctions: context.customFunctions,
11109
11157
  externalData: context.externalData,
11110
11158
  logger: context.logger,
@@ -11143,10 +11191,12 @@ function createArrayItemEvaluationContext$1(entry, arrayItem, rootFormValue, ite
11143
11191
  }
11144
11192
  }
11145
11193
  }
11194
+ const { relativePath, groupValue, fieldValue } = resolveArrayItemScope(pathInfo, arrayItem);
11146
11195
  return {
11147
- fieldValue: arrayItem,
11196
+ fieldValue,
11148
11197
  formValue: arrayItem,
11149
- fieldPath: `${arrayPath}.${itemIndex}`,
11198
+ fieldPath: relativePath ? `${arrayPath}.${itemIndex}.${relativePath}` : `${arrayPath}.${itemIndex}`,
11199
+ groupValue,
11150
11200
  customFunctions: context.customFunctions,
11151
11201
  externalData: context.externalData,
11152
11202
  logger: context.logger,
@@ -11175,24 +11225,10 @@ function evaluateDerivationCondition(condition, context) {
11175
11225
  * @internal
11176
11226
  */
11177
11227
  function computeDerivedValue(entry, evalContext, applicatorContext) {
11178
- // Static value
11179
- if (entry.value !== undefined) {
11180
- return entry.value;
11181
- }
11182
- // Expression
11183
- if (entry.expression) {
11184
- return ExpressionParser.evaluate(entry.expression, evalContext);
11185
- }
11186
- // Custom function
11187
- if (entry.functionName) {
11188
- const fn = applicatorContext.derivationFunctions?.[entry.functionName];
11189
- if (!fn) {
11190
- throw new Error(`Derivation function '${entry.functionName}' not found in customFnConfig.derivations`);
11191
- }
11192
- return fn(evalContext);
11193
- }
11194
- // No value source specified
11195
- throw new Error(`Derivation for ${entry.fieldKey} has no value source. ` + `Specify 'value', 'expression', or 'functionName'.`);
11228
+ return computeValueFromEntry(entry, evalContext, {
11229
+ derivationFunctions: applicatorContext.derivationFunctions,
11230
+ subject: entry.fieldKey,
11231
+ });
11196
11232
  }
11197
11233
  /**
11198
11234
  * Error message prefix for derivation-related errors.
@@ -11442,6 +11478,134 @@ function topologicalSort(entries) {
11442
11478
  return sorted;
11443
11479
  }
11444
11480
 
11481
+ /**
11482
+ * Extracts the union of field dependencies declared by a derivation config.
11483
+ *
11484
+ * Combines:
11485
+ * - Explicit `dependsOn` (when provided, it takes precedence over auto-detection)
11486
+ * - Expression-detected dependencies (only used when `dependsOn` is empty)
11487
+ * - `'*'` wildcard for `functionName` (only when `dependsOn` is empty)
11488
+ * - Condition expression dependencies (always included)
11489
+ *
11490
+ * @internal
11491
+ */
11492
+ function extractDependenciesFromConfig(config) {
11493
+ const deps = new Set();
11494
+ if (config.dependsOn && config.dependsOn.length > 0) {
11495
+ config.dependsOn.forEach((dep) => deps.add(dep));
11496
+ }
11497
+ else {
11498
+ if (config.expression) {
11499
+ extractStringDependencies(config.expression).forEach((dep) => deps.add(dep));
11500
+ }
11501
+ if (config.functionName) {
11502
+ deps.add('*');
11503
+ }
11504
+ }
11505
+ if (config.condition && config.condition !== true) {
11506
+ extractExpressionDependencies(config.condition).forEach((dep) => deps.add(dep));
11507
+ }
11508
+ return Array.from(deps);
11509
+ }
11510
+
11511
+ /**
11512
+ * Recursively walks a field-definition tree, invoking `visitor` for each field.
11513
+ *
11514
+ * Owns the subtleties shared across derivation collectors:
11515
+ * - Detects container fields via `hasChildFields`.
11516
+ * - Falls back to the simplified-array Symbol-metadata template when an array
11517
+ * field has empty `fields` (the case for arrays initialized without a
11518
+ * starting `value` — only the metadata template carries their item shape).
11519
+ * - Flattens primitive (FieldDef) and object (FieldDef[]) array items into a
11520
+ * single child list before recursing.
11521
+ *
11522
+ * Callers customize per-boundary context via {@link FieldTraversalHooks}: e.g.,
11523
+ * the value-derivation collector tracks an array path AND a group path (with
11524
+ * the group path reset at array boundaries), while the property-derivation
11525
+ * collector tracks only the array path.
11526
+ *
11527
+ * @internal
11528
+ */
11529
+ function traverseFieldsWithContext(fields, context, visitor, hooks) {
11530
+ for (const field of fields) {
11531
+ visitor(field, context);
11532
+ if (!hasChildFields(field))
11533
+ continue;
11534
+ if (field.type === 'array') {
11535
+ const childContext = mergeContext(context, hooks?.onArrayChild?.(context, field));
11536
+ const arrayChildren = collectArrayChildren(field);
11537
+ traverseFieldsWithContext(arrayChildren, childContext, visitor, hooks);
11538
+ continue;
11539
+ }
11540
+ const overrides = field.type === 'group' ? hooks?.onGroupChild?.(context, field) : hooks?.onLayoutChild?.(context, field);
11541
+ const childContext = mergeContext(context, overrides);
11542
+ traverseFieldsWithContext(normalizeFieldsArray(field.fields), childContext, visitor, hooks);
11543
+ }
11544
+ }
11545
+ /**
11546
+ * Returns the flattened list of children for an array field, falling back
11547
+ * to the Symbol metadata template when `fields` is empty.
11548
+ *
11549
+ * Caller must ensure `field` is a container (passes `hasChildFields`); this
11550
+ * function reads `field.fields` directly and would error otherwise.
11551
+ *
11552
+ * @internal
11553
+ */
11554
+ function collectArrayChildren(field) {
11555
+ let arrayItems = normalizeFieldsArray(field.fields);
11556
+ if (arrayItems.length === 0) {
11557
+ const metadataTemplate = getNormalizedArrayMetadata(field)?.template;
11558
+ if (metadataTemplate) {
11559
+ arrayItems = [
11560
+ Array.isArray(metadataTemplate) ? [...metadataTemplate] : metadataTemplate,
11561
+ ];
11562
+ }
11563
+ }
11564
+ const flattened = [];
11565
+ for (const item of arrayItems) {
11566
+ if (Array.isArray(item)) {
11567
+ flattened.push(...item);
11568
+ }
11569
+ else {
11570
+ flattened.push(item);
11571
+ }
11572
+ }
11573
+ return flattened;
11574
+ }
11575
+ /** @internal */
11576
+ function mergeContext(base, overrides) {
11577
+ return overrides ? { ...base, ...overrides } : { ...base };
11578
+ }
11579
+
11580
+ /**
11581
+ * Token in `dependsOn` arrays that resolves to the current field's own
11582
+ * absolute path at collection time. Useful for self-derivations on fields
11583
+ * nested under groups, where the absolute path depends on ancestor keys
11584
+ * the config author may not know (e.g. factory-built field shapes).
11585
+ *
11586
+ * @public
11587
+ */
11588
+ const SELF_DEPENDENCY_TOKEN = '$self';
11589
+ /**
11590
+ * Token in `dependsOn` arrays that resolves to the absolute path of the
11591
+ * field's nearest parent container (group or array) at collection time.
11592
+ *
11593
+ * Useful when a derivation should fire whenever any sibling under the
11594
+ * same parent container changes (e.g. "compute when anything in the
11595
+ * address group is edited") without enumerating each sibling explicitly.
11596
+ *
11597
+ * Resolution rules:
11598
+ * - Inside group(s) only: resolves to the dotted ancestor group path
11599
+ * (e.g. `'address'` or `'org.address'`).
11600
+ * - Inside an array (no group between): resolves to the array key
11601
+ * (e.g. `'items'`). Fires whenever any item changes.
11602
+ * - Inside group(s) inside an array: resolves to the array placeholder
11603
+ * form including the inner groups (e.g. `'items.$.address'`).
11604
+ * - At form root: throws `DynamicFormError` (no parent to target).
11605
+ *
11606
+ * @public
11607
+ */
11608
+ const GROUP_DEPENDENCY_TOKEN = '$group';
11445
11609
  /**
11446
11610
  * Collects all derivation entries from field definitions.
11447
11611
  *
@@ -11479,8 +11643,21 @@ function topologicalSort(entries) {
11479
11643
  */
11480
11644
  function collectDerivations(fields) {
11481
11645
  const entries = [];
11482
- const context = {};
11483
- traverseFields$1(fields, entries, context);
11646
+ traverseFieldsWithContext(fields, {}, (field, context) => collectFromField$1(field, entries, context), {
11647
+ // Array boundary: the array placeholder path takes over and any
11648
+ // ancestor groupPath is reset for descendants (entries inside
11649
+ // array items use `arrayPath.$.fieldKey` form).
11650
+ onArrayChild: (_, field) => ({ arrayPath: field.key, groupPath: undefined }),
11651
+ onGroupChild: (parent, field) => {
11652
+ // Group establishes a model boundary; descend with the field's
11653
+ // key appended to the ancestor groupPath. Groups without a key
11654
+ // (rare) act like layout containers — leave context unchanged.
11655
+ if (!field.key)
11656
+ return {};
11657
+ return { groupPath: parent.groupPath ? `${parent.groupPath}.${field.key}` : field.key };
11658
+ },
11659
+ // Layout containers (page, row, container) leave context unchanged.
11660
+ });
11484
11661
  // Sort entries in topological order for efficient processing.
11485
11662
  // This ensures derivations are processed in dependency order,
11486
11663
  // reducing the number of iterations needed in the applicator.
@@ -11488,40 +11665,83 @@ function collectDerivations(fields) {
11488
11665
  return { entries: sortedEntries };
11489
11666
  }
11490
11667
  /**
11491
- * Recursively traverses field definitions to collect derivations.
11668
+ * Builds the absolute field path for a derivation entry from the field's
11669
+ * key and the current collection context.
11670
+ *
11671
+ * - Inside an array AND inside one or more groups (groups nested under
11672
+ * the array item): combines both as `${arrayPath}.$.${groupPath}.${fieldKey}`.
11673
+ * - Inside an array only: returns `${arrayPath}.$.${fieldKey}`.
11674
+ * - Inside one or more groups: returns `${groupPath}.${fieldKey}`.
11675
+ * - Otherwise returns `fieldKey` unchanged.
11676
+ *
11677
+ * `groupPath` is reset when entering an array (each array item is its own
11678
+ * model root); ancestor groups OUTSIDE the array are not part of the
11679
+ * entry path. Groups INSIDE the array are tracked via `groupPath` and
11680
+ * combined here.
11492
11681
  *
11493
11682
  * @internal
11494
11683
  */
11495
- function traverseFields$1(fields, entries, context) {
11496
- for (const field of fields) {
11497
- collectFromField$1(field, entries, context);
11498
- // Recursively process container fields (page, row, group, array)
11499
- if (hasChildFields(field)) {
11500
- const childContext = { ...context };
11501
- // Update array path context if this is an array field
11502
- if (field.type === 'array') {
11503
- childContext.arrayPath = field.key;
11504
- // Array fields have items that can be either FieldDef (primitive) or FieldDef[] (object).
11505
- // Normalize all items to arrays and flatten for traversal.
11506
- const arrayItems = normalizeFieldsArray(field.fields);
11507
- const normalizedChildren = [];
11508
- for (const item of arrayItems) {
11509
- if (Array.isArray(item)) {
11510
- // Object item: FieldDef[] - add each field
11511
- normalizedChildren.push(...item);
11512
- }
11513
- else {
11514
- // Primitive item: single FieldDef - add directly
11515
- normalizedChildren.push(item);
11516
- }
11517
- }
11518
- traverseFields$1(normalizedChildren, entries, childContext);
11519
- }
11520
- else {
11521
- traverseFields$1(normalizeFieldsArray(field.fields), entries, childContext);
11684
+ function buildEffectiveFieldKey(fieldKey, context) {
11685
+ if (context.arrayPath && context.groupPath) {
11686
+ return `${context.arrayPath}.$.${context.groupPath}.${fieldKey}`;
11687
+ }
11688
+ if (context.arrayPath) {
11689
+ return `${context.arrayPath}.$.${fieldKey}`;
11690
+ }
11691
+ if (context.groupPath) {
11692
+ return `${context.groupPath}.${fieldKey}`;
11693
+ }
11694
+ return fieldKey;
11695
+ }
11696
+ /**
11697
+ * Resolves the absolute path of the field's nearest parent container
11698
+ * (group or array). Returns `undefined` when the field is at the form
11699
+ * root with no parent container.
11700
+ *
11701
+ * @internal
11702
+ */
11703
+ function buildNearestGroupPath(context) {
11704
+ if (context.arrayPath && context.groupPath) {
11705
+ return `${context.arrayPath}.$.${context.groupPath}`;
11706
+ }
11707
+ return context.arrayPath ?? context.groupPath;
11708
+ }
11709
+ /**
11710
+ * Substitutes special tokens in a `dependsOn` array with their resolved
11711
+ * absolute paths. Currently supports:
11712
+ *
11713
+ * - `SELF_DEPENDENCY_TOKEN` ('$self') → the field's own absolute path
11714
+ * - `'$self.X'` → the field's own path joined with `.X` (e.g. for object-valued
11715
+ * fields where you want to depend on a sub-property)
11716
+ * - `GROUP_DEPENDENCY_TOKEN` ('$group') → the field's nearest parent
11717
+ * container path; throws if the field has no parent group/array.
11718
+ * - `'$group.sibling'` → the parent path joined with `.sibling`, useful to
11719
+ * target a specific sibling without naming the parent group key.
11720
+ *
11721
+ * Non-token strings are passed through unchanged.
11722
+ *
11723
+ * @internal
11724
+ */
11725
+ function resolveTokenDependencies(deps, effectiveFieldKey, context) {
11726
+ return deps.map((dep) => {
11727
+ if (dep === SELF_DEPENDENCY_TOKEN) {
11728
+ return effectiveFieldKey;
11729
+ }
11730
+ if (dep.startsWith(`${SELF_DEPENDENCY_TOKEN}.`)) {
11731
+ return effectiveFieldKey + dep.slice(SELF_DEPENDENCY_TOKEN.length);
11732
+ }
11733
+ if (dep === GROUP_DEPENDENCY_TOKEN || dep.startsWith(`${GROUP_DEPENDENCY_TOKEN}.`)) {
11734
+ const groupPath = buildNearestGroupPath(context);
11735
+ if (!groupPath) {
11736
+ throw new DynamicFormError(`Derivation for '${effectiveFieldKey}' uses '${dep}' but the field has no parent group or array. ` +
11737
+ `'${GROUP_DEPENDENCY_TOKEN}' is only valid for fields nested inside a group or array container.`);
11522
11738
  }
11739
+ if (dep === GROUP_DEPENDENCY_TOKEN)
11740
+ return groupPath;
11741
+ return groupPath + dep.slice(GROUP_DEPENDENCY_TOKEN.length);
11523
11742
  }
11524
- }
11743
+ return dep;
11744
+ });
11525
11745
  }
11526
11746
  /**
11527
11747
  * Collects derivation entries from a single field.
@@ -11561,8 +11781,7 @@ function collectFromField$1(field, entries, context) {
11561
11781
  * @internal
11562
11782
  */
11563
11783
  function createShorthandEntry(fieldKey, expression, context) {
11564
- // Build the effective field key, including array path if in array context
11565
- const effectiveFieldKey = context.arrayPath ? `${context.arrayPath}.$.${fieldKey}` : fieldKey;
11784
+ const effectiveFieldKey = buildEffectiveFieldKey(fieldKey, context);
11566
11785
  return {
11567
11786
  fieldKey: effectiveFieldKey,
11568
11787
  dependsOn: extractStringDependencies(expression),
@@ -11588,11 +11807,16 @@ function createShorthandEntry(fieldKey, expression, context) {
11588
11807
  * @internal
11589
11808
  */
11590
11809
  function createLogicEntry(fieldKey, config, context) {
11591
- // Build the effective field key, including array path if in array context
11592
- const effectiveFieldKey = context.arrayPath ? `${context.arrayPath}.$.${fieldKey}` : fieldKey;
11810
+ const effectiveFieldKey = buildEffectiveFieldKey(fieldKey, context);
11593
11811
  // Runtime guards for HTTP and async derivations.
11594
11812
  // Mutual exclusivity and required fields are now enforced by TypeScript (via `source` discriminant).
11595
11813
  // The wildcard and empty-array checks below are not expressible in the type system.
11814
+ //
11815
+ // Note: `$group` / `$group.X` tokens are intentionally allowed for HTTP and async sources even
11816
+ // though they resolve to the parent path and therefore fire on any sibling change inside that
11817
+ // group/array. Unlike `*`, the token is structurally scoped (collection throws if the field has
11818
+ // no parent container) and an explicit opt-in. Consumers that want to bound request frequency
11819
+ // can use `trigger: 'debounced'` here, or rely on debouncing inside their async function.
11596
11820
  if (config.source === 'http') {
11597
11821
  if (config.dependsOn.length === 0) {
11598
11822
  throw new DynamicFormError(`HTTP derivation for '${effectiveFieldKey}' requires explicit 'dependsOn'. ` +
@@ -11613,7 +11837,7 @@ function createLogicEntry(fieldKey, config, context) {
11613
11837
  `Wildcards would trigger async functions on every form change. Specify explicit field dependencies instead.`);
11614
11838
  }
11615
11839
  }
11616
- const dependsOn = extractDependencies$1(config);
11840
+ const dependsOn = resolveTokenDependencies(extractDependenciesFromConfig(config), effectiveFieldKey, context);
11617
11841
  const condition = config.condition ?? true;
11618
11842
  const trigger = config.trigger ?? 'onChange';
11619
11843
  // Extract debounceMs from debounced configs
@@ -11638,43 +11862,6 @@ function createLogicEntry(fieldKey, config, context) {
11638
11862
  reEngageOnDependencyChange: config.reEngageOnDependencyChange,
11639
11863
  };
11640
11864
  }
11641
- /**
11642
- * Extracts all field dependencies from a derivation config.
11643
- *
11644
- * Combines dependencies from:
11645
- * - Explicit `dependsOn` array (if provided, takes precedence)
11646
- * - Condition expression
11647
- * - Value expression
11648
- * - Function name (defaults to '*' if no explicit dependsOn)
11649
- *
11650
- * @internal
11651
- */
11652
- function extractDependencies$1(config) {
11653
- const deps = new Set();
11654
- // If explicit dependsOn is provided, use it as the primary source
11655
- // This allows users to override automatic detection and control
11656
- // when derivations are triggered
11657
- if (config.dependsOn && config.dependsOn.length > 0) {
11658
- config.dependsOn.forEach((dep) => deps.add(dep));
11659
- }
11660
- else {
11661
- // Extract from expression (automatic dependency detection)
11662
- if (config.expression) {
11663
- const exprDeps = extractStringDependencies(config.expression);
11664
- exprDeps.forEach((dep) => deps.add(dep));
11665
- }
11666
- // Custom functions assume full form access if no explicit dependsOn
11667
- if (config.functionName) {
11668
- deps.add('*');
11669
- }
11670
- }
11671
- // Always extract from condition (these are additional runtime guards)
11672
- if (config.condition && config.condition !== true) {
11673
- const conditionDeps = extractExpressionDependencies(config.condition);
11674
- conditionDeps.forEach((dep) => deps.add(dep));
11675
- }
11676
- return Array.from(deps);
11677
- }
11678
11865
 
11679
11866
  /**
11680
11867
  * Detects cycles in the derivation dependency graph.
@@ -12361,6 +12548,58 @@ function createAsyncDerivationStream(entry, formValue$, context) {
12361
12548
  }));
12362
12549
  }
12363
12550
 
12551
+ /**
12552
+ * Returns the unique set of debounce periods declared by `entries` whose
12553
+ * `trigger === 'debounced'`. Entries without an explicit `debounceMs` use
12554
+ * {@link DEFAULT_DEBOUNCE_MS}.
12555
+ *
12556
+ * @internal
12557
+ */
12558
+ function getDebouncePeriods(entries) {
12559
+ const periods = new Set();
12560
+ for (const entry of entries) {
12561
+ if (entry.trigger === 'debounced') {
12562
+ periods.add(entry.debounceMs ?? DEFAULT_DEBOUNCE_MS);
12563
+ }
12564
+ }
12565
+ return Array.from(periods);
12566
+ }
12567
+ /**
12568
+ * Filters `entries` down to those whose `trigger === 'debounced'` and whose
12569
+ * effective `debounceMs` (defaulting to {@link DEFAULT_DEBOUNCE_MS}) equals `period`.
12570
+ *
12571
+ * @internal
12572
+ */
12573
+ function filterEntriesByDebouncePeriod(entries, period) {
12574
+ return entries.filter((entry) => entry.trigger === 'debounced' && (entry.debounceMs ?? DEFAULT_DEBOUNCE_MS) === period);
12575
+ }
12576
+
12577
+ /**
12578
+ * Resolves a record of external-data signals to their current values without
12579
+ * establishing reactive dependencies.
12580
+ *
12581
+ * The orchestrators read external data per derivation cycle; using `untracked`
12582
+ * here ensures the orchestrator's own computed/effect graph isn't tied to the
12583
+ * external-data signal identities.
12584
+ *
12585
+ * @internal
12586
+ */
12587
+ function resolveExternalData(externalDataSignal) {
12588
+ const externalDataRecord = untracked(() => externalDataSignal?.());
12589
+ if (!externalDataRecord)
12590
+ return undefined;
12591
+ const resolved = {};
12592
+ for (const [key, value] of Object.entries(externalDataRecord)) {
12593
+ if (isSignal(value)) {
12594
+ resolved[key] = untracked(() => value());
12595
+ }
12596
+ else {
12597
+ resolved[key] = value;
12598
+ }
12599
+ }
12600
+ return resolved;
12601
+ }
12602
+
12364
12603
  /**
12365
12604
  * Orchestrates derivation processing for a dynamic form.
12366
12605
  *
@@ -12477,7 +12716,7 @@ class DerivationOrchestrator {
12477
12716
  if (!collection || !formAccessor)
12478
12717
  return of(null);
12479
12718
  // Get unique debounce periods from entries with trigger 'debounced'
12480
- const debouncePeriods = this.getDebouncePeriods(collection.entries);
12719
+ const debouncePeriods = getDebouncePeriods(collection.entries);
12481
12720
  if (debouncePeriods.length === 0)
12482
12721
  return of(null);
12483
12722
  // merge: Process multiple debounce periods concurrently.
@@ -12510,7 +12749,7 @@ class DerivationOrchestrator {
12510
12749
  rootForm: formAccessor,
12511
12750
  derivationFunctions: this.functionRegistry.getDerivationFunctions(),
12512
12751
  customFunctions: this.functionRegistry.getCustomFunctions(),
12513
- externalData: this.resolveExternalData(),
12752
+ externalData: resolveExternalData(this.config.externalData),
12514
12753
  logger: this.logger,
12515
12754
  warningTracker: this.warningTracker,
12516
12755
  derivationLogger: untracked(() => this.config.derivationLogger()),
@@ -12538,7 +12777,7 @@ class DerivationOrchestrator {
12538
12777
  rootForm: formAccessor,
12539
12778
  derivationFunctions: this.functionRegistry.getDerivationFunctions(),
12540
12779
  customFunctions: this.functionRegistry.getCustomFunctions(),
12541
- externalData: this.resolveExternalData(),
12780
+ externalData: resolveExternalData(this.config.externalData),
12542
12781
  logger: this.logger,
12543
12782
  warningTracker: this.warningTracker,
12544
12783
  derivationLogger: untracked(() => this.config.derivationLogger()),
@@ -12588,7 +12827,7 @@ class DerivationOrchestrator {
12588
12827
  logger: this.logger,
12589
12828
  derivationLogger: this.config.derivationLogger,
12590
12829
  customFunctions: () => this.functionRegistry.getCustomFunctions(),
12591
- externalData: () => this.resolveExternalData(),
12830
+ externalData: () => resolveExternalData(this.config.externalData),
12592
12831
  warningTracker: this.warningTracker,
12593
12832
  guard$: this.streamGuard.guard$,
12594
12833
  };
@@ -12662,7 +12901,7 @@ class DerivationOrchestrator {
12662
12901
  derivationLogger: this.config.derivationLogger,
12663
12902
  customFunctions: () => this.functionRegistry.getCustomFunctions(),
12664
12903
  asyncDerivationFunctions: () => this.functionRegistry.getAsyncDerivationFunctions(),
12665
- externalData: () => this.resolveExternalData(),
12904
+ externalData: () => resolveExternalData(this.config.externalData),
12666
12905
  warningTracker: this.warningTracker,
12667
12906
  };
12668
12907
  const stream = createAsyncDerivationStream(entry, formValue$, context).pipe(takeUntilDestroyed(this.destroyRef));
@@ -12697,42 +12936,6 @@ class DerivationOrchestrator {
12697
12936
  return `${entry.fieldKey}:${JSON.stringify(config, Object.keys(config).sort())}`;
12698
12937
  }));
12699
12938
  }
12700
- /**
12701
- * Gets all unique debounce periods from entries with trigger 'debounced'.
12702
- */
12703
- getDebouncePeriods(entries) {
12704
- const periods = new Set();
12705
- for (const entry of entries) {
12706
- if (entry.trigger === 'debounced') {
12707
- periods.add(entry.debounceMs ?? DEFAULT_DEBOUNCE_MS);
12708
- }
12709
- }
12710
- return Array.from(periods);
12711
- }
12712
- /**
12713
- * Resolves external data signals to their current values without creating dependencies.
12714
- *
12715
- * Uses `untracked()` to read signals without establishing reactive dependencies,
12716
- * which is important for derivations that shouldn't re-trigger on every external data change.
12717
- *
12718
- * @returns Record of resolved external data values, or undefined if no external data.
12719
- */
12720
- resolveExternalData() {
12721
- const externalDataRecord = untracked(() => this.config.externalData?.());
12722
- if (!externalDataRecord) {
12723
- return undefined;
12724
- }
12725
- const resolved = {};
12726
- for (const [key, signal] of Object.entries(externalDataRecord)) {
12727
- if (isSignal(signal)) {
12728
- resolved[key] = untracked(() => signal());
12729
- }
12730
- else {
12731
- resolved[key] = signal;
12732
- }
12733
- }
12734
- return resolved;
12735
- }
12736
12939
  }
12737
12940
  /**
12738
12941
  * Creates a DerivationOrchestrator for a dynamic form.
@@ -13171,14 +13374,26 @@ function tryApplyArrayPropertyDerivation(entry, context) {
13171
13374
  /**
13172
13375
  * Creates an evaluation context for property derivation processing.
13173
13376
  *
13377
+ * Note: `fieldState`/`formFieldState` are intentionally not populated here.
13378
+ * Property derivations run against the form value signal and write to a
13379
+ * separate override store; the applicator does not have access to the live
13380
+ * `FieldTree` (no `rootForm` on `PropertyDerivationApplicatorContext`), so
13381
+ * field-state snapshots cannot be read in this pipeline. Functions that need
13382
+ * field state (e.g. `dirty()`, `touched()`) must use a regular derivation.
13383
+ *
13174
13384
  * @internal
13175
13385
  */
13176
13386
  function createEvaluationContext(entry, formValue, context) {
13177
13387
  const fieldValue = getNestedValue(formValue, entry.fieldKey);
13388
+ // Parent group value: the absolute path with the trailing field segment
13389
+ // dropped. `undefined` when the field is at form root.
13390
+ const parentPath = getParentPathInScope(entry.fieldKey);
13391
+ const groupValue = parentPath ? getNestedValue(formValue, parentPath) : undefined;
13178
13392
  return {
13179
13393
  fieldValue,
13180
13394
  formValue,
13181
13395
  fieldPath: entry.fieldKey,
13396
+ groupValue,
13182
13397
  customFunctions: context.customFunctions,
13183
13398
  externalData: context.externalData,
13184
13399
  logger: context.logger,
@@ -13190,10 +13405,13 @@ function createEvaluationContext(entry, formValue, context) {
13190
13405
  * @internal
13191
13406
  */
13192
13407
  function createArrayItemEvaluationContext(entry, arrayItem, rootFormValue, itemIndex, arrayPath, context) {
13408
+ const pathInfo = parseArrayPath(entry.fieldKey);
13409
+ const { relativePath, groupValue, fieldValue } = resolveArrayItemScope(pathInfo, arrayItem);
13193
13410
  return {
13194
- fieldValue: arrayItem,
13411
+ fieldValue,
13195
13412
  formValue: arrayItem,
13196
- fieldPath: `${arrayPath}.${itemIndex}`,
13413
+ fieldPath: relativePath ? `${arrayPath}.${itemIndex}.${relativePath}` : `${arrayPath}.${itemIndex}`,
13414
+ groupValue,
13197
13415
  customFunctions: context.customFunctions,
13198
13416
  externalData: context.externalData,
13199
13417
  logger: context.logger,
@@ -13219,24 +13437,11 @@ function evaluatePropertyCondition(condition, context) {
13219
13437
  * @internal
13220
13438
  */
13221
13439
  function computePropertyValue(entry, evalContext, applicatorContext) {
13222
- // Static value
13223
- if (entry.value !== undefined) {
13224
- return entry.value;
13225
- }
13226
- // Expression
13227
- if (entry.expression) {
13228
- return ExpressionParser.evaluate(entry.expression, evalContext);
13229
- }
13230
- // Custom function
13231
- if (entry.functionName) {
13232
- const fn = applicatorContext.derivationFunctions?.[entry.functionName];
13233
- if (!fn) {
13234
- throw new DynamicFormError(`Property derivation function '${entry.functionName}' not found in customFnConfig.derivations`);
13235
- }
13236
- return fn(evalContext);
13237
- }
13238
- throw new DynamicFormError(`Property derivation for ${entry.fieldKey}.${entry.targetProperty} has no value source. ` +
13239
- `Specify 'value', 'expression', or 'functionName'.`);
13440
+ return computeValueFromEntry(entry, evalContext, {
13441
+ derivationFunctions: applicatorContext.derivationFunctions,
13442
+ subject: `${entry.fieldKey}.${entry.targetProperty}`,
13443
+ functionKind: 'Property derivation function',
13444
+ });
13240
13445
  }
13241
13446
 
13242
13447
  /**
@@ -13256,40 +13461,12 @@ function computePropertyValue(entry, evalContext, applicatorContext) {
13256
13461
  function collectPropertyDerivations(fields, logger, tracker) {
13257
13462
  const entries = [];
13258
13463
  const context = { logger, tracker };
13259
- traverseFields(fields, entries, context);
13464
+ traverseFieldsWithContext(fields, context, (field, ctx) => collectFromField(field, entries, ctx), {
13465
+ onArrayChild: (_, field) => ({ arrayPath: field.key }),
13466
+ // Group and layout containers do not affect property-derivation paths.
13467
+ });
13260
13468
  return { entries };
13261
13469
  }
13262
- /**
13263
- * Recursively traverses field definitions to collect property derivations.
13264
- *
13265
- * @internal
13266
- */
13267
- function traverseFields(fields, entries, context) {
13268
- for (const field of fields) {
13269
- collectFromField(field, entries, context);
13270
- // Recursively process container fields (page, row, group, array)
13271
- if (hasChildFields(field)) {
13272
- const childContext = { ...context };
13273
- if (field.type === 'array') {
13274
- childContext.arrayPath = field.key;
13275
- const arrayItems = normalizeFieldsArray(field.fields);
13276
- const normalizedChildren = [];
13277
- for (const item of arrayItems) {
13278
- if (Array.isArray(item)) {
13279
- normalizedChildren.push(...item);
13280
- }
13281
- else {
13282
- normalizedChildren.push(item);
13283
- }
13284
- }
13285
- traverseFields(normalizedChildren, entries, childContext);
13286
- }
13287
- else {
13288
- traverseFields(normalizeFieldsArray(field.fields), entries, childContext);
13289
- }
13290
- }
13291
- }
13292
- }
13293
13470
  /**
13294
13471
  * Collects property derivation entries from a single field.
13295
13472
  *
@@ -13319,7 +13496,7 @@ function collectFromField(field, entries, context) {
13319
13496
  */
13320
13497
  function createPropertyDerivationEntryFromDerivation(fieldKey, config, context) {
13321
13498
  const effectiveFieldKey = buildPropertyOverrideKey(context.arrayPath, context.arrayPath ? PLACEHOLDER_INDEX : undefined, fieldKey);
13322
- const dependsOn = extractDependencies(config);
13499
+ const dependsOn = extractDependenciesFromConfig(config);
13323
13500
  const condition = config.condition ?? true;
13324
13501
  const trigger = config.trigger ?? 'onChange';
13325
13502
  const debounceMs = trigger === 'debounced' ? config.debounceMs : undefined;
@@ -13337,32 +13514,6 @@ function createPropertyDerivationEntryFromDerivation(fieldKey, config, context)
13337
13514
  originalConfig: config,
13338
13515
  };
13339
13516
  }
13340
- /**
13341
- * Extracts all field dependencies from a property derivation config.
13342
- *
13343
- * @internal
13344
- */
13345
- function extractDependencies(config) {
13346
- const deps = new Set();
13347
- if (config.dependsOn && config.dependsOn.length > 0) {
13348
- config.dependsOn.forEach((dep) => deps.add(dep));
13349
- }
13350
- else {
13351
- if (config.expression) {
13352
- const exprDeps = extractStringDependencies(config.expression);
13353
- exprDeps.forEach((dep) => deps.add(dep));
13354
- }
13355
- if (config.functionName) {
13356
- deps.add('*');
13357
- }
13358
- }
13359
- // Always extract from condition
13360
- if (config.condition && config.condition !== true) {
13361
- const conditionDeps = extractExpressionDependencies(config.condition);
13362
- conditionDeps.forEach((dep) => deps.add(dep));
13363
- }
13364
- return Array.from(deps);
13365
- }
13366
13517
 
13367
13518
  /**
13368
13519
  * Orchestrates property derivation processing for a dynamic form.
@@ -13440,7 +13591,7 @@ class PropertyDerivationOrchestrator {
13440
13591
  const collection = untracked(() => this.propertyDerivationCollection());
13441
13592
  if (!collection)
13442
13593
  return of(null);
13443
- const debouncePeriods = this.getDebouncePeriods(collection.entries);
13594
+ const debouncePeriods = getDebouncePeriods(collection.entries);
13444
13595
  if (debouncePeriods.length === 0)
13445
13596
  return of(null);
13446
13597
  const periodStreams = debouncePeriods.map((debounceMs) => this.createPeriodStream(debounceMs, collection, changedFields));
@@ -13465,7 +13616,7 @@ class PropertyDerivationOrchestrator {
13465
13616
  store: this.config.store,
13466
13617
  derivationFunctions: this.functionRegistry.getDerivationFunctions(),
13467
13618
  customFunctions: this.functionRegistry.getCustomFunctions(),
13468
- externalData: this.resolveExternalData(),
13619
+ externalData: resolveExternalData(this.config.externalData),
13469
13620
  logger: this.logger,
13470
13621
  warningTracker: this.warningTracker,
13471
13622
  };
@@ -13481,45 +13632,12 @@ class PropertyDerivationOrchestrator {
13481
13632
  store: this.config.store,
13482
13633
  derivationFunctions: this.functionRegistry.getDerivationFunctions(),
13483
13634
  customFunctions: this.functionRegistry.getCustomFunctions(),
13484
- externalData: this.resolveExternalData(),
13635
+ externalData: resolveExternalData(this.config.externalData),
13485
13636
  logger: this.logger,
13486
13637
  warningTracker: this.warningTracker,
13487
13638
  };
13488
13639
  applyPropertyDerivationsForTrigger(filteredCollection, 'debounced', applicatorContext, changedFields);
13489
13640
  }
13490
- getDebouncePeriods(entries) {
13491
- const periods = new Set();
13492
- for (const entry of entries) {
13493
- if (entry.trigger === 'debounced') {
13494
- periods.add(entry.debounceMs ?? DEFAULT_DEBOUNCE_MS);
13495
- }
13496
- }
13497
- return Array.from(periods);
13498
- }
13499
- /**
13500
- * Resolves external data signals to their current values.
13501
- *
13502
- * Called on every onChange and debounced application. Each call iterates all
13503
- * external data entries and resolves signals via untracked(). For forms with
13504
- * many external data entries, this could be optimized by caching the resolved
13505
- * record and only invalidating when external data signal values change.
13506
- * In practice, external data entries are few, so the linear scan is acceptable.
13507
- */
13508
- resolveExternalData() {
13509
- const externalDataRecord = untracked(() => this.config.externalData?.());
13510
- if (!externalDataRecord)
13511
- return undefined;
13512
- const resolved = {};
13513
- for (const [key, signalValue] of Object.entries(externalDataRecord)) {
13514
- if (isSignal(signalValue)) {
13515
- resolved[key] = untracked(() => signalValue());
13516
- }
13517
- else {
13518
- resolved[key] = signalValue;
13519
- }
13520
- }
13521
- return resolved;
13522
- }
13523
13641
  }
13524
13642
  /**
13525
13643
  * Creates a PropertyDerivationOrchestrator for a dynamic form.
@@ -14491,7 +14609,10 @@ function rowFieldMapper(fieldDef) {
14491
14609
  // Rebuilt each emission so logic-driven updates to fieldDef (e.g. `disabled`)
14492
14610
  // flow through. Shallow spread is safe while RowField has no nested
14493
14611
  // mutable props; add a deep-clone if that stops being true.
14494
- const containerField = { ...fieldDef, wrappers: ROW_WRAPPERS };
14612
+ // `type` is rewritten to 'container' because `row` is a synthetic field
14613
+ // type — the runtime renders it as a ContainerField with a synthesized
14614
+ // `{ type: 'row' }` wrapper.
14615
+ const containerField = { ...fieldDef, type: 'container', wrappers: ROW_WRAPPERS };
14495
14616
  const inputs = {
14496
14617
  key: fieldDef.key,
14497
14618
  field: containerField,
@@ -14637,31 +14758,31 @@ const BUILT_IN_FIELDS = [
14637
14758
  // `row` is a virtual field type: it maps to ContainerFieldComponent, and
14638
14759
  // the rowFieldMapper injects a `{ type: 'row' }` wrapper so the container
14639
14760
  // renders the flex/grid layout via RowWrapperComponent.
14640
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-DQ_OQLtx.mjs'),
14761
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-PozYj2JC.mjs'),
14641
14762
  mapper: rowFieldMapper,
14642
14763
  valueHandling: 'flatten',
14643
14764
  },
14644
14765
  {
14645
14766
  name: 'group',
14646
- loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-BdLdSEHj.mjs'),
14767
+ loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-2yRmHAUp.mjs'),
14647
14768
  mapper: groupFieldMapper,
14648
14769
  valueHandling: 'include',
14649
14770
  },
14650
14771
  {
14651
14772
  name: 'array',
14652
- loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-CJ_OclbR.mjs'),
14773
+ loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-CWxCWVdz.mjs'),
14653
14774
  mapper: arrayFieldMapper,
14654
14775
  valueHandling: 'include',
14655
14776
  },
14656
14777
  {
14657
14778
  name: 'page',
14658
- loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-C5rUo80O.mjs'),
14779
+ loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-B_CxX0T-.mjs'),
14659
14780
  mapper: pageFieldMapper,
14660
14781
  valueHandling: 'flatten',
14661
14782
  },
14662
14783
  {
14663
14784
  name: 'text',
14664
- loadComponent: () => import('./ng-forge-dynamic-forms-text-field.component-lvuyTM1r.mjs'),
14785
+ loadComponent: () => import('./ng-forge-dynamic-forms-text-field.component-rJMtKX2X.mjs'),
14665
14786
  mapper: textFieldMapper,
14666
14787
  valueHandling: 'exclude',
14667
14788
  ...DISPLAY_FIELD_TYPES_BASE,
@@ -14673,7 +14794,7 @@ const BUILT_IN_FIELDS = [
14673
14794
  },
14674
14795
  {
14675
14796
  name: 'container',
14676
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-DQ_OQLtx.mjs'),
14797
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-PozYj2JC.mjs'),
14677
14798
  mapper: containerFieldMapper,
14678
14799
  valueHandling: 'flatten',
14679
14800
  },
@@ -14681,7 +14802,7 @@ const BUILT_IN_FIELDS = [
14681
14802
  const BUILT_IN_WRAPPERS = [
14682
14803
  {
14683
14804
  wrapperName: 'css',
14684
- loadComponent: () => import('./ng-forge-dynamic-forms-css-wrapper.component-2fdmbtL7.mjs'),
14805
+ loadComponent: () => import('./ng-forge-dynamic-forms-css-wrapper.component-DrtHSaVV.mjs'),
14685
14806
  },
14686
14807
  {
14687
14808
  wrapperName: 'row',
@@ -15714,4 +15835,4 @@ function extractErrorParams(error) {
15714
15835
  */
15715
15836
 
15716
15837
  export { SubmitEvent as $, ARRAY_CONTEXT as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DynamicFormLogger as D, EventBus as E, FIELD_SIGNAL_CONTEXT as F, DEFAULT_VALIDATION_MESSAGES as G, DynamicForm as H, DynamicFormError as I, EventDispatcher as J, FIELD_REGISTRY as K, FORM_OPTIONS as L, FormClearEvent as M, FormResetEvent as N, INITIALIZATION_TIMEOUT_MS as O, InsertArrayItemEvent as P, MoveArrayItemEvent as Q, RootFormRegistryService as R, NextPageEvent as S, NoopLogger as T, PageChangeEvent as U, PopArrayItemEvent as V, WRAPPER_AUTO_ASSOCIATIONS as W, PrependArrayItemEvent as X, PreviousPageEvent as Y, RemoveAtIndexEvent as Z, ShiftArrayItemEvent as _, DEFAULT_WRAPPERS as a, WRAPPER_REGISTRY as a0, applyMetaToElement as a1, applyValidator as a2, applyValidators as a3, arrayEvent as a4, arrayFieldMapper as a5, baseFieldMapper as a6, buildBaseInputs as a7, containerFieldMapper as a8, createField as a9, resolveNextButtonDisabled as aA, resolveNonFieldDisabled as aB, resolveNonFieldHidden as aC, resolveSubmitButtonDisabled as aD, resolveTokens as aE, rowFieldMapper as aF, textFieldMapper as aG, toReadonlyFieldTree as aH, withEventFormValue as aI, withLoggerConfig as aJ, withPreviousValue as aK, withValueExclusionDefaults as aL, wrapperProps as aM, createWrappers as aa, evaluateNonFieldDisabled as ab, evaluateNonFieldHidden as ac, field as ad, formConfig as ae, getArrayLength as af, groupFieldMapper as ag, hasFormValue as ah, interpolateParams as ai, isArrayField as aj, isCheckedField as ak, isContainerField as al, isContainerTypedField as am, isDisplayOnlyField as an, isFormStateCondition as ao, isLeafField as ap, isPageField as aq, isRowField as ar, isSimplifiedArrayField as as, isValueBearingField as at, isValueField as au, isWrapperTypeDefinition as av, isWrappersBundle as aw, omit as ax, pageFieldMapper as ay, provideDynamicForm as az, isSameWrapperChain as b, createFieldResolutionPipe as c, derivedFromDeferred as d, createWrapperChainController as e, DfFieldOutlet as f, isEqual as g, createSchemaFromFields as h, injectFieldRegistry as i, createRenderReadySignal as j, ARRAY_TEMPLATE_REGISTRY as k, ARRAY_ITEM_ID_GENERATOR as l, mapFieldToInputs as m, getNormalizedArrayMetadata as n, getFieldValueHandling as o, getFieldDefaultValue as p, isGroupField as q, resolveWrappers as r, createArrayItemIdGenerator as s, ComponentInitializedEvent as t, DynamicTextPipe as u, validatePageNesting as v, dynamicTextToObservable as w, AppendArrayItemEvent as x, ConsoleLogger as y, DEFAULT_PROPS as z };
15717
- //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-BdMxsqmk.mjs.map
15838
+ //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-Ll4W2Z_n.mjs.map