@ng-forge/dynamic-forms 1.2.0-next.7 → 1.2.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-DK7dAQv7.mjs → ng-forge-dynamic-forms-array-field.component-6yyDriVB.mjs} +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
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BfxYqAQA.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BB8jAcY4.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BfxYqAQA.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-BB8jAcY4.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-Cj2msZp_.mjs → ng-forge-dynamic-forms-container-field.component-DfQ0y-77.mjs} +2 -2
- 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
- package/fesm2022/{ng-forge-dynamic-forms-form-schema.service-C3cVSmft.mjs → ng-forge-dynamic-forms-form-schema.service-BzbBv-r0.mjs} +2 -2
- 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
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DN6X506r.mjs → ng-forge-dynamic-forms-group-field.component-DxHD5I8E.mjs} +3 -3
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DN6X506r.mjs.map → ng-forge-dynamic-forms-group-field.component-DxHD5I8E.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms-internal.mjs +5 -1
- package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-DCX7tvaB.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-tA8ZkP8i.mjs} +464 -163
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-tA8ZkP8i.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-D16ey8r-.mjs → ng-forge-dynamic-forms-page-field.component-DCdBvJ-h.mjs} +2 -2
- 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
- package/fesm2022/{ng-forge-dynamic-forms-schema-builder-DO-su9sF.mjs → ng-forge-dynamic-forms-schema-builder-IsjNBo0h.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-schema-builder-DO-su9sF.mjs.map → ng-forge-dynamic-forms-schema-builder-IsjNBo0h.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
- package/package.json +1 -1
- package/types/ng-forge-dynamic-forms-internal.d.ts +16 -2
- package/types/ng-forge-dynamic-forms.d.ts +48 -3
- 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 {
|
|
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 {
|
|
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
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
|
|
661
|
+
fieldEnvInjector = computed(() => this.dfFieldOutletEnvironmentInjector() ?? this.defaultEnvInjector, /* @ts-ignore */
|
|
481
662
|
...(ngDevMode ? [{ debugName: "fieldEnvInjector" }] : /* istanbul ignore next */ []));
|
|
482
|
-
|
|
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
|
-
|
|
502
|
-
|
|
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
|
-
|
|
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: () =>
|
|
796
|
+
factory: () => new Map(),
|
|
583
797
|
});
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
5047
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-tA8ZkP8i.mjs.map
|