@ng-forge/dynamic-forms 1.3.0-next.3 → 1.3.0-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/fesm2022/ng-forge-dynamic-forms-active-page-initialized.event-bnrwNw7Y.mjs +156 -0
  2. package/fesm2022/ng-forge-dynamic-forms-active-page-initialized.event-bnrwNw7Y.mjs.map +1 -0
  3. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-EuYCbquo.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-B6WH0Etk.mjs} +2 -2
  4. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-EuYCbquo.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-B6WH0Etk.mjs.map} +1 -1
  5. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-web-mcp-2wQK_wPp.mjs → ng-forge-dynamic-forms-bootstrap-web-mcp-VjJn-JeD.mjs} +2 -2
  6. package/fesm2022/{ng-forge-dynamic-forms-bootstrap-web-mcp-2wQK_wPp.mjs.map → ng-forge-dynamic-forms-bootstrap-web-mcp-VjJn-JeD.mjs.map} +1 -1
  7. package/fesm2022/{ng-forge-dynamic-forms-form-state-manager-DcOXRFRL.mjs → ng-forge-dynamic-forms-form-state-manager-BJKBX4FL.mjs} +26 -3
  8. package/fesm2022/ng-forge-dynamic-forms-form-state-manager-BJKBX4FL.mjs.map +1 -0
  9. package/fesm2022/ng-forge-dynamic-forms-internal.mjs +109 -14
  10. package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
  11. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-BRjQmWC9.mjs → ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs} +37 -5
  12. package/fesm2022/ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs.map +1 -0
  13. package/fesm2022/ng-forge-dynamic-forms.mjs +85 -26
  14. package/fesm2022/ng-forge-dynamic-forms.mjs.map +1 -1
  15. package/package.json +1 -1
  16. package/types/ng-forge-dynamic-forms-internal.d.ts +9 -0
  17. package/types/ng-forge-dynamic-forms.d.ts +63 -2
  18. package/fesm2022/ng-forge-dynamic-forms-active-page-initialized.event-CiKN-mcc.mjs +0 -12
  19. package/fesm2022/ng-forge-dynamic-forms-active-page-initialized.event-CiKN-mcc.mjs.map +0 -1
  20. package/fesm2022/ng-forge-dynamic-forms-form-state-manager-DcOXRFRL.mjs.map +0 -1
  21. package/fesm2022/ng-forge-dynamic-forms-page-field.component-BRjQmWC9.mjs.map +0 -1
@@ -1,10 +1,11 @@
1
1
  import { h as FIELD_WINDOWING, i as initializationComponentKey, n as collectInitializingContainerKeys, o as setupContainerInitEffect, p as resolveFieldWindowing, r as computeContainerHostClasses, t as DfFieldOutlet } from "./ng-forge-dynamic-forms-df-field-outlet.directive-CQsDMV-s.mjs";
2
+ import { i as DF_FIELD_PLACEHOLDERS, n as createPlaceholderContextCache, r as resolvePlaceholderTemplate, t as ActivePageInitializedEvent } from "./ng-forge-dynamic-forms-active-page-initialized.event-bnrwNw7Y.mjs";
2
3
  import { t as createFieldResolutionPipe, u as injectFieldRegistry } from "./ng-forge-dynamic-forms-resolve-field-ByGa5cpo.mjs";
3
- import { t as ActivePageInitializedEvent } from "./ng-forge-dynamic-forms-active-page-initialized.event-CiKN-mcc.mjs";
4
4
  import * as i0 from "@angular/core";
5
5
  import { ChangeDetectionStrategy, Component, DestroyRef, EnvironmentInjector, Injector, afterRenderEffect, computed, inject, input, signal } from "@angular/core";
6
6
  import { explicitEffect } from "ngxtension/explicit-effect";
7
7
  import { DynamicFormLogger, EventBus, FORM_OPTIONS, derivedFromDeferred, getGridClassString, isContainerField, validatePageNesting } from "@ng-forge/dynamic-forms/internal";
8
+ import { NgTemplateOutlet } from "@angular/common";
8
9
  import { outputFromObservable, takeUntilDestroyed } from "@angular/core/rxjs-interop";
9
10
  var PageFieldComponent = class PageFieldComponent {
10
11
  destroyRef = inject(DestroyRef);
@@ -15,6 +16,8 @@ var PageFieldComponent = class PageFieldComponent {
15
16
  logger = inject(DynamicFormLogger);
16
17
  formOptions = inject(FORM_OPTIONS, { optional: true });
17
18
  globalFieldWindowing = inject(FIELD_WINDOWING);
19
+ fieldPlaceholders = inject(DF_FIELD_PLACEHOLDERS, { optional: true });
20
+ placeholderContextFor = createPlaceholderContextCache();
18
21
  field = input.required(...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
19
22
  key = input.required(...ngDevMode ? [{ debugName: "key" }] : /* istanbul ignore next */ []);
20
23
  className = input(...ngDevMode ? [void 0, { debugName: "className" }] : /* istanbul ignore next */ []);
@@ -73,6 +76,16 @@ var PageFieldComponent = class PageFieldComponent {
73
76
  const grid = getGridClassString(field.fieldDef);
74
77
  return grid ? `df-field-placeholder ${grid}` : "df-field-placeholder";
75
78
  }
79
+ placeholderTemplate(field) {
80
+ const placeholders = this.fieldPlaceholders?.();
81
+ return placeholders ? resolvePlaceholderTemplate(placeholders, {
82
+ key: field.key,
83
+ type: field.fieldDef.type
84
+ }) : null;
85
+ }
86
+ placeholderContext(field) {
87
+ return this.placeholderContextFor(field);
88
+ }
76
89
  setupEffects() {
77
90
  setupContainerInitEffect(this.resolvedFields, this.eventBus, "page", () => this.field().key, this.injector);
78
91
  let announced = null;
@@ -170,7 +183,12 @@ var PageFieldComponent = class PageFieldComponent {
170
183
  [style.min-height]="fieldWindowing().placeholderHeight"
171
184
  [attr.data-field-key]="field.key"
172
185
  aria-hidden="true"
173
- ></div>
186
+ inert
187
+ >
188
+ @if (placeholderTemplate(field); as tpl) {
189
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="placeholderContext(field)" />
190
+ }
191
+ </div>
174
192
  }
175
193
  }
176
194
  } @else {
@@ -185,6 +203,15 @@ var PageFieldComponent = class PageFieldComponent {
185
203
  type: DfFieldOutlet,
186
204
  selector: "[dfFieldOutlet]",
187
205
  inputs: ["dfFieldOutlet", "dfFieldOutletEnvironmentInjector"]
206
+ }, {
207
+ kind: "directive",
208
+ type: NgTemplateOutlet,
209
+ selector: "[ngTemplateOutlet]",
210
+ inputs: [
211
+ "ngTemplateOutletContext",
212
+ "ngTemplateOutlet",
213
+ "ngTemplateOutletInjector"
214
+ ]
188
215
  }],
189
216
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
190
217
  deferBlockDependencies: [() => [DfFieldOutlet]]
@@ -199,7 +226,7 @@ i0.ɵɵngDeclareClassMetadata({
199
226
  type: Component,
200
227
  args: [{
201
228
  selector: "section[page-field]",
202
- imports: [DfFieldOutlet],
229
+ imports: [DfFieldOutlet, NgTemplateOutlet],
203
230
  template: `
204
231
  @for (field of resolvedFields(); track field.key; let i = $index) {
205
232
  @if (windowsField(field, i)) {
@@ -212,7 +239,12 @@ i0.ɵɵngDeclareClassMetadata({
212
239
  [style.min-height]="fieldWindowing().placeholderHeight"
213
240
  [attr.data-field-key]="field.key"
214
241
  aria-hidden="true"
215
- ></div>
242
+ inert
243
+ >
244
+ @if (placeholderTemplate(field); as tpl) {
245
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="placeholderContext(field)" />
246
+ }
247
+ </div>
216
248
  }
217
249
  }
218
250
  } @else {
@@ -292,4 +324,4 @@ i0.ɵɵngDeclareClassMetadata({
292
324
  });
293
325
  export { PageFieldComponent as default };
294
326
 
295
- //# sourceMappingURL=ng-forge-dynamic-forms-page-field.component-BRjQmWC9.mjs.map
327
+ //# sourceMappingURL=ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs","names":[],"sources":["../../../../packages/dynamic-forms/src/lib/fields/page/page-field.component.ts"],"sourcesContent":["import {\n afterRenderEffect,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n EnvironmentInjector,\n inject,\n Injector,\n input,\n signal,\n TemplateRef,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { DfFieldOutlet } from '../../directives/df-field-outlet/df-field-outlet.directive';\nimport { DF_FIELD_PLACEHOLDERS, type FieldPlaceholderContext } from '../../directives/df-placeholder/df-placeholder.directive';\nimport { createPlaceholderContextCache, resolvePlaceholderTemplate } from '../../directives/df-placeholder/resolve-placeholder-template';\nimport { outputFromObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { derivedFromDeferred } from '@ng-forge/dynamic-forms/internal';\nimport { createFieldResolutionPipe, ResolvedField } from '../../utils/resolve-field/resolve-field';\nimport {\n collectInitializingContainerKeys,\n computeContainerHostClasses,\n initializationComponentKey,\n setupContainerInitEffect,\n} from '../../utils/container-utils/container-utils';\nimport { PageField, validatePageNesting } from '@ng-forge/dynamic-forms/internal';\nimport { injectFieldRegistry } from '../../utils/inject-field-registry/inject-field-registry';\nimport { EventBus } from '@ng-forge/dynamic-forms/internal';\nimport { NextPageEvent, PageChangeEvent, PreviousPageEvent } from '../../events/constants';\nimport { FieldDef } from '@ng-forge/dynamic-forms/internal';\nimport { DynamicFormLogger } from '@ng-forge/dynamic-forms/internal';\nimport { FORM_OPTIONS } from '@ng-forge/dynamic-forms/internal';\nimport { getGridClassString } from '@ng-forge/dynamic-forms/internal';\nimport { isContainerField } from '@ng-forge/dynamic-forms/internal';\nimport { FIELD_WINDOWING } from '../../providers/features/field-windowing/field-windowing.token';\nimport { resolveFieldWindowing } from '../../providers/features/field-windowing/resolve-field-windowing';\nimport { ActivePageInitializedEvent } from '../../events/constants/active-page-initialized.event';\nimport { ComponentInitializedEvent } from '@ng-forge/dynamic-forms/internal';\n\n/** Renders a single page in multi-page (wizard) forms. */\n@Component({\n selector: 'section[page-field]',\n imports: [DfFieldOutlet, NgTemplateOutlet],\n template: `\n @for (field of resolvedFields(); track field.key; let i = $index) {\n @if (windowsField(field, i)) {\n @if (!field.hidden()) {\n @defer (on viewport) {\n <ng-container *dfFieldOutlet=\"field; environmentInjector: environmentInjector\" />\n } @placeholder {\n <div\n [class]=\"placeholderGridClass(field)\"\n [style.min-height]=\"fieldWindowing().placeholderHeight\"\n [attr.data-field-key]=\"field.key\"\n aria-hidden=\"true\"\n inert\n >\n @if (placeholderTemplate(field); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"placeholderContext(field)\" />\n }\n </div>\n }\n }\n } @else {\n <ng-container *dfFieldOutlet=\"field; environmentInjector: environmentInjector\" />\n }\n }\n `,\n styleUrl: './page-field.component.scss',\n host: {\n '[class]': 'hostClasses()',\n '[class.disabled]': 'disabled()',\n '[class.df-page-visible]': 'isVisible()',\n '[class.df-page-hidden]': '!isVisible()',\n '[attr.aria-hidden]': '!isVisible()',\n '[attr.data-page-index]': 'pageIndex()',\n '[id]': '`${key()}`',\n '[attr.data-testid]': 'key()',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class PageFieldComponent {\n // ─────────────────────────────────────────────────────────────────────────────\n // Dependencies\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly fieldRegistry = injectFieldRegistry();\n private readonly injector = inject(Injector);\n protected readonly environmentInjector = inject(EnvironmentInjector);\n private readonly eventBus = inject(EventBus);\n private readonly logger = inject(DynamicFormLogger);\n private readonly formOptions = inject(FORM_OPTIONS, { optional: true });\n private readonly globalFieldWindowing = inject(FIELD_WINDOWING);\n private readonly fieldPlaceholders = inject(DF_FIELD_PLACEHOLDERS, { optional: true });\n private readonly placeholderContextFor = createPlaceholderContextCache();\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Inputs\n // ─────────────────────────────────────────────────────────────────────────────\n\n field = input.required<PageField>();\n key = input.required<string>();\n className = input<string>();\n pageIndex = input.required<number>();\n isVisible = input.required<boolean>();\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Computed Signals\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly hostClasses = computed(() => computeContainerHostClasses('page-field', this.className()));\n\n readonly disabled = computed(() => this.field().disabled || false);\n\n readonly isValid = computed(() => validatePageNesting(this.field()));\n\n /**\n * Effective field-windowing config for this page. Per-form\n * `FormOptions.fieldWindowing` wins over the global `withFieldWindowing()`\n * default; both fall back to disabled (fully eager).\n */\n protected readonly fieldWindowing = computed(() =>\n resolveFieldWindowing(this.globalFieldWindowing, this.formOptions?.()?.fieldWindowing),\n );\n\n private readonly rawFieldRegistry = computed(() => this.fieldRegistry.raw);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Outputs\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly nextPage = outputFromObservable(this.eventBus.on<NextPageEvent>('next-page'));\n readonly previousPage = outputFromObservable(this.eventBus.on<PreviousPageEvent>('previous-page'));\n readonly pageChange = outputFromObservable(this.eventBus.on<PageChangeEvent>('page-change'));\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Field Resolution\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly fieldsSource = computed(() => {\n if (!this.isValid()) {\n return [];\n }\n return this.field().fields || [];\n });\n\n protected readonly resolvedFields = derivedFromDeferred(\n this.fieldsSource,\n createFieldResolutionPipe(() => ({\n loadTypeComponent: (type: string) => this.fieldRegistry.loadTypeComponent(type),\n registry: this.rawFieldRegistry(),\n injector: this.injector,\n destroyRef: this.destroyRef,\n onError: (fieldDef: FieldDef<unknown>, error: unknown) => {\n const fieldKey = fieldDef.key || '<no key>';\n this.logger.error(\n `Failed to load component for field type '${fieldDef.type}' (key: ${fieldKey}) ` +\n `within page '${this.field().key}'. Ensure the field type is registered in your field registry.`,\n error,\n );\n },\n })),\n { initialValue: [] as ResolvedField[], injector: this.injector },\n );\n\n private readonly initializedContainers = signal<ReadonlySet<string>>(new Set());\n\n private readonly expectedContainerKeys = computed(() => collectInitializingContainerKeys(this.fieldsSource()));\n\n private readonly renderReady = computed(() => {\n const source = this.fieldsSource();\n const fields = this.resolvedFields();\n const initialized = this.initializedContainers();\n return (\n fields.length === source.length &&\n fields.every((field) => field.renderReady()) &&\n this.expectedContainerKeys().every((key) => initialized.has(key))\n );\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Constructor\n // ─────────────────────────────────────────────────────────────────────────────\n\n constructor() {\n this.eventBus\n .on<ComponentInitializedEvent>('component-initialized')\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n const key = initializationComponentKey(event.componentType, event.componentId);\n this.initializedContainers.update((current) => {\n if (current.has(key)) return current;\n const next = new Set(current);\n next.add(key);\n return next;\n });\n });\n this.setupEffects();\n }\n\n /**\n * Whether a field should be deferred by field windowing. Containers are never\n * windowed: they emit `ComponentInitializedEvent`, which the form's init\n * tracker counts, so deferring one would stall `initialized` until it scrolls\n * into view. Leaf fields carry no such count, so they defer freely.\n */\n protected windowsField(field: ResolvedField, index: number): boolean {\n const w = this.fieldWindowing();\n return w.enabled && index >= w.eager && !isContainerField(field.fieldDef);\n }\n\n /** Class string for a windowed field's placeholder — matches the real field's grid column. */\n protected placeholderGridClass(field: ResolvedField): string {\n const grid = getGridClassString(field.fieldDef);\n return grid ? `df-field-placeholder ${grid}` : 'df-field-placeholder';\n }\n\n /** Projected placeholder template for a windowed field, or null for the built-in bare div. */\n protected placeholderTemplate(field: ResolvedField): TemplateRef<FieldPlaceholderContext> | null {\n const placeholders = this.fieldPlaceholders?.();\n return placeholders ? resolvePlaceholderTemplate(placeholders, { key: field.key, type: field.fieldDef.type }) : null;\n }\n\n /** Memoised template context for a windowed field's projected placeholder. */\n protected placeholderContext(field: ResolvedField): FieldPlaceholderContext {\n return this.placeholderContextFor(field);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n private setupEffects(): void {\n setupContainerInitEffect(this.resolvedFields, this.eventBus, 'page', () => this.field().key, this.injector);\n\n // Announced once per visit. `renderReady` tracks `resolvedFields`, which moves on every\n // reconciliation, so without this an event named \"initialized\" re-fires for one page.\n // Cleared when the page goes away, so returning to it announces again.\n let announced: string | null = null;\n afterRenderEffect({\n write: () => {\n if (!this.isVisible()) {\n announced = null;\n return;\n }\n if (!this.renderReady()) return;\n const visit = `${this.pageIndex()}:${this.key()}`;\n if (announced === visit) return;\n announced = visit;\n this.eventBus.dispatch(ActivePageInitializedEvent, this.pageIndex(), this.key());\n },\n });\n\n explicitEffect([this.isValid, this.field], ([valid, pageField]) => {\n if (!valid) {\n this.logger.error(\n `Invalid configuration: Page '${pageField.key}' contains nested page fields. ` +\n `Pages cannot contain other pages. Consider using groups or rows for nested structure.`,\n pageField,\n );\n }\n });\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { d as FieldViewportObserver, f as resolveFieldParking, h as FIELD_WINDOWING, i as initializationComponentKey, m as clampWindowSize, n as collectInitializingContainerKeys, p as resolveFieldWindowing, t as DfFieldOutlet, u as resolveWrappers } from "./ng-forge-dynamic-forms-df-field-outlet.directive-CQsDMV-s.mjs";
2
- import { a as walkAndValidateAddons, n as FormStateManager, o as normalizeSimplifiedArrays, r as VALUE_EXCLUSION_DEFAULTS, s as FormSubmitEvent, t as FORM_STATE_DEPS } from "./ng-forge-dynamic-forms-form-state-manager-DcOXRFRL.mjs";
2
+ import { a as walkAndValidateAddons, n as FormStateManager, o as normalizeSimplifiedArrays, r as VALUE_EXCLUSION_DEFAULTS, s as FormSubmitEvent, t as FORM_STATE_DEPS } from "./ng-forge-dynamic-forms-form-state-manager-BJKBX4FL.mjs";
3
3
  import { c as PROPERTY_OVERRIDE_STORE, l as createPropertyOverrideStore, u as injectFieldRegistry } from "./ng-forge-dynamic-forms-resolve-field-ByGa5cpo.mjs";
4
4
  import { a as resolveDefaultExport, n as loadWrapperComponent } from "./ng-forge-dynamic-forms-wrapper-chain-BnntfNU1.mjs";
5
5
  import { n as getNormalizedArrayMetadata } from "./ng-forge-dynamic-forms-default-value-D5M4MNE-.mjs";
@@ -7,9 +7,9 @@ import { a as isDynamicFormFeature, i as createFeature, n as withLoggerConfig, o
7
7
  import { t as ArrayItemRegistryService } from "./ng-forge-dynamic-forms-array-item-registry.service-D-AxVLdk.mjs";
8
8
  import { t as SchemaRegistryService } from "./ng-forge-dynamic-forms-schema-registry.service-axBV9FBH.mjs";
9
9
  import { n as createContainerFieldProcessors, t as CONTAINER_FIELD_PROCESSORS } from "./ng-forge-dynamic-forms-container-field-processors-C_JRvaVt.mjs";
10
+ import { a as DfPlaceholder, i as DF_FIELD_PLACEHOLDERS, n as createPlaceholderContextCache, o as DfPlaceholderRegistry, r as resolvePlaceholderTemplate, t as ActivePageInitializedEvent } from "./ng-forge-dynamic-forms-active-page-initialized.event-bnrwNw7Y.mjs";
10
11
  import { t as DEV_MODE } from "./ng-forge-dynamic-forms-dev-mode-4rbYBBo_.mjs";
11
12
  import { t as VALIDATION_EXECUTION_DEFAULTS } from "./ng-forge-dynamic-forms-validation-execution.token-BFyySKtp.mjs";
12
- import { t as ActivePageInitializedEvent } from "./ng-forge-dynamic-forms-active-page-initialized.event-CiKN-mcc.mjs";
13
13
  import * as i0 from "@angular/core";
14
14
  import { ChangeDetectionStrategy, Component, DestroyRef, Directive, ElementRef, EnvironmentInjector, Injectable, InjectionToken, Injector, PLATFORM_ID, PendingTasks, TemplateRef, afterNextRender, computed, contentChildren, inject, input, isDevMode, linkedSignal, makeEnvironmentProviders, model, runInInjectionContext, signal, untracked } from "@angular/core";
15
15
  import { explicitEffect } from "ngxtension/explicit-effect";
@@ -517,7 +517,7 @@ var PageOrchestratorComponent = class PageOrchestratorComponent {
517
517
  isInline: true,
518
518
  styles: [":host{display:block;position:relative;width:100%}\n"],
519
519
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
520
- deferBlockDependencies: [() => [import("./ng-forge-dynamic-forms-page-field.component-BRjQmWC9.mjs").then((m) => m.default)]]
520
+ deferBlockDependencies: [() => [import("./ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs").then((m) => m.default)]]
521
521
  });
522
522
  };
523
523
  i0.ɵɵngDeclareClassMetadataAsync({
@@ -525,7 +525,7 @@ i0.ɵɵngDeclareClassMetadataAsync({
525
525
  version: "22.2.5",
526
526
  ngImport: i0,
527
527
  type: PageOrchestratorComponent,
528
- resolveDeferredDeps: () => [import("./ng-forge-dynamic-forms-page-field.component-BRjQmWC9.mjs").then((m) => m.default)],
528
+ resolveDeferredDeps: () => [import("./ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs").then((m) => m.default)],
529
529
  resolveMetadata: (PageFieldComponent) => ({
530
530
  decorators: [{
531
531
  type: Component,
@@ -624,7 +624,7 @@ function createDerivationRenderGate() {
624
624
  explicitEffect([hasDerivations], ([has]) => {
625
625
  if (!has || engine() !== "idle") return;
626
626
  engine.set("loading");
627
- pendingTasks.run(() => import("./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-EuYCbquo.mjs").then(({ bootstrapDerivationOrchestrator }) => {
627
+ pendingTasks.run(() => import("./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-B6WH0Etk.mjs").then(({ bootstrapDerivationOrchestrator }) => {
628
628
  runInInjectionContext(injector, () => bootstrapDerivationOrchestrator());
629
629
  engine.set("wired");
630
630
  }).catch((error) => {
@@ -677,7 +677,7 @@ function createWebMcpGate() {
677
677
  const controller = new AbortController();
678
678
  epoch = controller;
679
679
  status.set("registering");
680
- import("./ng-forge-dynamic-forms-bootstrap-web-mcp-2wQK_wPp.mjs").then(({ bootstrapWebMcp }) => {
680
+ import("./ng-forge-dynamic-forms-bootstrap-web-mcp-VjJn-JeD.mjs").then(({ bootstrapWebMcp }) => {
681
681
  if (thisEpoch !== epochId || controller.signal.aborted) return;
682
682
  return runInInjectionContext(injector, () => bootstrapWebMcp(input.options, controller.signal));
683
683
  }).then((result) => {
@@ -1039,8 +1039,12 @@ var DynamicForm = class DynamicForm {
1039
1039
  logger = inject(DynamicFormLogger$1);
1040
1040
  dispatcher = inject(EventDispatcher, { optional: true });
1041
1041
  templateRegistry = inject(DfFieldTemplateRegistry);
1042
+ placeholderRegistry = inject(DfPlaceholderRegistry);
1043
+ fieldPlaceholders = inject(DF_FIELD_PLACEHOLDERS);
1042
1044
  globalFieldWindowing = inject(FIELD_WINDOWING);
1043
1045
  _projectedTemplates = contentChildren(DfTemplate, ...ngDevMode ? [{ debugName: "_projectedTemplates" }] : /* istanbul ignore next */ []);
1046
+ _projectedPlaceholders = contentChildren(DfPlaceholder, ...ngDevMode ? [{ debugName: "_projectedPlaceholders" }] : /* istanbul ignore next */ []);
1047
+ placeholderContextFor = createPlaceholderContextCache();
1044
1048
  stateManager = this.connectDeps();
1045
1049
  formIdPrefix = inject(FormIdPrefixService);
1046
1050
  idPrefix = this.formIdPrefix.prefix;
@@ -1121,6 +1125,15 @@ var DynamicForm = class DynamicForm {
1121
1125
  const grid = getGridClassString(field.fieldDef);
1122
1126
  return grid ? `df-field-placeholder ${grid}` : "df-field-placeholder";
1123
1127
  }
1128
+ placeholderTemplate(field) {
1129
+ return resolvePlaceholderTemplate(this.fieldPlaceholders(), {
1130
+ key: field.key,
1131
+ type: field.fieldDef.type
1132
+ });
1133
+ }
1134
+ placeholderContext(field) {
1135
+ return this.placeholderContextFor(field);
1136
+ }
1124
1137
  setupEffects() {
1125
1138
  explicitEffect([this.formModeDetection, this.pageFieldDefinitions], ([{ mode }, pages]) => {
1126
1139
  if (mode === "paged" && pages.length > 0) this.eventBus.dispatch(ComponentInitializedEvent, "dynamic-form", this.componentId);
@@ -1139,6 +1152,7 @@ var DynamicForm = class DynamicForm {
1139
1152
  for (const t of templates) map.set(t.dfTemplate(), t.templateRef);
1140
1153
  this.templateRegistry.set(map);
1141
1154
  });
1155
+ this.placeholderRegistry.bind(this._projectedPlaceholders);
1142
1156
  }
1143
1157
  connectDeps() {
1144
1158
  const deps = inject(FORM_STATE_DEPS);
@@ -1232,12 +1246,21 @@ var DynamicForm = class DynamicForm {
1232
1246
  {
1233
1247
  provide: DF_FIELD_TEMPLATES$1,
1234
1248
  useFactory: () => inject(DfFieldTemplateRegistry).map
1249
+ },
1250
+ DfPlaceholderRegistry,
1251
+ {
1252
+ provide: DF_FIELD_PLACEHOLDERS,
1253
+ useFactory: () => inject(DfPlaceholderRegistry).placeholders
1235
1254
  }
1236
1255
  ],
1237
1256
  queries: [{
1238
1257
  propertyName: "_projectedTemplates",
1239
1258
  predicate: DfTemplate,
1240
1259
  isSignal: true
1260
+ }, {
1261
+ propertyName: "_projectedPlaceholders",
1262
+ predicate: DfPlaceholder,
1263
+ isSignal: true
1241
1264
  }],
1242
1265
  ngImport: i0,
1243
1266
  template: `
@@ -1258,7 +1281,12 @@ var DynamicForm = class DynamicForm {
1258
1281
  [style.min-height]="fieldWindowing().placeholderHeight"
1259
1282
  [attr.data-field-key]="field.key"
1260
1283
  aria-hidden="true"
1261
- ></div>
1284
+ inert
1285
+ >
1286
+ @if (placeholderTemplate(field); as tpl) {
1287
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="placeholderContext(field)" />
1288
+ }
1289
+ </div>
1262
1290
  }
1263
1291
  }
1264
1292
  } @else {
@@ -1276,21 +1304,34 @@ var DynamicForm = class DynamicForm {
1276
1304
  `,
1277
1305
  isInline: true,
1278
1306
  styles: [".df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}.df-form>*{grid-column:1/-1}.df-row{display:grid;grid-template-columns:repeat(var(--df-grid-columns, 12),1fr);gap:var(--df-grid-gap, .5rem);align-items:start;width:100%}.df-row>*:not([class*=df-col-]){grid-column:1/-1}.df-col-1{grid-column:span 1}.df-col-2{grid-column:span 2}.df-col-3{grid-column:span 3}.df-col-4{grid-column:span 4}.df-col-5{grid-column:span 5}.df-col-6{grid-column:span 6}.df-col-7{grid-column:span 7}.df-col-8{grid-column:span 8}.df-col-9{grid-column:span 9}.df-col-10{grid-column:span 10}.df-col-11{grid-column:span 11}.df-col-12{grid-column:span 12}.df-col-auto{grid-column:span auto;width:auto}.df-col-full{grid-column:1/-1}.df-col-start-1{grid-column-start:1}.df-col-start-2{grid-column-start:2}.df-col-start-3{grid-column-start:3}.df-col-start-4{grid-column-start:4}.df-col-start-5{grid-column-start:5}.df-col-start-6{grid-column-start:6}.df-col-start-7{grid-column-start:7}.df-col-start-8{grid-column-start:8}.df-col-start-9{grid-column-start:9}.df-col-start-10{grid-column-start:10}.df-col-start-11{grid-column-start:11}.df-col-start-12{grid-column-start:12}.df-col-end-1{grid-column-end:1}.df-col-end-2{grid-column-end:2}.df-col-end-3{grid-column-end:3}.df-col-end-4{grid-column-end:4}.df-col-end-5{grid-column-end:5}.df-col-end-6{grid-column-end:6}.df-col-end-7{grid-column-end:7}.df-col-end-8{grid-column-end:8}.df-col-end-9{grid-column-end:9}.df-col-end-10{grid-column-end:10}.df-col-end-11{grid-column-end:11}.df-col-end-12{grid-column-end:12}.df-col-end-13{grid-column-end:13}@media(max-width:576px){.df-form{--df-grid-gap: var(--df-grid-gap-sm, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-sm, .5rem)}.df-row{grid-template-columns:1fr}.df-row>*{grid-column:1/-1!important}.df-row.df-row-mobile-keep-cols{grid-template-columns:repeat(var(--df-grid-columns, 12),1fr)}.df-row.df-row-mobile-keep-cols>*{grid-column:revert!important}}@media(min-width:577px)and (max-width:768px){.df-form{--df-grid-gap: var(--df-grid-gap-md, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-md, .5rem)}.df-row{--df-grid-columns: 6}.df-col-sm-1{grid-column:span 1}.df-col-sm-2{grid-column:span 2}.df-col-sm-3{grid-column:span 3}.df-col-sm-4{grid-column:span 4}.df-col-sm-5{grid-column:span 5}.df-col-sm-6{grid-column:span 6}.df-col-sm-full{grid-column:1/-1}}@media(min-width:769px)and (max-width:992px){.df-form{--df-grid-gap: var(--df-grid-gap-lg, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-lg, .5rem)}.df-col-md-1{grid-column:span 1}.df-col-md-2{grid-column:span 2}.df-col-md-3{grid-column:span 3}.df-col-md-4{grid-column:span 4}.df-col-md-5{grid-column:span 5}.df-col-md-6{grid-column:span 6}.df-col-md-7{grid-column:span 7}.df-col-md-8{grid-column:span 8}.df-col-md-9{grid-column:span 9}.df-col-md-10{grid-column:span 10}.df-col-md-11{grid-column:span 11}.df-col-md-12{grid-column:span 12}.df-col-md-full{grid-column:1/-1}}@media(min-width:993px){.df-form{--df-grid-gap: var(--df-grid-gap-xl, .5rem);--df-grid-row-gap: var(--df-grid-row-gap-xl, .5rem)}.df-col-lg-1{grid-column:span 1}.df-col-lg-2{grid-column:span 2}.df-col-lg-3{grid-column:span 3}.df-col-lg-4{grid-column:span 4}.df-col-lg-5{grid-column:span 5}.df-col-lg-6{grid-column:span 6}.df-col-lg-7{grid-column:span 7}.df-col-lg-8{grid-column:span 8}.df-col-lg-9{grid-column:span 9}.df-col-lg-10{grid-column:span 10}.df-col-lg-11{grid-column:span 11}.df-col-lg-12{grid-column:span 12}.df-col-lg-full{grid-column:1/-1}}.df-gap-none{--df-grid-gap: 0}.df-gap-xs{--df-grid-gap: .25rem}.df-gap-sm{--df-grid-gap: .5rem}.df-gap-md{--df-grid-gap: 1rem}.df-gap-lg{--df-grid-gap: 1.5rem}.df-gap-xl{--df-grid-gap: 2rem}.df-row-gap-none{--df-grid-row-gap: 0}.df-row-gap-xs{--df-grid-row-gap: .25rem}.df-row-gap-sm{--df-grid-row-gap: .5rem}.df-row-gap-md{--df-grid-row-gap: 1rem}.df-row-gap-lg{--df-grid-row-gap: 1.5rem}.df-row-gap-xl{--df-grid-row-gap: 2rem}.df-field{display:block;width:100%;min-width:0;overflow:hidden;margin:0}.df-group,.df-page{display:block;width:100%}.df-form.disabled,.df-row.disabled,.df-field.disabled{opacity:.6;pointer-events:none}.df-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-sr-only-focusable:focus,.df-sr-only-focusable:active{position:static;width:auto;height:auto;padding:inherit;margin:inherit;overflow:visible;clip:auto;white-space:normal}.df-live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.df-form :focus-visible{outline:2px solid var(--df-focus-color, #005fcc);outline-offset:2px}.df-group:focus-within{outline:1px dashed var(--df-focus-color, #005fcc);outline-offset:4px}:host{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap, .5rem);width:100%}:host>*{grid-column:1/-1}:host.df-form-spacing-custom{--df-grid-row-gap: var(--df-form-custom-spacing, 1.5rem)}:host.df-form-gap-none{--df-grid-row-gap: 0}:host.df-form-gap-xs{--df-grid-row-gap: .25rem}:host.df-form-gap-sm{--df-grid-row-gap: .5rem}:host.df-form-gap-md{--df-grid-row-gap: 1rem}:host.df-form-gap-lg{--df-grid-row-gap: 1.5rem}:host.df-form-gap-xl{--df-grid-row-gap: 2rem}:host.df-form-paged{gap:0}.df-field-placeholder{display:block}\n"],
1279
- dependencies: [{
1280
- kind: "directive",
1281
- type: DfFieldOutlet,
1282
- selector: "[dfFieldOutlet]",
1283
- inputs: ["dfFieldOutlet", "dfFieldOutletEnvironmentInjector"]
1284
- }, {
1285
- kind: "component",
1286
- type: PageOrchestratorComponent,
1287
- selector: "div[page-orchestrator]",
1288
- inputs: [
1289
- "pageFields",
1290
- "form",
1291
- "fieldSignalContext"
1292
- ]
1293
- }],
1307
+ dependencies: [
1308
+ {
1309
+ kind: "directive",
1310
+ type: DfFieldOutlet,
1311
+ selector: "[dfFieldOutlet]",
1312
+ inputs: ["dfFieldOutlet", "dfFieldOutletEnvironmentInjector"]
1313
+ },
1314
+ {
1315
+ kind: "component",
1316
+ type: PageOrchestratorComponent,
1317
+ selector: "div[page-orchestrator]",
1318
+ inputs: [
1319
+ "pageFields",
1320
+ "form",
1321
+ "fieldSignalContext"
1322
+ ]
1323
+ },
1324
+ {
1325
+ kind: "directive",
1326
+ type: NgTemplateOutlet,
1327
+ selector: "[ngTemplateOutlet]",
1328
+ inputs: [
1329
+ "ngTemplateOutletContext",
1330
+ "ngTemplateOutlet",
1331
+ "ngTemplateOutletInjector"
1332
+ ]
1333
+ }
1334
+ ],
1294
1335
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
1295
1336
  deferBlockDependencies: [() => [DfFieldOutlet]]
1296
1337
  });
@@ -1304,7 +1345,11 @@ i0.ɵɵngDeclareClassMetadata({
1304
1345
  type: Component,
1305
1346
  args: [{
1306
1347
  selector: "form[dynamic-form]",
1307
- imports: [DfFieldOutlet, PageOrchestratorComponent],
1348
+ imports: [
1349
+ DfFieldOutlet,
1350
+ PageOrchestratorComponent,
1351
+ NgTemplateOutlet
1352
+ ],
1308
1353
  template: `
1309
1354
  @if (shouldRender()) {
1310
1355
  @switch (formModeDetection().mode) {
@@ -1323,7 +1368,12 @@ i0.ɵɵngDeclareClassMetadata({
1323
1368
  [style.min-height]="fieldWindowing().placeholderHeight"
1324
1369
  [attr.data-field-key]="field.key"
1325
1370
  aria-hidden="true"
1326
- ></div>
1371
+ inert
1372
+ >
1373
+ @if (placeholderTemplate(field); as tpl) {
1374
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="placeholderContext(field)" />
1375
+ }
1376
+ </div>
1327
1377
  }
1328
1378
  }
1329
1379
  } @else {
@@ -1345,6 +1395,11 @@ i0.ɵɵngDeclareClassMetadata({
1345
1395
  {
1346
1396
  provide: DF_FIELD_TEMPLATES$1,
1347
1397
  useFactory: () => inject(DfFieldTemplateRegistry).map
1398
+ },
1399
+ DfPlaceholderRegistry,
1400
+ {
1401
+ provide: DF_FIELD_PLACEHOLDERS,
1402
+ useFactory: () => inject(DfPlaceholderRegistry).placeholders
1348
1403
  }
1349
1404
  ],
1350
1405
  host: {
@@ -1402,6 +1457,10 @@ i0.ɵɵngDeclareClassMetadata({
1402
1457
  type: i0.ContentChildren,
1403
1458
  args: [i0.forwardRef(() => DfTemplate), { isSignal: true }]
1404
1459
  }],
1460
+ _projectedPlaceholders: [{
1461
+ type: i0.ContentChildren,
1462
+ args: [i0.forwardRef(() => DfPlaceholder), { isSignal: true }]
1463
+ }],
1405
1464
  validityChange: [{
1406
1465
  type: i0.Output,
1407
1466
  args: ["validityChange"]
@@ -1497,7 +1556,7 @@ const BUILT_IN_FIELDS = [
1497
1556
  },
1498
1557
  {
1499
1558
  name: "page",
1500
- loadComponent: () => import("./ng-forge-dynamic-forms-page-field.component-BRjQmWC9.mjs"),
1559
+ loadComponent: () => import("./ng-forge-dynamic-forms-page-field.component-Bsd8YpzL.mjs"),
1501
1560
  mapper: pageFieldMapper,
1502
1561
  valueHandling: "flatten",
1503
1562
  ...CONTAINER_FIELD_TYPES_BASE
@@ -2131,6 +2190,6 @@ function arrayEvent(arrayKey) {
2131
2190
  move: (from, to) => new MoveArrayItemEvent(arrayKey, from, to)
2132
2191
  };
2133
2192
  }
2134
- export { ActivePageInitializedEvent, AppendArrayItemEvent, BUILT_IN_FIELDS, ComponentAddonComponent, ConsoleLogger, DF_FIELD_TEMPLATES, DfTemplate, DynamicForm, DynamicFormError, DynamicFormLogger, EventDispatcher, FormClearEvent, FormResetEvent, FormSubmitEvent, GoToPageEvent, InsertArrayItemEvent, MoveArrayItemEvent, NextPageEvent, NoopLogger, PageChangeEvent, PagerStateEvent, PopArrayItemEvent, PrependArrayItemEvent, PreviousPageEvent, RemoveAtIndexEvent, ShiftArrayItemEvent, TemplateAddonComponent, TextAddonComponent, arrayEvent, createWrappers, hasFormValue, isArrayField, isContainerField, isDisplayOnlyField, isFieldBoundContext, isFormStateCondition, isGroupField, isHiddenField, isLeafField, isPageField, isRowField, isSimplifiedArrayField, isValueBearingField, isWrapperTypeDefinition, isWrappersBundle, provideDynamicForm, resolveDynamicValue, rowError, sanitizeFormConfig, withAddonActions, withCustomAddon, withEventFormValue, withExperimentalWebMcp, withFieldWindowing, withLegacyStatusClasses, withLoggerConfig, withPagePreload, withValidationExecutionDefaults, withValueExclusionDefaults, wrapperProps };
2193
+ export { ActivePageInitializedEvent, AppendArrayItemEvent, BUILT_IN_FIELDS, ComponentAddonComponent, ConsoleLogger, DF_FIELD_TEMPLATES, DfPlaceholder, DfTemplate, DynamicForm, DynamicFormError, DynamicFormLogger, EventDispatcher, FormClearEvent, FormResetEvent, FormSubmitEvent, GoToPageEvent, InsertArrayItemEvent, MoveArrayItemEvent, NextPageEvent, NoopLogger, PageChangeEvent, PagerStateEvent, PopArrayItemEvent, PrependArrayItemEvent, PreviousPageEvent, RemoveAtIndexEvent, ShiftArrayItemEvent, TemplateAddonComponent, TextAddonComponent, arrayEvent, createWrappers, hasFormValue, isArrayField, isContainerField, isDisplayOnlyField, isFieldBoundContext, isFormStateCondition, isGroupField, isHiddenField, isLeafField, isPageField, isRowField, isSimplifiedArrayField, isValueBearingField, isWrapperTypeDefinition, isWrappersBundle, provideDynamicForm, resolveDynamicValue, rowError, sanitizeFormConfig, withAddonActions, withCustomAddon, withEventFormValue, withExperimentalWebMcp, withFieldWindowing, withLegacyStatusClasses, withLoggerConfig, withPagePreload, withValidationExecutionDefaults, withValueExclusionDefaults, wrapperProps };
2135
2194
 
2136
2195
  //# sourceMappingURL=ng-forge-dynamic-forms.mjs.map