@ng-forge/dynamic-forms 1.2.0-next.4 → 1.2.0-next.6

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 (26) hide show
  1. package/README.md +11 -11
  2. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-BLPWSurR.mjs → ng-forge-dynamic-forms-array-field.component-NTHLPjau.mjs} +2 -2
  3. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-BLPWSurR.mjs.map → ng-forge-dynamic-forms-array-field.component-NTHLPjau.mjs.map} +1 -1
  4. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-jHiY95pr.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CNCeWAeJ.mjs} +2 -2
  5. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-jHiY95pr.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CNCeWAeJ.mjs.map} +1 -1
  6. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs → ng-forge-dynamic-forms-container-field.component-ByGdzAsk.mjs} +5 -4
  7. package/fesm2022/ng-forge-dynamic-forms-container-field.component-ByGdzAsk.mjs.map +1 -0
  8. package/fesm2022/ng-forge-dynamic-forms-field-errors-wrapper.component-ZdaC4Bit.mjs +25 -0
  9. package/fesm2022/ng-forge-dynamic-forms-field-errors-wrapper.component-ZdaC4Bit.mjs.map +1 -0
  10. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs → ng-forge-dynamic-forms-group-field.component-DnLZdj8v.mjs} +2 -2
  11. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs.map → ng-forge-dynamic-forms-group-field.component-DnLZdj8v.mjs.map} +1 -1
  12. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +10 -72
  13. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  14. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +221 -91
  15. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  16. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-B2C_WAMP.mjs} +127 -40
  17. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-B2C_WAMP.mjs.map +1 -0
  18. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs → ng-forge-dynamic-forms-page-field.component-CwH22lRl.mjs} +2 -2
  19. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs.map → ng-forge-dynamic-forms-page-field.component-CwH22lRl.mjs.map} +1 -1
  20. package/fesm2022/ng-forge-dynamic-forms.mjs +2 -2
  21. package/package.json +2 -2
  22. package/types/ng-forge-dynamic-forms-integration.d.ts +7 -31
  23. package/types/ng-forge-dynamic-forms-internal.d.ts +449 -218
  24. package/types/ng-forge-dynamic-forms.d.ts +26 -8
  25. package/fesm2022/ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs.map +0 -1
  26. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { reflectComponentType, Injector, inject, EnvironmentInjector, DestroyRef, computed, signal, input, ViewContainerRef, Directive, InjectionToken, linkedSignal, ChangeDetectionStrategy, Component, Injectable, isSignal, runInInjectionContext, afterNextRender, untracked, PendingTasks, ElementRef, PLATFORM_ID, isDevMode, TemplateRef, model, contentChildren, makeEnvironmentProviders } from '@angular/core';
2
+ import { reflectComponentType, Injector, inject, EnvironmentInjector, DestroyRef, computed, signal, input, ViewContainerRef, Directive, InjectionToken, linkedSignal, untracked, ChangeDetectionStrategy, Component, Injectable, isSignal, runInInjectionContext, afterNextRender, PendingTasks, ElementRef, PLATFORM_ID, isDevMode, TemplateRef, model, contentChildren, makeEnvironmentProviders } from '@angular/core';
3
3
  import { explicitEffect } from 'ngxtension/explicit-effect';
4
4
  import { DynamicFormLogger, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, toReadonlyFieldTreeCached, writeToFieldValue, WRAPPER_AUTO_ASSOCIATIONS, DEFAULT_WRAPPERS, READONLY_FIELD_TREE_CACHE, getGridClassString, EventBus, FieldContextRegistryService, FunctionRegistryService, FORM_OPTIONS, evaluateCondition, FIELD_SIGNAL_CONTEXT, isRowField, isGenericContainerField, isContainerField, isArrayField, hasChildFields, isSimplifiedArrayField, DynamicFormError, isStateLogicConfig, isDerivationLogicConfig, isFormStateCondition, createFormStateLogicFunction, createDebouncedLogicFunction, createLogicFunction, ExpressionParser, applyValidator, isPageField, isGroupField, getFieldValueHandling, normalizeFieldsArray, keyBy, mapValues, isEqual, hasTargetProperty, ARRAY_CONTEXT, GROUP_CONTEXT, FORM_ID_PREFIX, baseFieldMapper, detectFormMode, validatePageNesting, FIELD_REGISTRY, assertNever, ADDON_TYPE_REGISTRY, deepMergeDefaults, derivedFromDeferred, createWarningTracker, RootFormRegistryService, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, EXTERNAL_DATA, DEPRECATION_WARNING_TRACKER, createAddonActionRegistry, ADDON_ACTION_REGISTRY, HttpConditionCache, HTTP_CONDITION_CACHE, HttpConditionFunctionCacheService, AsyncConditionFunctionCacheService, DynamicValueFunctionCacheService, LogicFunctionCacheService, setupInitializationTracking, ComponentInitializedEvent, DF_FIELD_TEMPLATES, rowFieldMapper, groupFieldMapper, arrayFieldMapper, pageFieldMapper, textFieldMapper, containerFieldMapper, isWrapperTypeDefinition, ADDON_TYPE_COMPONENT_CACHE, ADDON_TYPE_DEFINITIONS, createDefaultDerivationLogConfig, NoopLogger, EMIT_FORM_VALUE_ON_EVENTS, DynamicTextPipe, ADDON_ACTION_HANDLERS } from '@ng-forge/dynamic-forms/internal';
5
5
  import { takeUntilDestroyed, toObservable, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
@@ -10,6 +10,8 @@ import { isPlatformBrowser, AsyncPipe, NgTemplateOutlet, NgComponentOutlet } fro
10
10
  import { NG_STATUS_CLASSES } from '@angular/forms/signals/compat';
11
11
 
12
12
  const EMPTY_WRAPPERS = Object.freeze([]);
13
+ const FIELD_ERRORS_WRAPPER = 'field-errors';
14
+ const FIELD_ERRORS_CONFIG = Object.freeze({ type: FIELD_ERRORS_WRAPPER });
13
15
  function isSameWrapperChain(a, b) {
14
16
  if (a === b)
15
17
  return true;
@@ -21,17 +23,26 @@ function isSameWrapperChain(a, b) {
21
23
  }
22
24
  return true;
23
25
  }
24
- function resolveWrappers(field, defaultWrappers, autoAssociations) {
25
- if (field.wrappers === null) {
26
+ function resolveWrappers(field, defaultWrappers, autoAssociations, wrapperRegistry) {
27
+ if (field.wrappers === null) {
26
28
  return EMPTY_WRAPPERS;
27
29
  }
28
30
  const autoWrappers = field.skipAutoWrappers ? EMPTY_WRAPPERS : (autoAssociations.get(field.type) ?? EMPTY_WRAPPERS);
29
31
  const defaults = field.skipDefaultWrappers ? EMPTY_WRAPPERS : (defaultWrappers ?? EMPTY_WRAPPERS);
30
32
  const fieldLevel = field.wrappers ?? EMPTY_WRAPPERS;
31
- if (autoWrappers.length === 0 && defaults.length === 0 && fieldLevel.length === 0) {
32
- return EMPTY_WRAPPERS;
33
+ const composed = [...autoWrappers, ...defaults, ...fieldLevel];
34
+ if (needsErrorWrapper(field, composed, wrapperRegistry)) {
35
+ composed.push(FIELD_ERRORS_CONFIG);
33
36
  }
34
- return [...autoWrappers, ...defaults, ...fieldLevel];
37
+ return composed.length === 0 ? EMPTY_WRAPPERS : composed;
38
+ }
39
+ const VALIDATABLE_CONTAINERS = new Set(['group', 'array']);
40
+ function needsErrorWrapper(field, composed, wrapperRegistry) {
41
+ if (!VALIDATABLE_CONTAINERS.has(field.type))
42
+ return false;
43
+ if (!field.validators || field.validators.length === 0)
44
+ return false;
45
+ return !composed.some((w) => w.type === FIELD_ERRORS_WRAPPER || wrapperRegistry.get(w.type)?.rendersFieldErrors);
35
46
  }
36
47
 
37
48
  const inputNamesCache = new WeakMap();
@@ -246,7 +257,7 @@ function pushFieldInputsOnChange(opts, getRefs) {
246
257
  });
247
258
  }
248
259
 
249
- function buildFieldInputs(rawInputs, cache, fieldType) {
260
+ function buildFieldInputs(rawInputs, cache, fieldType, validationMessages) {
250
261
  const fieldTreeCandidate = rawInputs['field'];
251
262
  const hasFieldTree = fieldTreeCandidate !== undefined && typeof fieldTreeCandidate === 'function';
252
263
  const readonlyField = hasFieldTree ? toReadonlyFieldTreeCached(cache, fieldTreeCandidate) : undefined;
@@ -258,6 +269,7 @@ function buildFieldInputs(rawInputs, cache, fieldType) {
258
269
  type: fieldType,
259
270
  field: readonlyField,
260
271
  setValue,
272
+ ...(validationMessages !== undefined && { validationMessages }),
261
273
  };
262
274
  }
263
275
 
@@ -356,6 +368,7 @@ class DfFieldOutlet {
356
368
  vcr = signal(this.vcrRef).asReadonly();
357
369
  destroyRef = inject(DestroyRef);
358
370
  wrapperAutoAssociations = inject(WRAPPER_AUTO_ASSOCIATIONS);
371
+ wrapperRegistry = inject(WRAPPER_REGISTRY);
359
372
  defaultWrappersSignal = inject(DEFAULT_WRAPPERS, { optional: true });
360
373
  readonlyFieldCache = inject(READONLY_FIELD_TREE_CACHE);
361
374
  fieldComponent = new FieldComponentSlot();
@@ -365,8 +378,8 @@ class DfFieldOutlet {
365
378
  ...(ngDevMode ? [{ debugName: "renderReady" }] : /* istanbul ignore next */ []));
366
379
  rawInputs = computed(() => this.dfFieldOutlet().inputs(), /* @ts-ignore */
367
380
  ...(ngDevMode ? [{ debugName: "rawInputs" }] : /* istanbul ignore next */ []));
368
- wrappers = computed(() => resolveWrappers(this.dfFieldOutlet().fieldDef, this.defaultWrappersSignal?.(), this.wrapperAutoAssociations), { ...(ngDevMode ? { debugName: "wrappers" } : /* istanbul ignore next */ {}), equal: isSameWrapperChain });
369
- fieldInputs = computed(() => buildFieldInputs(this.rawInputs(), this.readonlyFieldCache, this.dfFieldOutlet().fieldDef.type), /* @ts-ignore */
381
+ wrappers = computed(() => resolveWrappers(this.dfFieldOutlet().fieldDef, this.defaultWrappersSignal?.(), this.wrapperAutoAssociations, this.wrapperRegistry), { ...(ngDevMode ? { debugName: "wrappers" } : /* istanbul ignore next */ {}), equal: isSameWrapperChain });
382
+ fieldInputs = computed(() => buildFieldInputs(this.rawInputs(), this.readonlyFieldCache, this.dfFieldOutlet().fieldDef.type, this.dfFieldOutlet().fieldDef.validationMessages), /* @ts-ignore */
370
383
  ...(ngDevMode ? [{ debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
371
384
  defaultEnvInjector = inject(EnvironmentInjector);
372
385
  fieldEnvInjector = computed(() => this.dfFieldOutletEnvironmentInjector() ?? this.defaultEnvInjector, /* @ts-ignore */
@@ -500,9 +513,33 @@ class PageOrchestratorComponent {
500
513
  const totalPages = this.pageFields().length;
501
514
  if (totalPages === 0)
502
515
  return 0;
503
- return 0;
516
+ return untracked(() => this.resolveInitialLanding());
504
517
  }, /* @ts-ignore */
505
518
  ...(ngDevMode ? [{ debugName: "currentPageIndex" }] : /* istanbul ignore next */ []));
519
+ resolveInitialLanding() {
520
+ const { index, validate } = this.initialPage();
521
+ const visible = this.visiblePageIndices();
522
+ if (index === 0 || visible.length === 0)
523
+ return 0;
524
+ const target = visible.includes(index) ? index : this.findNearestVisiblePage(index, visible);
525
+ if (target <= 0)
526
+ return Math.max(target, 0);
527
+ if (!validate)
528
+ return target;
529
+ const firstInvalid = visible.filter((i) => i < target).find((i) => !this.isPageValid(i));
530
+ return firstInvalid ?? target;
531
+ }
532
+ initialPage = computed(() => {
533
+ const raw = this.formOptions?.()?.initialPage;
534
+ const totalPages = this.pageFields().length;
535
+ const requested = typeof raw === 'number' ? raw : raw?.index;
536
+ const validate = typeof raw === 'number' ? false : (raw?.validate ?? false);
537
+ if (typeof requested !== 'number' || !Number.isFinite(requested) || requested < 0 || totalPages === 0) {
538
+ return { index: 0, validate: false };
539
+ }
540
+ return { index: Math.min(Math.trunc(requested), totalPages - 1), validate };
541
+ }, /* @ts-ignore */
542
+ ...(ngDevMode ? [{ debugName: "initialPage" }] : /* istanbul ignore next */ []));
506
543
  state = computed(() => {
507
544
  const currentIndex = this.currentPageIndex();
508
545
  const totalPages = this.pageFields().length;
@@ -553,7 +590,7 @@ class PageOrchestratorComponent {
553
590
  }
554
591
  constructor() {
555
592
  this.setupEventListeners();
556
- explicitEffect([this.state, this.visiblePageIndices], ([state, visibleIndices]) => {
593
+ explicitEffect([this.state, this.visiblePageIndices], ([state, visibleIndices]) => {
557
594
  const currentVisiblePosition = visibleIndices.indexOf(state.currentPageIndex);
558
595
  if (currentVisiblePosition === -1 && visibleIndices.length > 0) {
559
596
  const nearest = this.findNearestVisiblePage(state.currentPageIndex, visibleIndices);
@@ -613,11 +650,14 @@ class PageOrchestratorComponent {
613
650
  const prevVisiblePageIndex = visibleIndices[currentVisiblePosition - 1];
614
651
  return this.executePageChange(prevVisiblePageIndex);
615
652
  }
616
- navigateToPage(pageIndex) {
653
+ navigateToPage(pageIndex, options) {
617
654
  const currentIndex = this.state().currentPageIndex;
618
655
  const visibleIndices = this.visiblePageIndices();
619
656
  if (pageIndex <= currentIndex || !visibleIndices.includes(pageIndex)) {
620
657
  return this.executePageChange(pageIndex);
658
+ }
659
+ if (options?.validate === false) {
660
+ return this.executePageChange(pageIndex);
621
661
  }
622
662
  const disableWhenPageInvalid = this.formOptions?.()?.nextButton?.disableWhenPageInvalid ?? true;
623
663
  if (!disableWhenPageInvalid) {
@@ -696,7 +736,7 @@ class PageOrchestratorComponent {
696
736
  .on('go-to-page')
697
737
  .pipe(takeUntilDestroyed())
698
738
  .subscribe((event) => {
699
- this.navigateToPage(event.pageIndex);
739
+ this.navigateToPage(event.pageIndex, event.options);
700
740
  });
701
741
  explicitEffect([this.state], ([state]) => this.eventBus.dispatch(PagerStateEvent, state));
702
742
  }
@@ -774,10 +814,10 @@ class PageOrchestratorComponent {
774
814
  }
775
815
  }
776
816
  `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [/* @ts-ignore */
777
- import('./ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs').then(m => m.default)]] });
817
+ import('./ng-forge-dynamic-forms-page-field.component-CwH22lRl.mjs').then(m => m.default)]] });
778
818
  }
779
819
  i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.1", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [/* @ts-ignore */
780
- import('./ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
820
+ import('./ng-forge-dynamic-forms-page-field.component-CwH22lRl.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
781
821
  type: Component,
782
822
  args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
783
823
  @for (pageField of pageFields(); track pageField.key; let i = $index) {
@@ -893,7 +933,7 @@ function validateSimplifiedTemplate(field) {
893
933
  }
894
934
  }
895
935
  function expandSimplifiedArray(field) {
896
- const { template, value = [], addButton, removeButton, key, logic, minLength, maxLength, wrappers, skipAutoWrappers, skipDefaultWrappers, } = field;
936
+ const { template, value = [], addButton, removeButton, key, logic, minLength, maxLength, wrappers, skipAutoWrappers, skipDefaultWrappers, validators, validationMessages, required, validateWhenHidden, } = field;
897
937
  const isObjectTemplate = Array.isArray(template);
898
938
  const values = value;
899
939
  validateSimplifiedTemplate(field);
@@ -929,6 +969,18 @@ function expandSimplifiedArray(field) {
929
969
  }
930
970
  if (skipDefaultWrappers !== undefined) {
931
971
  arrayFieldObj['skipDefaultWrappers'] = skipDefaultWrappers;
972
+ }
973
+ if (validators !== undefined) {
974
+ arrayFieldObj['validators'] = validators;
975
+ }
976
+ if (validationMessages !== undefined) {
977
+ arrayFieldObj['validationMessages'] = validationMessages;
978
+ }
979
+ if (required !== undefined) {
980
+ arrayFieldObj['required'] = required;
981
+ }
982
+ if (validateWhenHidden !== undefined) {
983
+ arrayFieldObj['validateWhenHidden'] = validateWhenHidden;
932
984
  }
933
985
  const arrayField = arrayFieldObj;
934
986
  const primitiveFieldKey = !isObjectTemplate ? template.key : undefined;
@@ -1245,6 +1297,11 @@ function resolveDescendantContext(fieldDef, ownContext) {
1245
1297
  let ancestorAlwaysHidden = ownContext.ancestorAlwaysHidden;
1246
1298
  let ancestorHiddenLogics = ownContext.ancestorHiddenLogics;
1247
1299
  let mutated = false;
1300
+ let ancestorRequired = ownContext.ancestorRequired;
1301
+ if (fieldDef.required !== undefined && fieldDef.required !== ancestorRequired) {
1302
+ ancestorRequired = fieldDef.required;
1303
+ mutated = true;
1304
+ }
1248
1305
  if (fieldDef.hidden === true && !ancestorAlwaysHidden) {
1249
1306
  ancestorAlwaysHidden = true;
1250
1307
  mutated = true;
@@ -1276,6 +1333,7 @@ function resolveDescendantContext(fieldDef, ownContext) {
1276
1333
  validateWhenHidden: ownContext.validateWhenHidden,
1277
1334
  ancestorAlwaysHidden,
1278
1335
  ancestorHiddenLogics,
1336
+ ancestorRequired,
1279
1337
  };
1280
1338
  }
1281
1339
 
@@ -1346,6 +1404,7 @@ function mapFieldToForm(fieldDef, fieldPath, inheritedContext = DEFAULT_FIELD_TR
1346
1404
  }
1347
1405
  if (isGroupField(fieldDef)) {
1348
1406
  const descendantContext = resolveDescendantContext(fieldDef, ownContext);
1407
+ applyContainerValidators(fieldDef, fieldPath, descendantContext);
1349
1408
  mapContainerChildren(fieldDef.fields, fieldPath, descendantContext);
1350
1409
  return;
1351
1410
  }
@@ -1395,7 +1454,7 @@ function mapLeafField(fieldDef, fieldPath, context) {
1395
1454
  }
1396
1455
  }
1397
1456
  const applyValidation = (validationPath) => {
1398
- applySimpleValidationRules(validationField, validationPath);
1457
+ applySimpleValidationRules(validationField, validationPath, context);
1399
1458
  if (validationField.validators) {
1400
1459
  for (const config of validationField.validators) {
1401
1460
  applyValidator(config, validationPath);
@@ -1409,8 +1468,11 @@ function mapLeafField(fieldDef, fieldPath, context) {
1409
1468
  }
1410
1469
  }
1411
1470
  };
1471
+ applyHiddenGatedValidation(path, context, applyValidation);
1472
+ }
1473
+ function applyHiddenGatedValidation(path, context, apply) {
1412
1474
  if (context.validateWhenHidden) {
1413
- applyValidation(path);
1475
+ apply(path);
1414
1476
  return;
1415
1477
  }
1416
1478
  if (context.ancestorAlwaysHidden) {
@@ -1423,10 +1485,21 @@ function mapLeafField(fieldDef, fieldPath, context) {
1423
1485
  if (ancestorHiddenLogic && ancestorHiddenLogic(ctx))
1424
1486
  return false;
1425
1487
  return true;
1426
- }, schema((subPath) => applyValidation(subPath)));
1488
+ }, schema((subPath) => apply(subPath)));
1427
1489
  }
1428
- function applySimpleValidationRules(fieldDef, path) {
1429
- if (fieldDef.required) {
1490
+ function applyContainerValidators(fieldDef, fieldPath, context) {
1491
+ const validators = fieldDef.validators;
1492
+ if (!validators || validators.length === 0)
1493
+ return;
1494
+ applyHiddenGatedValidation(fieldPath, context, (validationPath) => {
1495
+ for (const config of validators) {
1496
+ applyValidator(config, validationPath, 'tree');
1497
+ }
1498
+ });
1499
+ }
1500
+ function applySimpleValidationRules(fieldDef, path, context) {
1501
+ const declaresRequiredLogic = fieldDef.logic?.some(isValidationStateLogic) ?? false;
1502
+ if (fieldDef.required ?? (declaresRequiredLogic ? false : context.ancestorRequired)) {
1430
1503
  required(path);
1431
1504
  }
1432
1505
  const stringConfig = getStringValidationConfig(fieldDef);
@@ -1459,6 +1532,7 @@ function mapArrayFieldToForm(arrayField, fieldPath, context) {
1459
1532
  if (arrayField.maxLength !== undefined) {
1460
1533
  maxLength(fieldPath, arrayField.maxLength);
1461
1534
  }
1535
+ applyContainerValidators(arrayField, fieldPath, context);
1462
1536
  let itemDefinitions = arrayField.fields;
1463
1537
  if (!itemDefinitions || itemDefinitions.length === 0) {
1464
1538
  const metadataTemplate = getNormalizedArrayMetadata(arrayField)?.template;
@@ -1504,17 +1578,16 @@ function mapArrayFieldToForm(arrayField, fieldPath, context) {
1504
1578
  mapContainerChildren(templateField.fields, itemPath, layoutDescendant);
1505
1579
  }
1506
1580
  else if (isGroupField(templateField)) {
1507
- const groupKey = templateField.key;
1508
- const groupOwn = resolveFieldOwnContext(templateField, context);
1509
- const groupDescendant = resolveDescendantContext(templateField, groupOwn);
1581
+ const groupKey = templateField.key;
1510
1582
  if (groupKey) {
1511
- const groupPath = pathRecord[groupKey];
1583
+ const groupPath = pathRecord[groupKey];
1512
1584
  if (groupPath) {
1513
- mapContainerChildren(templateField.fields, groupPath, groupDescendant);
1585
+ mapFieldToForm(templateField, groupPath, context);
1514
1586
  }
1515
1587
  }
1516
1588
  else {
1517
- mapContainerChildren(templateField.fields, itemPath, groupDescendant);
1589
+ const groupOwn = resolveFieldOwnContext(templateField, context);
1590
+ mapContainerChildren(templateField.fields, itemPath, resolveDescendantContext(templateField, groupOwn));
1518
1591
  }
1519
1592
  }
1520
1593
  else {
@@ -3791,7 +3864,7 @@ function createDerivationRenderGate() {
3791
3864
  if (!has || engine() !== 'idle')
3792
3865
  return;
3793
3866
  engine.set('loading');
3794
- pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-jHiY95pr.mjs')
3867
+ pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-CNCeWAeJ.mjs')
3795
3868
  .then(({ bootstrapDerivationOrchestrator }) => {
3796
3869
  runInInjectionContext(injector, () => bootstrapDerivationOrchestrator());
3797
3870
  engine.set('wired');
@@ -4346,28 +4419,28 @@ const DISPLAY_FIELD_TYPES_BASE = {
4346
4419
  const BUILT_IN_FIELDS = [
4347
4420
  {
4348
4421
  name: 'row',
4349
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs'),
4422
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-ByGdzAsk.mjs'),
4350
4423
  mapper: rowFieldMapper,
4351
4424
  valueHandling: 'flatten',
4352
4425
  ...CONTAINER_FIELD_TYPES_BASE,
4353
4426
  },
4354
4427
  {
4355
4428
  name: 'group',
4356
- loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs'),
4429
+ loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-DnLZdj8v.mjs'),
4357
4430
  mapper: groupFieldMapper,
4358
4431
  valueHandling: 'include',
4359
4432
  ...CONTAINER_FIELD_TYPES_BASE,
4360
4433
  },
4361
4434
  {
4362
4435
  name: 'array',
4363
- loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-BLPWSurR.mjs'),
4436
+ loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-NTHLPjau.mjs'),
4364
4437
  mapper: arrayFieldMapper,
4365
4438
  valueHandling: 'include',
4366
4439
  ...CONTAINER_FIELD_TYPES_BASE,
4367
4440
  },
4368
4441
  {
4369
4442
  name: 'page',
4370
- loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs'),
4443
+ loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-CwH22lRl.mjs'),
4371
4444
  mapper: pageFieldMapper,
4372
4445
  valueHandling: 'flatten',
4373
4446
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -4385,7 +4458,7 @@ const BUILT_IN_FIELDS = [
4385
4458
  },
4386
4459
  {
4387
4460
  name: 'container',
4388
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs'),
4461
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-ByGdzAsk.mjs'),
4389
4462
  mapper: containerFieldMapper,
4390
4463
  valueHandling: 'flatten',
4391
4464
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -4400,6 +4473,11 @@ const BUILT_IN_WRAPPERS = [
4400
4473
  wrapperName: 'row',
4401
4474
  loadComponent: () => import('./ng-forge-dynamic-forms-row-wrapper.component-BBWmqQA_.mjs'),
4402
4475
  },
4476
+ {
4477
+ wrapperName: 'field-errors',
4478
+ loadComponent: () => import('./ng-forge-dynamic-forms-field-errors-wrapper.component-ZdaC4Bit.mjs'),
4479
+ rendersFieldErrors: true,
4480
+ },
4403
4481
  ];
4404
4482
 
4405
4483
  function isDynamicFormFeature(value) {
@@ -4459,7 +4537,8 @@ function provideDynamicForm(...items) {
4459
4537
  const wrapperBundles = items.filter(isWrappersBundle);
4460
4538
  const features = items.filter(isDynamicFormFeature);
4461
4539
  const fields = [...BUILT_IN_FIELDS, ...fieldTypes];
4462
- const wrappers = [...BUILT_IN_WRAPPERS, ...wrapperTypes, ...wrapperBundles.flatMap((bundle) => bundle.ɵdefinitions)];
4540
+ const customWrappers = [...wrapperTypes, ...wrapperBundles.flatMap((bundle) => bundle.ɵdefinitions)];
4541
+ const wrappers = [...BUILT_IN_WRAPPERS, ...customWrappers];
4463
4542
  const featureProviders = [];
4464
4543
  const hasLoggerFeature = features.some((feature) => feature.ɵkind === 'logger');
4465
4544
  features.forEach((feature) => {
@@ -4500,11 +4579,16 @@ function provideDynamicForm(...items) {
4500
4579
  useFactory: () => {
4501
4580
  const logger = inject(DynamicFormLogger);
4502
4581
  const registry = new Map();
4503
- wrappers.forEach((wrapperType) => {
4504
- if (registry.has(wrapperType.wrapperName)) {
4505
- logger.warn(`Wrapper type "${wrapperType.wrapperName}" is already registered. Overwriting.`);
4582
+ const builtInNames = new Set(BUILT_IN_WRAPPERS.map((w) => w.wrapperName));
4583
+ BUILT_IN_WRAPPERS.forEach((wrapperType) => registry.set(wrapperType.wrapperName, wrapperType));
4584
+ const seenCustom = new Set();
4585
+ customWrappers.forEach((wrapperType) => {
4586
+ const name = wrapperType.wrapperName;
4587
+ if (seenCustom.has(name) && !builtInNames.has(name)) {
4588
+ logger.warn(`Wrapper type "${name}" is already registered. Overwriting.`);
4506
4589
  }
4507
- registry.set(wrapperType.wrapperName, wrapperType);
4590
+ seenCustom.add(name);
4591
+ registry.set(name, wrapperType);
4508
4592
  });
4509
4593
  return registry;
4510
4594
  },
@@ -4789,10 +4873,13 @@ function sanitizeFormConfigPure(config, fieldRegistry, typeRegistry, options = {
4789
4873
 
4790
4874
  class GoToPageEvent {
4791
4875
  pageIndex;
4876
+ options;
4792
4877
  type = 'go-to-page';
4793
4878
  constructor(
4794
- pageIndex) {
4879
+ pageIndex,
4880
+ options) {
4795
4881
  this.pageIndex = pageIndex;
4882
+ this.options = options;
4796
4883
  }
4797
4884
  }
4798
4885
 
@@ -4912,4 +4999,4 @@ function arrayEvent(arrayKey) {
4912
4999
 
4913
5000
 
4914
5001
  export { withEventFormValue as $, ArrayItemRegistryService as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DfFieldOutlet as D, EventDispatcher as E, FIELD_WINDOWING as F, GoToPageEvent as G, PageChangeEvent as H, InsertArrayItemEvent as I, PagerStateEvent as J, PopArrayItemEvent as K, PrependArrayItemEvent as L, MoveArrayItemEvent as M, NextPageEvent as N, PreviousPageEvent as O, PROPERTY_OVERRIDE_STORE as P, TextAddonComponent as Q, RemoveAtIndexEvent as R, ShiftArrayItemEvent as S, TemplateAddonComponent as T, arrayEvent as U, createWrappers as V, isWrappersBundle as W, provideDynamicForm as X, sanitizeFormConfig as Y, withAddonActions as Z, withCustomAddon as _, isSameWrapperChain as a, withFieldWindowing as a0, withLegacyStatusClasses as a1, withLoggerConfig as a2, withPagePreload as a3, withValidationExecutionDefaults as a4, withValueExclusionDefaults as a5, wrapperProps as a6, createWrapperChainController as b, createFieldResolutionPipe as c, createSchemaFromFields as d, createHiddenSignal as e, createRenderReadySignal as f, getNormalizedArrayMetadata as g, getFieldDefaultValue as h, injectFieldRegistry as i, resolveFieldWindowing as j, DEV_MODE as k, DEFAULT_DEBOUNCE_MS as l, mapFieldToInputs as m, DERIVATION_WARNING_TRACKER as n, FormStateManager as o, DERIVATION_LOG_CONFIG as p, AppendArrayItemEvent as q, resolveWrappers as r, ComponentAddonComponent as s, traverseFieldsWithContext as t, ConsoleLogger as u, DfTemplate as v, DynamicForm as w, FormClearEvent as x, FormResetEvent as y, FormSubmitEvent as z };
4915
- //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs.map
5002
+ //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-B2C_WAMP.mjs.map