@ng-forge/dynamic-forms 1.2.0-next.7 → 1.2.0-next.9

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 (23) hide show
  1. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-DK7dAQv7.mjs → ng-forge-dynamic-forms-array-field.component-6yyDriVB.mjs} +2 -2
  2. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-DK7dAQv7.mjs.map → ng-forge-dynamic-forms-array-field.component-6yyDriVB.mjs.map} +1 -1
  3. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BfxYqAQA.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BB8jAcY4.mjs} +2 -2
  4. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BfxYqAQA.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BB8jAcY4.mjs.map} +1 -1
  5. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-Cj2msZp_.mjs → ng-forge-dynamic-forms-container-field.component-DfQ0y-77.mjs} +2 -2
  6. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-Cj2msZp_.mjs.map → ng-forge-dynamic-forms-container-field.component-DfQ0y-77.mjs.map} +1 -1
  7. package/fesm2022/{ng-forge-dynamic-forms-form-schema.service-C3cVSmft.mjs → ng-forge-dynamic-forms-form-schema.service-BzbBv-r0.mjs} +2 -2
  8. package/fesm2022/{ng-forge-dynamic-forms-form-schema.service-C3cVSmft.mjs.map → ng-forge-dynamic-forms-form-schema.service-BzbBv-r0.mjs.map} +1 -1
  9. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DN6X506r.mjs → ng-forge-dynamic-forms-group-field.component-DxHD5I8E.mjs} +3 -3
  10. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DN6X506r.mjs.map → ng-forge-dynamic-forms-group-field.component-DxHD5I8E.mjs.map} +1 -1
  11. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +5 -1
  12. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  13. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-DCX7tvaB.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-tA8ZkP8i.mjs} +464 -163
  14. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-tA8ZkP8i.mjs.map +1 -0
  15. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-D16ey8r-.mjs → ng-forge-dynamic-forms-page-field.component-DCdBvJ-h.mjs} +2 -2
  16. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-D16ey8r-.mjs.map → ng-forge-dynamic-forms-page-field.component-DCdBvJ-h.mjs.map} +1 -1
  17. package/fesm2022/{ng-forge-dynamic-forms-schema-builder-DO-su9sF.mjs → ng-forge-dynamic-forms-schema-builder-IsjNBo0h.mjs} +2 -2
  18. package/fesm2022/{ng-forge-dynamic-forms-schema-builder-DO-su9sF.mjs.map → ng-forge-dynamic-forms-schema-builder-IsjNBo0h.mjs.map} +1 -1
  19. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  20. package/package.json +1 -1
  21. package/types/ng-forge-dynamic-forms-internal.d.ts +16 -2
  22. package/types/ng-forge-dynamic-forms.d.ts +48 -3
  23. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-DCX7tvaB.mjs.map +0 -1
@@ -1,13 +1,132 @@
1
1
  import * as i0 from '@angular/core';
2
- import { reflectComponentType, Injector, inject, EnvironmentInjector, DestroyRef, computed, signal, afterNextRender, input, ViewContainerRef, Directive, InjectionToken, Injectable, isSignal, runInInjectionContext, untracked, linkedSignal, injectAsync, resource, ChangeDetectionStrategy, Component, PendingTasks, ElementRef, PLATFORM_ID, isDevMode, TemplateRef, model, contentChildren, makeEnvironmentProviders } from '@angular/core';
2
+ import { InjectionToken, inject, PLATFORM_ID, DestroyRef, Injectable, reflectComponentType, Injector, EnvironmentInjector, computed, signal, afterNextRender, input, ViewContainerRef, Directive, isSignal, runInInjectionContext, untracked, linkedSignal, injectAsync, resource, ChangeDetectionStrategy, Component, PendingTasks, ElementRef, isDevMode, TemplateRef, model, contentChildren, makeEnvironmentProviders } from '@angular/core';
3
3
  import { explicitEffect } from 'ngxtension/explicit-effect';
4
- import { DynamicFormLogger, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, toReadonlyFieldTreeCached, writeToFieldValue, ComponentInitializedEvent, isPageField, isGroupField, isArrayField, isRowField, isGenericContainerField, hasChildFields, normalizeFieldsArray, WRAPPER_AUTO_ASSOCIATIONS, DEFAULT_WRAPPERS, READONLY_FIELD_TREE_CACHE, EventBus, getGridClassString, GROUP_CONTEXT, isContainerField, isSimplifiedArrayField, DynamicFormError, getFieldValueHandling, keyBy, mapValues, isEqual, isDerivationLogicConfig, hasTargetProperty, ARRAY_CONTEXT, FORM_ID_PREFIX, baseFieldMapper, detectFormMode, validatePageNesting, FIELD_REGISTRY, assertNever, FunctionRegistryService, ADDON_TYPE_REGISTRY, deepMergeDefaults, FIELD_SIGNAL_CONTEXT, derivedFromDeferred, FieldContextRegistryService, FORM_OPTIONS, evaluateCondition, createWarningTracker, RootFormRegistryService, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, EXTERNAL_DATA, DEPRECATION_WARNING_TRACKER, createAddonActionRegistry, ADDON_ACTION_REGISTRY, HttpConditionCache, HTTP_CONDITION_CACHE, HttpConditionFunctionCacheService, AsyncConditionFunctionCacheService, DynamicValueFunctionCacheService, LogicFunctionCacheService, 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';
4
+ import { derivedFrom } from 'ngxtension/derived-from';
5
+ import { of, Observable, distinctUntilChanged, forkJoin, from, catchError, map, switchMap, pipe, isObservable, firstValueFrom, exhaustMap, EMPTY, scan, Subject, concatMap, filter, take, shareReplay } from 'rxjs';
6
+ import { DynamicFormLogger, WRAPPER_COMPONENT_LOAD_CACHE, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, toReadonlyFieldTreeCached, writeToFieldValue, ComponentInitializedEvent, isPageField, isGroupField, isArrayField, isRowField, isGenericContainerField, hasChildFields, normalizeFieldsArray, WRAPPER_AUTO_ASSOCIATIONS, DEFAULT_WRAPPERS, READONLY_FIELD_TREE_CACHE, EventBus, getGridClassString, FORM_OPTIONS, GROUP_CONTEXT, FIELD_REGISTRY, DynamicFormError, isContainerField, isSimplifiedArrayField, getFieldValueHandling, keyBy, mapValues, isEqual, isDerivationLogicConfig, hasTargetProperty, ARRAY_CONTEXT, FORM_ID_PREFIX, baseFieldMapper, detectFormMode, validatePageNesting, assertNever, FunctionRegistryService, ADDON_TYPE_REGISTRY, deepMergeDefaults, FIELD_SIGNAL_CONTEXT, derivedFromDeferred, FieldContextRegistryService, evaluateCondition, createWarningTracker, RootFormRegistryService, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, EXTERNAL_DATA, DEPRECATION_WARNING_TRACKER, createAddonActionRegistry, ADDON_ACTION_REGISTRY, HttpConditionCache, HTTP_CONDITION_CACHE, HttpConditionFunctionCacheService, AsyncConditionFunctionCacheService, DynamicValueFunctionCacheService, LogicFunctionCacheService, 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';
7
+ import { isPlatformBrowser, AsyncPipe, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
5
8
  import { takeUntilDestroyed, toObservable, outputFromObservable } from '@angular/core/rxjs-interop';
6
- import { of, forkJoin, from, catchError, map, switchMap, isObservable, firstValueFrom, exhaustMap, EMPTY, pipe, scan, Observable, Subject, concatMap, filter, take, shareReplay } from 'rxjs';
7
9
  import { submit, form, provideSignalFormsConfig } from '@angular/forms/signals';
8
- import { isPlatformBrowser, AsyncPipe, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
9
10
  import { NG_STATUS_CLASSES } from '@angular/forms/signals/compat';
10
11
 
12
+ const FIELD_WINDOWING = new InjectionToken('FIELD_WINDOWING', {
13
+ providedIn: 'root',
14
+ factory: () => ({ enabled: false, eager: 12, placeholderHeight: '4rem', park: { enabled: false, margin: '100%' } }),
15
+ });
16
+
17
+ function clampWindowSize(value, fallback) {
18
+ if (value === undefined || !Number.isFinite(value))
19
+ return fallback;
20
+ return Math.max(0, Math.floor(value));
21
+ }
22
+
23
+ const DEFAULT_MARGIN = '100%';
24
+ const ROOT_MARGIN_PART = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?(?:px|%)$/i;
25
+ function normalizeFieldParkingMargin(value, fallback = DEFAULT_MARGIN) {
26
+ const normalizedFallback = isValidRootMargin(fallback) ? fallback.trim() : DEFAULT_MARGIN;
27
+ if (!value || !isValidRootMargin(value))
28
+ return normalizedFallback;
29
+ return value.trim().split(/\s+/).join(' ');
30
+ }
31
+ function isValidRootMargin(value) {
32
+ const parts = value.trim().split(/\s+/);
33
+ return parts.length >= 1 && parts.length <= 4 && parts.every((part) => ROOT_MARGIN_PART.test(part));
34
+ }
35
+
36
+ function resolveFieldWindowing(global, perForm) {
37
+ if (perForm === undefined) {
38
+ return global;
39
+ }
40
+ if (typeof perForm === 'boolean') {
41
+ return { ...global, enabled: perForm };
42
+ }
43
+ const configuresMounting = 'eager' in perForm || 'placeholderHeight' in perForm || Object.keys(perForm).length === 0;
44
+ return {
45
+ enabled: configuresMounting ? true : global.enabled,
46
+ eager: clampWindowSize(perForm.eager, global.eager),
47
+ placeholderHeight: perForm.placeholderHeight ?? global.placeholderHeight,
48
+ park: resolveFieldParking(global.park, perForm.park),
49
+ };
50
+ }
51
+ function resolveFieldParking(global, perForm) {
52
+ if (perForm === undefined)
53
+ return global;
54
+ if (typeof perForm === 'boolean')
55
+ return { ...global, enabled: perForm };
56
+ return { enabled: true, margin: normalizeFieldParkingMargin(perForm.margin, global.margin) };
57
+ }
58
+
59
+ const ALWAYS_VISIBLE = of(true);
60
+ class FieldViewportObserver {
61
+ isBrowser = isPlatformBrowser(inject(PLATFORM_ID)) && typeof IntersectionObserver !== 'undefined';
62
+ observers = new Map();
63
+ constructor() {
64
+ inject(DestroyRef).onDestroy(() => {
65
+ for (const { observer } of this.observers.values())
66
+ observer.disconnect();
67
+ this.observers.clear();
68
+ });
69
+ }
70
+ observe(el, rootMargin) {
71
+ if (!this.isBrowser)
72
+ return ALWAYS_VISIBLE;
73
+ rootMargin = normalizeFieldParkingMargin(rootMargin);
74
+ return new Observable((subscriber) => {
75
+ const listener = (visible) => subscriber.next(visible);
76
+ this.startObserving(el, rootMargin, listener);
77
+ subscriber.next(true);
78
+ return () => this.stopObserving(el, rootMargin, listener);
79
+ }).pipe(distinctUntilChanged());
80
+ }
81
+ startObserving(el, rootMargin, listener) {
82
+ const entry = this.observerFor(rootMargin);
83
+ const listeners = entry.listeners.get(el);
84
+ if (listeners) {
85
+ listeners.add(listener);
86
+ return;
87
+ }
88
+ entry.listeners.set(el, new Set([listener]));
89
+ entry.observer.observe(el);
90
+ }
91
+ stopObserving(el, rootMargin, listener) {
92
+ const entry = this.observers.get(rootMargin);
93
+ if (!entry)
94
+ return;
95
+ const listeners = entry.listeners.get(el);
96
+ if (!listeners)
97
+ return;
98
+ listeners.delete(listener);
99
+ if (listeners.size > 0)
100
+ return;
101
+ entry.observer.unobserve(el);
102
+ entry.listeners.delete(el);
103
+ if (entry.listeners.size > 0)
104
+ return;
105
+ entry.observer.disconnect();
106
+ this.observers.delete(rootMargin);
107
+ }
108
+ observerFor(rootMargin) {
109
+ const existing = this.observers.get(rootMargin);
110
+ if (existing)
111
+ return existing;
112
+ const listeners = new Map();
113
+ const observer = new IntersectionObserver((entries) => {
114
+ for (const entry of entries) {
115
+ for (const listener of listeners.get(entry.target) ?? [])
116
+ listener(entry.isIntersecting);
117
+ }
118
+ }, { rootMargin });
119
+ const entry = { observer, listeners };
120
+ this.observers.set(rootMargin, entry);
121
+ return entry;
122
+ }
123
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FieldViewportObserver, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
124
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FieldViewportObserver });
125
+ }
126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: FieldViewportObserver, decorators: [{
127
+ type: Injectable
128
+ }], ctorParameters: () => [] });
129
+
11
130
  const EMPTY_WRAPPERS = Object.freeze([]);
12
131
  const FIELD_ERRORS_WRAPPER = 'field-errors';
13
132
  const FIELD_ERRORS_CONFIG = Object.freeze({ type: FIELD_ERRORS_WRAPPER });
@@ -67,22 +186,29 @@ function hasDefaultExport(value) {
67
186
  function resolveDefaultExport(result) {
68
187
  return hasDefaultExport(result) ? result.default : result;
69
188
  }
70
- async function loadWrapperComponent(type, registry, cache) {
189
+ async function loadWrapperComponent(type, registry, cache, loadCache) {
71
190
  const cached = cache.get(type);
72
191
  if (cached)
73
192
  return cached;
193
+ const pending = loadCache?.get(type);
194
+ if (pending)
195
+ return pending;
74
196
  const definition = registry.get(type);
75
197
  if (!definition)
76
198
  return undefined;
77
- const component = resolveDefaultExport(await definition.loadComponent());
78
- if (component)
79
- cache.set(type, component);
80
- return component;
81
- }
82
- function loadWrapperComponents(configs, registry, cache, logger) {
199
+ const load = (async () => {
200
+ const component = resolveDefaultExport(await definition.loadComponent());
201
+ if (component)
202
+ cache.set(type, component);
203
+ return component;
204
+ })().finally(() => loadCache?.delete(type));
205
+ loadCache?.set(type, load);
206
+ return load;
207
+ }
208
+ function loadWrapperComponents(configs, registry, cache, logger, loadCache) {
83
209
  if (configs.length === 0)
84
210
  return of([]);
85
- return forkJoin(configs.map((config) => from(loadWrapperComponent(config.type, registry, cache)).pipe(catchError(() => of(undefined)), map((component) => {
211
+ return forkJoin(configs.map((config) => from(loadWrapperComponent(config.type, registry, cache, loadCache)).pipe(catchError(() => of(undefined)), map((component) => {
86
212
  if (!component) {
87
213
  if (DEV_MODE) {
88
214
  logger.error(`Wrapper type '${config.type}' could not be loaded. Ensure it is registered via provideDynamicForm().`);
@@ -199,6 +325,7 @@ function injectChainDeps() {
199
325
  return {
200
326
  registry: inject(WRAPPER_REGISTRY),
201
327
  cache: inject(WRAPPER_COMPONENT_CACHE),
328
+ loadCache: inject(WRAPPER_COMPONENT_LOAD_CACHE),
202
329
  logger: inject(DynamicFormLogger),
203
330
  destroyRef: inject(DestroyRef),
204
331
  environmentInjector: inject(EnvironmentInjector),
@@ -222,7 +349,7 @@ function resolveLoadedWrappers(state, deps) {
222
349
  const loaded = state.wrappers.map((config) => ({ config, component: deps.cache.get(config.type) }));
223
350
  return of({ state, loaded });
224
351
  }
225
- return loadWrapperComponents(state.wrappers, deps.registry, deps.cache, deps.logger).pipe(map((loaded) => ({ state, loaded })));
352
+ return loadWrapperComponents(state.wrappers, deps.registry, deps.cache, deps.logger, deps.loadCache).pipe(map((loaded) => ({ state, loaded })));
226
353
  }
227
354
  function applyEmission({ state, loaded }, ctx) {
228
355
  const { opts, deps, mounted, refs } = ctx;
@@ -300,14 +427,19 @@ class FieldComponentSlot {
300
427
  state = signal(EMPTY_STATE, /* @ts-ignore */
301
428
  ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
302
429
  lastInputs = null;
430
+ _parked = signal(false, /* @ts-ignore */
431
+ ...(ngDevMode ? [{ debugName: "_parked" }] : /* istanbul ignore next */ []));
303
432
  phase = () => this.state().phase;
304
433
  snapshot = () => this.state();
434
+ parked = this._parked.asReadonly();
305
435
  mountOrReuse(slot, component, fieldInjector, environmentInjector, rawInputs, fieldInputs) {
306
436
  const current = this.state();
307
437
  if (current.phase !== 'empty' && current.ref.componentType === component) {
308
438
  slot.insert(current.ref.hostView);
309
439
  this.lastInputs = null;
310
440
  this.state.set(Object.freeze({ phase: 'mounted', ref: current.ref, slot }));
441
+ if (this._parked())
442
+ current.ref.changeDetectorRef.detach();
311
443
  this.pushInputs(rawInputs, fieldInputs);
312
444
  if (current.phase === 'detached')
313
445
  this.replayFocus(current.focusSnapshot);
@@ -316,6 +448,7 @@ class FieldComponentSlot {
316
448
  if (current.phase !== 'empty')
317
449
  current.ref.destroy();
318
450
  this.lastInputs = null;
451
+ this._parked.set(false);
319
452
  this.state.set(EMPTY_STATE);
320
453
  const ref = slot.createComponent(component, {
321
454
  environmentInjector,
@@ -352,12 +485,34 @@ class FieldComponentSlot {
352
485
  this.lastInputs = null;
353
486
  this.state.set(Object.freeze({ phase: 'detached', ref: current.ref, focusSnapshot }));
354
487
  return idx < 0;
488
+ }
489
+ park() {
490
+ const current = this.state();
491
+ if (current.phase === 'empty' || this._parked())
492
+ return;
493
+ current.ref.changeDetectorRef.detach();
494
+ this._parked.set(true);
495
+ }
496
+ refresh() {
497
+ const current = this.state();
498
+ if (current.phase === 'empty' || !this._parked())
499
+ return;
500
+ current.ref.changeDetectorRef.detectChanges();
501
+ }
502
+ unpark() {
503
+ const current = this.state();
504
+ if (current.phase === 'empty' || !this._parked())
505
+ return;
506
+ current.ref.changeDetectorRef.reattach();
507
+ current.ref.changeDetectorRef.markForCheck();
508
+ this._parked.set(false);
355
509
  }
356
510
  destroyOnTeardown() {
357
511
  const current = this.state();
358
512
  if (current.phase === 'detached')
359
513
  current.ref.destroy();
360
514
  this.lastInputs = null;
515
+ this._parked.set(false);
361
516
  this.state.set(EMPTY_STATE);
362
517
  }
363
518
  captureFocus(ref) {
@@ -450,6 +605,32 @@ function setupContainerInitEffect(resolvedFields, eventBus, componentType, field
450
605
  });
451
606
  }
452
607
 
608
+ const EMPTY_ERRORS = Object.freeze([]);
609
+ function snapshotParkedDomState(fieldTree) {
610
+ const state = fieldTree?.();
611
+ if (!state)
612
+ return null;
613
+ return {
614
+ disabled: state.disabled?.() ?? false,
615
+ readonly: state.readonly?.() ?? false,
616
+ required: state.required?.() ?? false,
617
+ touched: state.touched?.() ?? false,
618
+ dirty: state.dirty?.() ?? false,
619
+ errors: state.errors?.() ?? EMPTY_ERRORS,
620
+ };
621
+ }
622
+ function isSameParkedDomState(a, b) {
623
+ return (a === b ||
624
+ (a !== null &&
625
+ b !== null &&
626
+ a.disabled === b.disabled &&
627
+ a.readonly === b.readonly &&
628
+ a.required === b.required &&
629
+ a.touched === b.touched &&
630
+ a.dirty === b.dirty &&
631
+ a.errors === b.errors));
632
+ }
633
+
453
634
  class DfFieldOutlet {
454
635
  dfFieldOutlet = input.required(/* @ts-ignore */
455
636
  ...(ngDevMode ? [{ debugName: "dfFieldOutlet" }] : /* istanbul ignore next */ []));
@@ -464,7 +645,7 @@ class DfFieldOutlet {
464
645
  readonlyFieldCache = inject(READONLY_FIELD_TREE_CACHE);
465
646
  eventBus = inject(EventBus, { optional: true });
466
647
  injector = inject(Injector);
467
- fieldComponent = new FieldComponentSlot();
648
+ fieldComponent = new FieldComponentSlot();
468
649
  componentIdentity = computed(() => this.dfFieldOutlet().component, /* @ts-ignore */
469
650
  ...(ngDevMode ? [{ debugName: "componentIdentity" }] : /* istanbul ignore next */ []));
470
651
  renderReady = computed(() => this.dfFieldOutlet().renderReady() && !this.dfFieldOutlet().hidden(), /* @ts-ignore */
@@ -477,12 +658,35 @@ class DfFieldOutlet {
477
658
  fieldInputs = computed(() => buildFieldInputs(this.rawInputs(), this.readonlyFieldCache, this.dfFieldOutlet().fieldDef.type, this.dfFieldOutlet().fieldDef.validationMessages), /* @ts-ignore */
478
659
  ...(ngDevMode ? [{ debugName: "fieldInputs" }] : /* istanbul ignore next */ []));
479
660
  defaultEnvInjector = inject(EnvironmentInjector);
480
- fieldEnvInjector = computed(() => this.dfFieldOutletEnvironmentInjector() ?? this.defaultEnvInjector, /* @ts-ignore */
661
+ fieldEnvInjector = computed(() => this.dfFieldOutletEnvironmentInjector() ?? this.defaultEnvInjector, /* @ts-ignore */
481
662
  ...(ngDevMode ? [{ debugName: "fieldEnvInjector" }] : /* istanbul ignore next */ []));
482
- fieldInjector = computed(() => this.dfFieldOutlet().injector, /* @ts-ignore */
663
+ fieldInjector = computed(() => this.dfFieldOutlet().injector, /* @ts-ignore */
483
664
  ...(ngDevMode ? [{ debugName: "fieldInjector" }] : /* istanbul ignore next */ []));
484
665
  outermostHostClasses = computed(() => getGridClassString(this.dfFieldOutlet().fieldDef) || undefined, /* @ts-ignore */
485
666
  ...(ngDevMode ? [{ debugName: "outermostHostClasses" }] : /* istanbul ignore next */ []));
667
+ formOptions = inject(FORM_OPTIONS, { optional: true });
668
+ globalFieldWindowing = inject(FIELD_WINDOWING);
669
+ viewportObserver = inject(FieldViewportObserver, { optional: true });
670
+ parking = computed(() => resolveFieldWindowing(this.globalFieldWindowing, this.formOptions?.()?.fieldWindowing).park, /* @ts-ignore */
671
+ ...(ngDevMode ? [{ debugName: "parking" }] : /* istanbul ignore next */ []));
672
+ observedElement = computed(() => {
673
+ const state = this.fieldComponent.snapshot();
674
+ return state.phase === 'empty' ? null : state.ref.location.nativeElement;
675
+ }, /* @ts-ignore */
676
+ ...(ngDevMode ? [{ debugName: "observedElement" }] : /* istanbul ignore next */ []));
677
+ visibility = derivedFrom([this.observedElement, this.parking], pipe(switchMap(([element, parking]) => {
678
+ const observer = this.viewportObserver;
679
+ return parking.enabled && element && observer ? observer.observe(element, parking.margin) : of(true);
680
+ })), { initialValue: true });
681
+ focusEpoch = signal(0, /* @ts-ignore */
682
+ ...(ngDevMode ? [{ debugName: "focusEpoch" }] : /* istanbul ignore next */ []));
683
+ parked = computed(() => this.parking().enabled && !this.visibility(), /* @ts-ignore */
684
+ ...(ngDevMode ? [{ debugName: "parked" }] : /* istanbul ignore next */ []));
685
+ fieldTree = computed(() => {
686
+ const candidate = this.rawInputs()['field'];
687
+ return typeof candidate === 'function' ? candidate : undefined;
688
+ }, { ...(ngDevMode ? { debugName: "fieldTree" } : /* istanbul ignore next */ {}), equal: Object.is });
689
+ parkedDomState = computed(() => (this.parked() ? snapshotParkedDomState(this.fieldTree()) : null), { ...(ngDevMode ? { debugName: "parkedDomState" } : /* istanbul ignore next */ {}), equal: isSameParkedDomState });
486
690
  constructor() {
487
691
  createWrapperChainController({
488
692
  vcr: this.vcr,
@@ -498,8 +702,8 @@ class DfFieldOutlet {
498
702
  this.fieldComponent.mountOrReuse(slot, resolved.component, resolved.injector, this.fieldEnvInjector(), this.rawInputs(), this.fieldInputs());
499
703
  },
500
704
  });
501
- explicitEffect([this.rawInputs, this.fieldInputs], ([rawInputs, fieldInputs]) => this.fieldComponent.pushInputs(rawInputs, fieldInputs));
502
- explicitEffect([this.hidden], ([hidden]) => {
705
+ explicitEffect([this.rawInputs, this.fieldInputs], ([rawInputs, fieldInputs]) => this.fieldComponent.pushInputs(rawInputs, fieldInputs));
706
+ explicitEffect([this.hidden], ([hidden]) => {
503
707
  if (!hidden || !this.eventBus)
504
708
  return;
505
709
  const resolved = this.dfFieldOutlet();
@@ -507,8 +711,41 @@ class DfFieldOutlet {
507
711
  for (const { type, path } of collectInitializingContainers([resolved.fieldDef], groupContext?.groupPath())) {
508
712
  emitComponentInitialized(this.eventBus, type, path, this.injector);
509
713
  }
714
+ });
715
+ explicitEffect([this.observedElement, this.parking], ([element, parking], onCleanup) => {
716
+ if (!parking.enabled || !element)
717
+ return;
718
+ const bumpEpoch = () => queueMicrotask(() => {
719
+ if (!this.destroyRef.destroyed)
720
+ this.focusEpoch.update((n) => n + 1);
721
+ });
722
+ element.addEventListener('focusin', bumpEpoch);
723
+ element.addEventListener('focusout', bumpEpoch);
724
+ onCleanup(() => {
725
+ element.removeEventListener('focusin', bumpEpoch);
726
+ element.removeEventListener('focusout', bumpEpoch);
727
+ });
728
+ });
729
+ explicitEffect([this.parked, this.focusEpoch, this.parkedDomState], ([parked, , domState]) => {
730
+ if (parked && this.canPark(domState)) {
731
+ const alreadyParked = this.fieldComponent.parked();
732
+ this.fieldComponent.park();
733
+ if (alreadyParked)
734
+ this.fieldComponent.refresh();
735
+ }
736
+ else {
737
+ this.fieldComponent.unpark();
738
+ }
510
739
  });
511
740
  this.destroyRef.onDestroy(() => this.fieldComponent.destroyOnTeardown());
741
+ }
742
+ canPark(domState) {
743
+ const element = this.observedElement();
744
+ if (!element)
745
+ return false;
746
+ if (element.contains(document.activeElement))
747
+ return false;
748
+ return (domState?.errors.length ?? 0) === 0;
512
749
  }
513
750
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: DfFieldOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
514
751
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: DfFieldOutlet, isStandalone: true, selector: "[dfFieldOutlet]", inputs: { dfFieldOutlet: { classPropertyName: "dfFieldOutlet", publicName: "dfFieldOutlet", isSignal: true, isRequired: true, transformFunction: null }, dfFieldOutletEnvironmentInjector: { classPropertyName: "dfFieldOutletEnvironmentInjector", publicName: "dfFieldOutletEnvironmentInjector", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
@@ -554,51 +791,77 @@ class FormSubmitEvent {
554
791
  type = 'submit';
555
792
  }
556
793
 
557
- class PageChangeEvent {
558
- currentPageIndex;
559
- totalPages;
560
- previousPageIndex;
561
- type = 'page-change';
562
- constructor(
563
- currentPageIndex,
564
- totalPages,
565
- previousPageIndex) {
566
- this.currentPageIndex = currentPageIndex;
567
- this.totalPages = totalPages;
568
- this.previousPageIndex = previousPageIndex;
569
- }
570
- }
571
-
572
- class PagerStateEvent {
573
- state;
574
- type = 'pager-state';
575
- constructor(state) {
576
- this.state = state;
577
- }
578
- }
579
-
580
- const PAGE_PRELOAD_WINDOW = new InjectionToken('PAGE_PRELOAD_WINDOW', {
794
+ const COMPONENT_CACHE = new InjectionToken('COMPONENT_CACHE', {
581
795
  providedIn: 'root',
582
- factory: () => 1,
796
+ factory: () => new Map(),
583
797
  });
584
-
585
- function clampWindowSize(value, fallback) {
586
- if (value === undefined || !Number.isFinite(value))
587
- return fallback;
588
- return Math.max(0, Math.floor(value));
589
- }
590
-
591
- function collectLeafFieldKeys(fields) {
592
- const keys = [];
593
- for (const field of fields) {
594
- if (isRowField(field) || isGenericContainerField(field)) {
595
- keys.push(...collectLeafFieldKeys(field.fields));
596
- }
597
- else if (field.key) {
598
- keys.push(field.key);
599
- }
600
- }
601
- return keys;
798
+ const COMPONENT_LOAD_CACHE = new InjectionToken('COMPONENT_LOAD_CACHE', {
799
+ providedIn: 'root',
800
+ factory: () => new Map(),
801
+ });
802
+ function injectFieldRegistry() {
803
+ const registry = inject(FIELD_REGISTRY);
804
+ const componentCache = inject(COMPONENT_CACHE);
805
+ const componentLoadCache = inject(COMPONENT_LOAD_CACHE);
806
+ return {
807
+ getType(name) {
808
+ return registry.get(name);
809
+ },
810
+ hasType(name) {
811
+ return registry.has(name);
812
+ },
813
+ async loadTypeComponent(name) {
814
+ const fieldType = registry.get(name);
815
+ if (!fieldType) {
816
+ throw new DynamicFormError(`Field type "${name}" is not registered`);
817
+ }
818
+ if (!fieldType.loadComponent) {
819
+ return undefined;
820
+ }
821
+ const cached = componentCache.get(name);
822
+ if (cached) {
823
+ return cached;
824
+ }
825
+ const pending = componentLoadCache.get(name);
826
+ if (pending) {
827
+ return pending;
828
+ }
829
+ try {
830
+ const load = fieldType
831
+ .loadComponent()
832
+ .then(resolveDefaultExport)
833
+ .then((component) => {
834
+ if (component) {
835
+ componentCache.set(name, component);
836
+ }
837
+ return component;
838
+ })
839
+ .catch((error) => {
840
+ throw new DynamicFormError(`Failed to load component for field type "${name}": ${error}`);
841
+ })
842
+ .finally(() => componentLoadCache.delete(name));
843
+ componentLoadCache.set(name, load);
844
+ return load;
845
+ }
846
+ catch (error) {
847
+ throw new DynamicFormError(`Failed to load component for field type "${name}": ${error}`);
848
+ }
849
+ },
850
+ getLoadedComponent(name) {
851
+ return componentCache.get(name);
852
+ },
853
+ getTypes() {
854
+ return Array.from(registry.values());
855
+ },
856
+ registerTypes(types) {
857
+ types.forEach((type) => {
858
+ registry.set(type.name, type);
859
+ });
860
+ },
861
+ get raw() {
862
+ return registry;
863
+ },
864
+ };
602
865
  }
603
866
 
604
867
  const NORMALIZED_ARRAY_METADATA = Symbol('normalizedArrayMetadata');
@@ -748,6 +1011,128 @@ function buildRemoveButton(config) {
748
1011
  };
749
1012
  }
750
1013
 
1014
+ function collectFieldDefs(fields, out = []) {
1015
+ for (const field of fields ?? []) {
1016
+ out.push(field);
1017
+ const children = field.fields;
1018
+ if (Array.isArray(children)) {
1019
+ for (const child of children) {
1020
+ if (Array.isArray(child))
1021
+ collectFieldDefs(child, out);
1022
+ else
1023
+ collectFieldDefs([child], out);
1024
+ }
1025
+ }
1026
+ const metadata = getNormalizedArrayMetadata(field);
1027
+ const template = metadata?.template;
1028
+ if (Array.isArray(template))
1029
+ collectFieldDefs(template, out);
1030
+ else if (template)
1031
+ collectFieldDefs([template], out);
1032
+ if (metadata?.autoRemoveButton)
1033
+ collectFieldDefs([metadata.autoRemoveButton], out);
1034
+ }
1035
+ return out;
1036
+ }
1037
+ function injectFormComponentPreloader() {
1038
+ const fieldRegistry = injectFieldRegistry();
1039
+ const wrapperRegistry = inject(WRAPPER_REGISTRY);
1040
+ const wrapperCache = inject(WRAPPER_COMPONENT_CACHE);
1041
+ const wrapperLoadCache = inject(WRAPPER_COMPONENT_LOAD_CACHE);
1042
+ const autoAssociations = inject(WRAPPER_AUTO_ASSOCIATIONS);
1043
+ const defaultWrappers = inject(DEFAULT_WRAPPERS, { optional: true });
1044
+ const preloadedConfigs = new WeakSet();
1045
+ const preloadedFieldRoots = new WeakSet();
1046
+ const preloadFields = (fields) => {
1047
+ const unseenFields = fields.filter((field) => {
1048
+ if (preloadedFieldRoots.has(field))
1049
+ return false;
1050
+ preloadedFieldRoots.add(field);
1051
+ return true;
1052
+ });
1053
+ if (unseenFields.length === 0)
1054
+ return;
1055
+ const normalizedFields = normalizeSimplifiedArrays(unseenFields);
1056
+ const defs = collectFieldDefs(normalizedFields);
1057
+ if (defs.length === 0)
1058
+ return;
1059
+ const fieldTypes = new Set();
1060
+ const wrapperTypes = new Set();
1061
+ for (const def of defs) {
1062
+ if (def.type)
1063
+ fieldTypes.add(def.type);
1064
+ for (const wrapper of resolveWrappers(def, defaultWrappers?.(), autoAssociations, wrapperRegistry)) {
1065
+ wrapperTypes.add(wrapper.type);
1066
+ }
1067
+ }
1068
+ const started = [];
1069
+ for (const type of fieldTypes) {
1070
+ if (fieldRegistry.getLoadedComponent(type))
1071
+ continue;
1072
+ started.push(Promise.resolve(fieldRegistry.loadTypeComponent(type)).catch(() => undefined));
1073
+ }
1074
+ for (const type of wrapperTypes) {
1075
+ if (wrapperCache.has(type))
1076
+ continue;
1077
+ started.push(loadWrapperComponent(type, wrapperRegistry, wrapperCache, wrapperLoadCache).catch(() => undefined));
1078
+ }
1079
+ void Promise.allSettled(started);
1080
+ };
1081
+ return {
1082
+ preloadConfig: (config) => {
1083
+ if (preloadedConfigs.has(config))
1084
+ return;
1085
+ preloadedConfigs.add(config);
1086
+ const fields = config.fields;
1087
+ if (fields.length > 0 && fields.every(isPageField))
1088
+ return;
1089
+ preloadFields(fields);
1090
+ },
1091
+ preloadFields,
1092
+ };
1093
+ }
1094
+
1095
+ class PageChangeEvent {
1096
+ currentPageIndex;
1097
+ totalPages;
1098
+ previousPageIndex;
1099
+ type = 'page-change';
1100
+ constructor(
1101
+ currentPageIndex,
1102
+ totalPages,
1103
+ previousPageIndex) {
1104
+ this.currentPageIndex = currentPageIndex;
1105
+ this.totalPages = totalPages;
1106
+ this.previousPageIndex = previousPageIndex;
1107
+ }
1108
+ }
1109
+
1110
+ class PagerStateEvent {
1111
+ state;
1112
+ type = 'pager-state';
1113
+ constructor(state) {
1114
+ this.state = state;
1115
+ }
1116
+ }
1117
+
1118
+ const PAGE_PRELOAD_WINDOW = new InjectionToken('PAGE_PRELOAD_WINDOW', {
1119
+ providedIn: 'root',
1120
+ factory: () => 1,
1121
+ });
1122
+
1123
+ function collectLeafFieldKeys(fields) {
1124
+ const keys = [];
1125
+ for (const field of fields) {
1126
+ if (isRowField(field) || isGenericContainerField(field)) {
1127
+ keys.push(...collectLeafFieldKeys(field.fields));
1128
+ }
1129
+ else if (field.key) {
1130
+ keys.push(field.key);
1131
+ }
1132
+ }
1133
+ return keys;
1134
+ }
1135
+
751
1136
  function createSlot() {
752
1137
  let counter = 0;
753
1138
  const templates = new Map();
@@ -1458,79 +1843,6 @@ function isValidFormConfiguration(fields) {
1458
1843
  return FormModeValidator.validateFormConfiguration(fields).isValid;
1459
1844
  }
1460
1845
 
1461
- const COMPONENT_CACHE = new InjectionToken('COMPONENT_CACHE', {
1462
- providedIn: 'root',
1463
- factory: () => new Map(),
1464
- });
1465
- const COMPONENT_LOAD_CACHE = new InjectionToken('COMPONENT_LOAD_CACHE', {
1466
- providedIn: 'root',
1467
- factory: () => new Map(),
1468
- });
1469
- function injectFieldRegistry() {
1470
- const registry = inject(FIELD_REGISTRY);
1471
- const componentCache = inject(COMPONENT_CACHE);
1472
- const componentLoadCache = inject(COMPONENT_LOAD_CACHE);
1473
- return {
1474
- getType(name) {
1475
- return registry.get(name);
1476
- },
1477
- hasType(name) {
1478
- return registry.has(name);
1479
- },
1480
- async loadTypeComponent(name) {
1481
- const fieldType = registry.get(name);
1482
- if (!fieldType) {
1483
- throw new DynamicFormError(`Field type "${name}" is not registered`);
1484
- }
1485
- if (!fieldType.loadComponent) {
1486
- return undefined;
1487
- }
1488
- const cached = componentCache.get(name);
1489
- if (cached) {
1490
- return cached;
1491
- }
1492
- const pending = componentLoadCache.get(name);
1493
- if (pending) {
1494
- return pending;
1495
- }
1496
- try {
1497
- const load = fieldType
1498
- .loadComponent()
1499
- .then(resolveDefaultExport)
1500
- .then((component) => {
1501
- if (component) {
1502
- componentCache.set(name, component);
1503
- }
1504
- return component;
1505
- })
1506
- .catch((error) => {
1507
- throw new DynamicFormError(`Failed to load component for field type "${name}": ${error}`);
1508
- })
1509
- .finally(() => componentLoadCache.delete(name));
1510
- componentLoadCache.set(name, load);
1511
- return load;
1512
- }
1513
- catch (error) {
1514
- throw new DynamicFormError(`Failed to load component for field type "${name}": ${error}`);
1515
- }
1516
- },
1517
- getLoadedComponent(name) {
1518
- return componentCache.get(name);
1519
- },
1520
- getTypes() {
1521
- return Array.from(registry.values());
1522
- },
1523
- registerTypes(types) {
1524
- types.forEach((type) => {
1525
- registry.set(type.name, type);
1526
- });
1527
- },
1528
- get raw() {
1529
- return registry;
1530
- },
1531
- };
1532
- }
1533
-
1534
1846
  function collectFieldData(fields, data, registry, pathPrefix, collectKeys = true) {
1535
1847
  for (const field of fields) {
1536
1848
  const valueHandling = field.type ? getFieldValueHandling(field.type, registry) : 'include';
@@ -2623,7 +2935,7 @@ class FormStateManager {
2623
2935
  debugName: 'FormStateManager.entity',
2624
2936
  equal: isEqual,
2625
2937
  });
2626
- loadFormSchemaService = injectAsync(() => import('./ng-forge-dynamic-forms-form-schema.service-C3cVSmft.mjs'));
2938
+ loadFormSchemaService = injectAsync(() => import('./ng-forge-dynamic-forms-form-schema.service-BzbBv-r0.mjs'));
2627
2939
  formSchemaRequest = computed(() => {
2628
2940
  const setup = this.formSetup();
2629
2941
  const config = this.activeConfig();
@@ -3252,6 +3564,10 @@ class PageOrchestratorComponent {
3252
3564
  ...(ngDevMode ? [{ debugName: "pageRenderStates" }] : /* istanbul ignore next */ []));
3253
3565
  constructor() {
3254
3566
  this.setupEventListeners();
3567
+ const preloader = injectFormComponentPreloader();
3568
+ explicitEffect([this.pageRenderStates], ([states]) => {
3569
+ preloader.preloadFields(states.filter((page) => !page.hidden && (page.active || page.preload)).map((page) => page.field));
3570
+ });
3255
3571
  explicitEffect([this.schemaCurrent, this.pageFields], ([schemaCurrent]) => {
3256
3572
  const ownership = this.activePageOwnership();
3257
3573
  if (!schemaCurrent || ownership.initialized)
@@ -3467,10 +3783,10 @@ class PageOrchestratorComponent {
3467
3783
  }
3468
3784
  }
3469
3785
  `, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [/* @ts-ignore */
3470
- import('./ng-forge-dynamic-forms-page-field.component-D16ey8r-.mjs').then(m => m.default)]] });
3786
+ import('./ng-forge-dynamic-forms-page-field.component-DCdBvJ-h.mjs').then(m => m.default)]] });
3471
3787
  }
3472
3788
  i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.1", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [/* @ts-ignore */
3473
- import('./ng-forge-dynamic-forms-page-field.component-D16ey8r-.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
3789
+ import('./ng-forge-dynamic-forms-page-field.component-DCdBvJ-h.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
3474
3790
  type: Component,
3475
3791
  args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
3476
3792
  @for (page of pageRenderStates(); track page.field.key) {
@@ -3589,7 +3905,7 @@ function createDerivationRenderGate() {
3589
3905
  if (!has || engine() !== 'idle')
3590
3906
  return;
3591
3907
  engine.set('loading');
3592
- pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BfxYqAQA.mjs')
3908
+ pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BB8jAcY4.mjs')
3593
3909
  .then(({ bootstrapDerivationOrchestrator }) => {
3594
3910
  runInInjectionContext(injector, () => bootstrapDerivationOrchestrator());
3595
3911
  engine.set('wired');
@@ -3749,6 +4065,7 @@ function coreProviders() {
3749
4065
  deps: [FormStateManager],
3750
4066
  },
3751
4067
  FormIdPrefixService,
4068
+ FieldViewportObserver,
3752
4069
  {
3753
4070
  provide: FORM_ID_PREFIX,
3754
4071
  useFactory: (svc) => svc.prefix,
@@ -3837,25 +4154,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
3837
4154
  type: Injectable
3838
4155
  }] });
3839
4156
 
3840
- const FIELD_WINDOWING = new InjectionToken('FIELD_WINDOWING', {
3841
- providedIn: 'root',
3842
- factory: () => ({ enabled: false, eager: 12, placeholderHeight: '4rem' }),
3843
- });
3844
-
3845
- function resolveFieldWindowing(global, perForm) {
3846
- if (perForm === undefined) {
3847
- return global;
3848
- }
3849
- if (typeof perForm === 'boolean') {
3850
- return { ...global, enabled: perForm };
3851
- }
3852
- return {
3853
- enabled: true,
3854
- eager: clampWindowSize(perForm.eager, global.eager),
3855
- placeholderHeight: perForm.placeholderHeight ?? global.placeholderHeight,
3856
- };
3857
- }
3858
-
3859
4157
  class DynamicForm {
3860
4158
  config = input.required({ ...(ngDevMode ? { debugName: "config" } : /* istanbul ignore next */ {}), alias: 'dynamic-form' });
3861
4159
  formOptions = input(undefined, /* @ts-ignore */
@@ -3951,6 +4249,8 @@ class DynamicForm {
3951
4249
  this.dispatcher?.connect(this.eventBus);
3952
4250
  this.destroyRef.onDestroy(() => this.dispatcher?.disconnect());
3953
4251
  inject(FORM_INITIALIZER, { optional: true });
4252
+ const preload = injectFormComponentPreloader();
4253
+ explicitEffect([this.config], ([config]) => preload.preloadConfig(config));
3954
4254
  this.setupEffects();
3955
4255
  this.setupEventHandlers();
3956
4256
  }
@@ -4144,28 +4444,28 @@ const DISPLAY_FIELD_TYPES_BASE = {
4144
4444
  const BUILT_IN_FIELDS = [
4145
4445
  {
4146
4446
  name: 'row',
4147
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-Cj2msZp_.mjs'),
4447
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-DfQ0y-77.mjs'),
4148
4448
  mapper: rowFieldMapper,
4149
4449
  valueHandling: 'flatten',
4150
4450
  ...CONTAINER_FIELD_TYPES_BASE,
4151
4451
  },
4152
4452
  {
4153
4453
  name: 'group',
4154
- loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-DN6X506r.mjs'),
4454
+ loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-DxHD5I8E.mjs'),
4155
4455
  mapper: groupFieldMapper,
4156
4456
  valueHandling: 'include',
4157
4457
  ...CONTAINER_FIELD_TYPES_BASE,
4158
4458
  },
4159
4459
  {
4160
4460
  name: 'array',
4161
- loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-DK7dAQv7.mjs'),
4461
+ loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-6yyDriVB.mjs'),
4162
4462
  mapper: arrayFieldMapper,
4163
4463
  valueHandling: 'include',
4164
4464
  ...CONTAINER_FIELD_TYPES_BASE,
4165
4465
  },
4166
4466
  {
4167
4467
  name: 'page',
4168
- loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-D16ey8r-.mjs'),
4468
+ loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-DCdBvJ-h.mjs'),
4169
4469
  mapper: pageFieldMapper,
4170
4470
  valueHandling: 'flatten',
4171
4471
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -4183,7 +4483,7 @@ const BUILT_IN_FIELDS = [
4183
4483
  },
4184
4484
  {
4185
4485
  name: 'container',
4186
- loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-Cj2msZp_.mjs'),
4486
+ loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-DfQ0y-77.mjs'),
4187
4487
  mapper: containerFieldMapper,
4188
4488
  valueHandling: 'flatten',
4189
4489
  ...CONTAINER_FIELD_TYPES_BASE,
@@ -4404,6 +4704,7 @@ function withFieldWindowing(config) {
4404
4704
  enabled: true,
4405
4705
  eager: clampWindowSize(config?.eager, 12),
4406
4706
  placeholderHeight: config?.placeholderHeight ?? '4rem',
4707
+ park: resolveFieldParking({ enabled: true, margin: '100%' }, config?.park),
4407
4708
  };
4408
4709
  return createFeature('field-windowing', [{ provide: FIELD_WINDOWING, useValue: resolved }]);
4409
4710
  }
@@ -4743,4 +5044,4 @@ function arrayEvent(arrayKey) {
4743
5044
 
4744
5045
 
4745
5046
  export { arrayEvent as $, ArrayItemRegistryService as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DfFieldOutlet as D, DfTemplate as E, FIELD_WINDOWING as F, DynamicForm as G, EventDispatcher as H, FormClearEvent as I, FormResetEvent as J, FormSubmitEvent as K, GoToPageEvent as L, InsertArrayItemEvent as M, MoveArrayItemEvent as N, NextPageEvent as O, PROPERTY_OVERRIDE_STORE as P, PageChangeEvent as Q, PagerStateEvent as R, SchemaRegistryService as S, PopArrayItemEvent as T, PrependArrayItemEvent as U, VALIDATION_EXECUTION_DEFAULTS as V, PreviousPageEvent as W, RemoveAtIndexEvent as X, ShiftArrayItemEvent as Y, TemplateAddonComponent as Z, TextAddonComponent as _, createFieldResolutionPipe as a, createWrappers as a0, isWrappersBundle as a1, provideDynamicForm as a2, sanitizeFormConfig as a3, withAddonActions as a4, withCustomAddon as a5, withEventFormValue as a6, withFieldWindowing as a7, withLegacyStatusClasses as a8, withLoggerConfig as a9, withPagePreload as aa, withValidationExecutionDefaults as ab, withValueExclusionDefaults as ac, wrapperProps as ad, isSameWrapperChain as b, computeContainerHostClasses as c, initializationComponentPath as d, createWrapperChainController as e, createHiddenSignal as f, createRenderReadySignal as g, getNormalizedArrayMetadata as h, injectFieldRegistry as i, emitComponentInitialized as j, getFieldDefaultValue as k, resolveFieldWindowing as l, mapFieldToInputs as m, collectInitializingContainerKeys as n, ActivePageInitializedEvent as o, initializationComponentKey as p, DEV_MODE as q, resolveWrappers as r, setupContainerInitEffect as s, traverseFieldsWithContext as t, DERIVATION_WARNING_TRACKER as u, FormStateManager as v, DERIVATION_LOG_CONFIG as w, AppendArrayItemEvent as x, ComponentAddonComponent as y, ConsoleLogger as z };
4746
- //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-DCX7tvaB.mjs.map
5047
+ //# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-tA8ZkP8i.mjs.map