@dynamic-field-kit/angular 1.4.0 → 1.5.1

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 (51) hide show
  1. package/CHANGELOG.md +190 -0
  2. package/LICENSE +21 -0
  3. package/README.md +144 -5
  4. package/dist/components/DynamicFormDevTools.d.ts +16 -0
  5. package/dist/components/DynamicInput.d.ts +2 -1
  6. package/dist/components/FieldInput.d.ts +7 -1
  7. package/dist/components/MultiFieldInput.d.ts +13 -2
  8. package/dist/fesm2022/dynamic-field-kit-angular.mjs +578 -34
  9. package/dist/index.d.ts +1 -1
  10. package/dist/layout/index.d.ts +2 -2
  11. package/dist/lib/dynamic-field-kit.module.d.ts +4 -4
  12. package/dist/lib/dynamic-form.store.d.ts +23 -0
  13. package/dist/public-api.d.ts +10 -8
  14. package/package.json +58 -24
  15. package/dist/README.md +0 -235
  16. package/dist/esm2022/components/BaseInput.mjs +0 -59
  17. package/dist/esm2022/components/DynamicInput.mjs +0 -244
  18. package/dist/esm2022/components/FieldInput.mjs +0 -99
  19. package/dist/esm2022/components/MultiFieldInput.mjs +0 -338
  20. package/dist/esm2022/dynamic-field-kit-angular.mjs +0 -5
  21. package/dist/esm2022/fieldRegistryToken.mjs +0 -12
  22. package/dist/esm2022/layout/defaultLayouts.mjs +0 -114
  23. package/dist/esm2022/layout/index.mjs +0 -3
  24. package/dist/esm2022/layout/layoutRegistry.mjs +0 -14
  25. package/dist/esm2022/lib/dynamic-field-kit.module.mjs +0 -52
  26. package/dist/esm2022/public-api.mjs +0 -18
  27. package/dist/esm2022/types/layout.mjs +0 -2
  28. package/dist/fesm2022/dynamic-field-kit-angular.mjs.map +0 -1
  29. package/ng-package.json +0 -7
  30. package/src/components/BaseInput.ts +0 -57
  31. package/src/components/DynamicInput.ts +0 -280
  32. package/src/components/FieldInput.ts +0 -74
  33. package/src/components/MultiFieldInput.ts +0 -331
  34. package/src/fieldRegistryToken.ts +0 -15
  35. package/src/layout/defaultLayouts.ts +0 -70
  36. package/src/layout/index.ts +0 -2
  37. package/src/layout/layoutRegistry.ts +0 -25
  38. package/src/lib/dynamic-field-kit.module.ts +0 -29
  39. package/src/public-api.ts +0 -40
  40. package/src/types/layout.ts +0 -14
  41. package/test/DynamicInput.spec.ts +0 -230
  42. package/test/FieldInput.spec.ts +0 -146
  43. package/test/MultiFieldInput.spec.ts +0 -256
  44. package/test/helpers/renderers.ts +0 -89
  45. package/test/layout.spec.ts +0 -119
  46. package/test/publicApi.spec.ts +0 -64
  47. package/test/setup.ts +0 -12
  48. package/test/smoke.spec.ts +0 -27
  49. package/tsconfig.json +0 -13
  50. package/tsconfig.spec.json +0 -9
  51. package/vitest.config.ts +0 -30
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Output, Input, Component, InjectionToken, inject, ViewContainerRef, ViewChild, ChangeDetectionStrategy, HostListener, NgModule } from '@angular/core';
2
+ import { EventEmitter, Output, Input, Component, InjectionToken, inject, ViewContainerRef, ViewChild, ChangeDetectionStrategy, HostListener, signal, computed, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { CommonModule, NgIf, NgClass, NgFor } from '@angular/common';
4
+ import { CommonModule, NgIf, NgClass, NgFor, JsonPipe } from '@angular/common';
5
5
  import { fieldRegistry, applyComputedValues, validateFields, resolveOptions, resolveDisabled, resolveReadOnly, validateField, canAddGroupItem, canRemoveGroupItem, createGroupItem } from '@dynamic-field-kit/core';
6
6
  export { FieldRegistry, fieldRegistry, resolveDisabled, resolveOptions, resolveReadOnly, validateField, validateFieldAsync, validateFields, validateFieldsAsync, validators } from '@dynamic-field-kit/core';
7
7
 
@@ -30,10 +30,10 @@ class BaseInputComponent {
30
30
  hasChanges(changes, prop) {
31
31
  return changes[prop] !== undefined;
32
32
  }
33
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BaseInputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
34
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: BaseInputComponent, isStandalone: true, selector: "ng-component", inputs: { value: "value", label: "label", placeholder: "placeholder", required: "required", disabled: "disabled", readOnly: "readOnly", error: "error", options: "options", className: "className", description: "description" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true });
33
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: BaseInputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
34
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: BaseInputComponent, isStandalone: true, selector: "ng-component", inputs: { value: "value", label: "label", placeholder: "placeholder", required: "required", disabled: "disabled", readOnly: "readOnly", error: "error", options: "options", className: "className", description: "description" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true });
35
35
  }
36
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BaseInputComponent, decorators: [{
36
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: BaseInputComponent, decorators: [{
37
37
  type: Component,
38
38
  args: [{
39
39
  template: '',
@@ -155,6 +155,9 @@ class DynamicInput extends BaseInputComponent {
155
155
  this.cleanup();
156
156
  this.host.clear();
157
157
  if (!Renderer) {
158
+ if (this.renderDefaultFallbackHTML5(this.type)) {
159
+ return;
160
+ }
158
161
  this.renderError(`Unknown field type: ${this.type}`);
159
162
  return;
160
163
  }
@@ -280,16 +283,128 @@ class DynamicInput extends BaseInputComponent {
280
283
  this.valueChange.emit(value);
281
284
  this.onChange.emit(value);
282
285
  }
286
+ renderDefaultFallbackHTML5(type) {
287
+ const nativeEl = this.host.element.nativeElement;
288
+ if (type === 'text' ||
289
+ type === 'password' ||
290
+ type === 'email' ||
291
+ type === 'number') {
292
+ const input = document.createElement('input');
293
+ input.type = type;
294
+ if (this.className) {
295
+ input.className = this.className;
296
+ }
297
+ if (this.placeholder) {
298
+ input.placeholder = this.placeholder;
299
+ }
300
+ if (this.disabled) {
301
+ input.disabled = true;
302
+ }
303
+ if (this.readOnly) {
304
+ input.readOnly = true;
305
+ }
306
+ if (this.required) {
307
+ input.required = true;
308
+ }
309
+ input.value = (this.value ?? '').toString();
310
+ input.addEventListener('input', (e) => {
311
+ const raw = e.target.value;
312
+ const val = type === 'number' ? (raw === '' ? undefined : Number(raw)) : raw;
313
+ this.emitValue(val);
314
+ });
315
+ nativeEl.appendChild(input);
316
+ return true;
317
+ }
318
+ if (type === 'textarea') {
319
+ const textarea = document.createElement('textarea');
320
+ if (this.className) {
321
+ textarea.className = this.className;
322
+ }
323
+ if (this.placeholder) {
324
+ textarea.placeholder = this.placeholder;
325
+ }
326
+ if (this.disabled) {
327
+ textarea.disabled = true;
328
+ }
329
+ if (this.readOnly) {
330
+ textarea.readOnly = true;
331
+ }
332
+ if (this.required) {
333
+ textarea.required = true;
334
+ }
335
+ textarea.value = this.value ?? '';
336
+ textarea.addEventListener('input', (e) => {
337
+ this.emitValue(e.target.value);
338
+ });
339
+ nativeEl.appendChild(textarea);
340
+ return true;
341
+ }
342
+ if (type === 'checkbox') {
343
+ const checkbox = document.createElement('input');
344
+ checkbox.type = 'checkbox';
345
+ if (this.className) {
346
+ checkbox.className = this.className;
347
+ }
348
+ if (this.disabled || this.readOnly) {
349
+ checkbox.disabled = true;
350
+ }
351
+ if (this.required) {
352
+ checkbox.required = true;
353
+ }
354
+ checkbox.checked = Boolean(this.value);
355
+ checkbox.addEventListener('change', (e) => {
356
+ this.emitValue(e.target.checked);
357
+ });
358
+ nativeEl.appendChild(checkbox);
359
+ return true;
360
+ }
361
+ if (type === 'select') {
362
+ const select = document.createElement('select');
363
+ if (this.className) {
364
+ select.className = this.className;
365
+ }
366
+ if (this.disabled || this.readOnly) {
367
+ select.disabled = true;
368
+ }
369
+ if (this.required) {
370
+ select.required = true;
371
+ }
372
+ const defaultOpt = document.createElement('option');
373
+ defaultOpt.value = '';
374
+ defaultOpt.disabled = true;
375
+ defaultOpt.textContent = '-- Select --';
376
+ select.appendChild(defaultOpt);
377
+ const options = this.options || [];
378
+ options.forEach((opt) => {
379
+ const optObj = opt;
380
+ const optVal = optObj['value'] ?? optObj['id'] ?? opt;
381
+ const optLabel = optObj['label'] ?? optObj['name'] ?? String(optVal);
382
+ const optionEl = document.createElement('option');
383
+ optionEl.value = String(optVal);
384
+ optionEl.textContent = String(optLabel);
385
+ if (String(optVal) === String(this.value)) {
386
+ optionEl.selected = true;
387
+ }
388
+ select.appendChild(optionEl);
389
+ });
390
+ select.addEventListener('change', (e) => {
391
+ this.emitValue(e.target.value);
392
+ });
393
+ nativeEl.appendChild(select);
394
+ return true;
395
+ }
396
+ return false;
397
+ }
283
398
  renderError(message) {
284
399
  const el = document.createElement('div');
285
400
  el.textContent = message;
286
401
  el.style.color = 'red';
287
402
  this.host.element.nativeElement.appendChild(el);
288
403
  }
289
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DynamicInput, deps: null, target: i0.ɵɵFactoryTarget.Component });
290
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: DynamicInput, isStandalone: true, selector: "dfk-dynamic-input", inputs: { type: "type", extraProps: "extraProps" }, outputs: { valueChange: "valueChange", onChange: "onChange" }, viewQueries: [{ propertyName: "host", first: true, predicate: ["host"], descendants: true, read: ViewContainerRef }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `<div #host style="display: contents;"></div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
404
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicInput, deps: null, target: i0.ɵɵFactoryTarget.Component });
405
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: DynamicInput, isStandalone: true, selector: "dfk-dynamic-input", inputs: { type: "type", extraProps: "extraProps" }, outputs: { valueChange: "valueChange", onChange: "onChange" }, viewQueries: [{ propertyName: "host", first: true, predicate: ["host"], descendants: true, read: ViewContainerRef }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `<div #host style="display: contents;"></div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
291
406
  }
292
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DynamicInput, decorators: [{
407
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicInput, decorators: [{
293
408
  type: Component,
294
409
  args: [{
295
410
  selector: 'dfk-dynamic-input',
@@ -320,6 +435,12 @@ class FieldInput {
320
435
  readOnly;
321
436
  error;
322
437
  onValueChangeField = new EventEmitter();
438
+ /**
439
+ * Emits this field's name when focus leaves it. Driven by `focusout`, which
440
+ * bubbles, so it works for any renderer without the renderer having to
441
+ * declare a blur output of its own.
442
+ */
443
+ onBlurField = new EventEmitter();
323
444
  shouldRender = false;
324
445
  get resolvedOptions() {
325
446
  if (this.options) {
@@ -340,8 +461,8 @@ class FieldInput {
340
461
  this.shouldRender = !!this.fieldDescription;
341
462
  this.cdr.markForCheck();
342
463
  }
343
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FieldInput, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
344
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: FieldInput, isStandalone: true, selector: "dfk-field-input", inputs: { fieldDescription: "fieldDescription", value: "value", options: "options", disabled: "disabled", readOnly: "readOnly", error: "error" }, outputs: { onValueChangeField: "onValueChangeField" }, usesOnChanges: true, ngImport: i0, template: `
464
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FieldInput, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
465
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: FieldInput, isStandalone: true, selector: "dfk-field-input", inputs: { fieldDescription: "fieldDescription", value: "value", options: "options", disabled: "disabled", readOnly: "readOnly", error: "error" }, outputs: { onValueChangeField: "onValueChangeField", onBlurField: "onBlurField" }, usesOnChanges: true, ngImport: i0, template: `
345
466
  <dfk-dynamic-input
346
467
  *ngIf="shouldRender"
347
468
  [type]="fieldDescription!.type"
@@ -355,6 +476,7 @@ class FieldInput {
355
476
  (valueChange)="
356
477
  onValueChangeField.emit({ value: $event, key: fieldDescription!.name })
357
478
  "
479
+ (focusout)="onBlurField.emit(fieldDescription!.name)"
358
480
  [disabled]="disabled"
359
481
  [readOnly]="readOnly"
360
482
  [error]="$any(error)"
@@ -362,7 +484,7 @@ class FieldInput {
362
484
  ></dfk-dynamic-input>
363
485
  `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DynamicInput, selector: "dfk-dynamic-input", inputs: ["type", "extraProps"], outputs: ["valueChange", "onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
364
486
  }
365
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FieldInput, decorators: [{
487
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: FieldInput, decorators: [{
366
488
  type: Component,
367
489
  args: [{
368
490
  selector: 'dfk-field-input',
@@ -383,6 +505,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
383
505
  (valueChange)="
384
506
  onValueChangeField.emit({ value: $event, key: fieldDescription!.name })
385
507
  "
508
+ (focusout)="onBlurField.emit(fieldDescription!.name)"
386
509
  [disabled]="disabled"
387
510
  [readOnly]="readOnly"
388
511
  [error]="$any(error)"
@@ -404,6 +527,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
404
527
  type: Input
405
528
  }], onValueChangeField: [{
406
529
  type: Output
530
+ }], onBlurField: [{
531
+ type: Output
407
532
  }] } });
408
533
 
409
534
  const DEFAULT_BREAKPOINT = 768;
@@ -413,6 +538,22 @@ class MultiFieldInput {
413
538
  properties;
414
539
  onChange = new EventEmitter();
415
540
  validityChange = new EventEmitter();
541
+ /**
542
+ * Emits a field's name when it loses focus. Touched state is tracked
543
+ * internally either way; this is the hook for driving an external form store
544
+ * - pass `createDynamicFormStore`'s `handleBlur` to get its `touched` map and
545
+ * `validateOnBlur` behaviour.
546
+ */
547
+ onBlurField = new EventEmitter();
548
+ touchedFields = {};
549
+ handleBlurField(fieldName) {
550
+ this.touchedFields = { ...this.touchedFields, [fieldName]: true };
551
+ this.onBlurField.emit(fieldName);
552
+ }
553
+ /** Whether this field has been blurred at least once. */
554
+ isTouched(fieldName) {
555
+ return Boolean(this.touchedFields[fieldName]);
556
+ }
416
557
  layout = 'column';
417
558
  // Top-level form data, threaded down through repeatable groups so a nested
418
559
  // field's appearCondition/computeValue can read the root form. Omitted at
@@ -468,7 +609,7 @@ class MultiFieldInput {
468
609
  groupTrackBy(field) {
469
610
  let fn = this.groupTrackByCache.get(field);
470
611
  if (!fn) {
471
- fn = (index, item) => field.keyField ? item[field.keyField] ?? index : index;
612
+ fn = (index, item) => field.keyField ? (item[field.keyField] ?? index) : index;
472
613
  this.groupTrackByCache.set(field, fn);
473
614
  }
474
615
  return fn;
@@ -482,7 +623,7 @@ class MultiFieldInput {
482
623
  }
483
624
  updateIsMobile() {
484
625
  const breakpoint = typeof this.layout === 'object' && this.layout.type === 'responsive'
485
- ? this.layout.breakpoint ?? DEFAULT_BREAKPOINT
626
+ ? (this.layout.breakpoint ?? DEFAULT_BREAKPOINT)
486
627
  : DEFAULT_BREAKPOINT;
487
628
  if (typeof window !== 'undefined' &&
488
629
  typeof window.matchMedia === 'function') {
@@ -562,14 +703,14 @@ class MultiFieldInput {
562
703
  this.validityChange.emit(validateFields(this.fieldDescriptions, this.data, this.rootData));
563
704
  this.cdr.markForCheck();
564
705
  }
565
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: MultiFieldInput, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
566
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: MultiFieldInput, isStandalone: true, selector: "dfk-multi-field-input", inputs: { fieldDescriptions: "fieldDescriptions", properties: "properties", layout: "layout", rootData: "rootData" }, outputs: { onChange: "onChange", validityChange: "validityChange" }, host: { listeners: { "window:resize": "onWindowResize()" } }, usesOnChanges: true, ngImport: i0, template: `
706
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: MultiFieldInput, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
707
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: MultiFieldInput, isStandalone: true, selector: "dfk-multi-field-input", inputs: { fieldDescriptions: "fieldDescriptions", properties: "properties", layout: "layout", rootData: "rootData" }, outputs: { onChange: "onChange", validityChange: "validityChange", onBlurField: "onBlurField" }, host: { listeners: { "window:resize": "onWindowResize()" } }, usesOnChanges: true, ngImport: i0, template: `
567
708
  <div
568
709
  class="p-4 border rounded-lg bg-gray-50"
569
710
  [ngClass]="{
570
711
  'flex flex-col': resolvedLayoutType === 'column',
571
712
  'flex flex-row': resolvedLayoutType === 'row',
572
- grid: resolvedLayoutType === 'grid'
713
+ grid: resolvedLayoutType === 'grid',
573
714
  }"
574
715
  [style.gap.px]="gap"
575
716
  [style.gridTemplateColumns]="
@@ -586,6 +727,7 @@ class MultiFieldInput {
586
727
  [readOnly]="getReadOnly(field)"
587
728
  [error]="getError(field)"
588
729
  (onValueChangeField)="onFieldChange($event)"
730
+ (onBlurField)="handleBlurField($event)"
589
731
  ></dfk-field-input>
590
732
 
591
733
  <div *ngIf="field.fields" [class]="field.className">
@@ -634,9 +776,9 @@ class MultiFieldInput {
634
776
  </div>
635
777
  </ng-container>
636
778
  </div>
637
- `, isInline: true, dependencies: [{ kind: "component", type: MultiFieldInput, selector: "dfk-multi-field-input", inputs: ["fieldDescriptions", "properties", "layout", "rootData"], outputs: ["onChange", "validityChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FieldInput, selector: "dfk-field-input", inputs: ["fieldDescription", "value", "options", "disabled", "readOnly", "error"], outputs: ["onValueChangeField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
779
+ `, isInline: true, dependencies: [{ kind: "component", type: MultiFieldInput, selector: "dfk-multi-field-input", inputs: ["fieldDescriptions", "properties", "layout", "rootData"], outputs: ["onChange", "validityChange", "onBlurField"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FieldInput, selector: "dfk-field-input", inputs: ["fieldDescription", "value", "options", "disabled", "readOnly", "error"], outputs: ["onValueChangeField", "onBlurField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
638
780
  }
639
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: MultiFieldInput, decorators: [{
781
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: MultiFieldInput, decorators: [{
640
782
  type: Component,
641
783
  args: [{
642
784
  selector: 'dfk-multi-field-input',
@@ -655,7 +797,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
655
797
  [ngClass]="{
656
798
  'flex flex-col': resolvedLayoutType === 'column',
657
799
  'flex flex-row': resolvedLayoutType === 'row',
658
- grid: resolvedLayoutType === 'grid'
800
+ grid: resolvedLayoutType === 'grid',
659
801
  }"
660
802
  [style.gap.px]="gap"
661
803
  [style.gridTemplateColumns]="
@@ -672,6 +814,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
672
814
  [readOnly]="getReadOnly(field)"
673
815
  [error]="getError(field)"
674
816
  (onValueChangeField)="onFieldChange($event)"
817
+ (onBlurField)="handleBlurField($event)"
675
818
  ></dfk-field-input>
676
819
 
677
820
  <div *ngIf="field.fields" [class]="field.className">
@@ -730,6 +873,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
730
873
  type: Output
731
874
  }], validityChange: [{
732
875
  type: Output
876
+ }], onBlurField: [{
877
+ type: Output
733
878
  }], layout: [{
734
879
  type: Input
735
880
  }], rootData: [{
@@ -739,6 +884,406 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
739
884
  args: ['window:resize']
740
885
  }] } });
741
886
 
887
+ class DynamicFormDevToolsComponent {
888
+ data = {};
889
+ errors = {};
890
+ touched = {};
891
+ isDirty = false;
892
+ fields = [];
893
+ /** Number of fields carrying errors, mirroring the react and vue overlays. */
894
+ errorCount() {
895
+ return Object.keys(this.errors || {}).length;
896
+ }
897
+ isOpen = signal(false);
898
+ activeTab = signal('data');
899
+ tabs = [
900
+ 'data',
901
+ 'errors',
902
+ 'meta',
903
+ 'fields',
904
+ ];
905
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicFormDevToolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
906
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: DynamicFormDevToolsComponent, isStandalone: true, selector: "dfk-dev-tools", inputs: { data: "data", errors: "errors", touched: "touched", isDirty: "isDirty", fields: "fields" }, ngImport: i0, template: `
907
+ <button
908
+ *ngIf="!isOpen()"
909
+ type="button"
910
+ (click)="isOpen.set(true)"
911
+ style="
912
+ position: fixed;
913
+ right: 16px;
914
+ bottom: 16px;
915
+ z-index: 99999;
916
+ background: #1e293b;
917
+ color: #f8fafc;
918
+ border: 1px solid #334155;
919
+ border-radius: 20px;
920
+ padding: 8px 14px;
921
+ font-size: 12px;
922
+ font-weight: 600;
923
+ cursor: pointer;
924
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
925
+ display: flex;
926
+ align-items: center;
927
+ gap: 6px;
928
+ "
929
+ >
930
+ <span>🔍 DevTools</span>
931
+ <span
932
+ *ngIf="errorCount() > 0"
933
+ class="dfk-devtools-badge"
934
+ style="
935
+ background: #ef4444;
936
+ color: #fff;
937
+ border-radius: 10px;
938
+ padding: 2px 6px;
939
+ font-size: 10px;
940
+ "
941
+ >{{ errorCount() }}</span
942
+ >
943
+ </button>
944
+
945
+ <div
946
+ *ngIf="isOpen()"
947
+ style="
948
+ position: fixed;
949
+ right: 16px;
950
+ bottom: 16px;
951
+ z-index: 99999;
952
+ width: 360px;
953
+ max-height: 420px;
954
+ background: #0f172a;
955
+ color: #f8fafc;
956
+ border: 1px solid #334155;
957
+ border-radius: 12px;
958
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
959
+ display: flex;
960
+ flex-direction: column;
961
+ font-family: monospace, sans-serif;
962
+ font-size: 12px;
963
+ overflow: hidden;
964
+ "
965
+ >
966
+ <div
967
+ style="
968
+ padding: 10px 14px;
969
+ background: #1e293b;
970
+ display: flex;
971
+ justify-content: space-between;
972
+ align-items: center;
973
+ border-bottom: 1px solid #334155;
974
+ "
975
+ >
976
+ <span style="font-weight: bold; color: #38bdf8;">🛠️ Form DevTools</span>
977
+ <button
978
+ type="button"
979
+ (click)="isOpen.set(false)"
980
+ style="background: transparent; border: none; color: #94a3b8; font-size: 14px; cursor: pointer;"
981
+ >
982
+
983
+ </button>
984
+ </div>
985
+
986
+ <div
987
+ style="display: flex; background: #1e293b; border-bottom: 1px solid #334155;"
988
+ >
989
+ <button
990
+ type="button"
991
+ *ngFor="let tab of tabs"
992
+ (click)="activeTab.set(tab)"
993
+ [style.background]="activeTab() === tab ? '#0f172a' : 'transparent'"
994
+ [style.color]="activeTab() === tab ? '#38bdf8' : '#94a3b8'"
995
+ style="flex: 1; padding: 6px 0; border: none; cursor: pointer; text-transform: capitalize; font-size: 11px;"
996
+ >
997
+ {{ tab
998
+ }}{{
999
+ tab === 'errors' && errorCount() > 0
1000
+ ? ' (' + errorCount() + ')'
1001
+ : ''
1002
+ }}
1003
+ </button>
1004
+ </div>
1005
+
1006
+ <div style="padding: 12px; overflow-y: auto; flex: 1;">
1007
+ <pre
1008
+ *ngIf="activeTab() === 'data'"
1009
+ style="margin: 0; white-space: pre-wrap; word-break: break-all; color: #a7f3d0;"
1010
+ >
1011
+ {{ data | json }}
1012
+ </pre>
1013
+ <pre
1014
+ *ngIf="activeTab() === 'errors'"
1015
+ style="margin: 0; white-space: pre-wrap; word-break: break-all; color: #f87171;"
1016
+ >
1017
+ {{ errors | json }}
1018
+ </pre>
1019
+ <div *ngIf="activeTab() === 'meta'">
1020
+ <div>isDirty: {{ isDirty }}</div>
1021
+ <pre style="margin: 4px 0 0 0; color: #cbd5e1;">{{
1022
+ touched | json
1023
+ }}</pre>
1024
+ </div>
1025
+ <div *ngIf="activeTab() === 'fields'">
1026
+ <div
1027
+ *ngFor="let f of fields"
1028
+ style="padding: 6px; margin-bottom: 6px; background: #1e293b; border-radius: 4px;"
1029
+ >
1030
+ <div style="color: #38bdf8; font-weight: bold;">{{ f.name }}</div>
1031
+ <div style="color: #94a3b8; font-size: 10px;">
1032
+ type: {{ f.type }}
1033
+ </div>
1034
+ </div>
1035
+ </div>
1036
+ </div>
1037
+ </div>
1038
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: JsonPipe, name: "json" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1039
+ }
1040
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicFormDevToolsComponent, decorators: [{
1041
+ type: Component,
1042
+ args: [{
1043
+ selector: 'dfk-dev-tools',
1044
+ standalone: true,
1045
+ imports: [NgIf, NgFor, JsonPipe],
1046
+ changeDetection: ChangeDetectionStrategy.OnPush,
1047
+ template: `
1048
+ <button
1049
+ *ngIf="!isOpen()"
1050
+ type="button"
1051
+ (click)="isOpen.set(true)"
1052
+ style="
1053
+ position: fixed;
1054
+ right: 16px;
1055
+ bottom: 16px;
1056
+ z-index: 99999;
1057
+ background: #1e293b;
1058
+ color: #f8fafc;
1059
+ border: 1px solid #334155;
1060
+ border-radius: 20px;
1061
+ padding: 8px 14px;
1062
+ font-size: 12px;
1063
+ font-weight: 600;
1064
+ cursor: pointer;
1065
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1066
+ display: flex;
1067
+ align-items: center;
1068
+ gap: 6px;
1069
+ "
1070
+ >
1071
+ <span>🔍 DevTools</span>
1072
+ <span
1073
+ *ngIf="errorCount() > 0"
1074
+ class="dfk-devtools-badge"
1075
+ style="
1076
+ background: #ef4444;
1077
+ color: #fff;
1078
+ border-radius: 10px;
1079
+ padding: 2px 6px;
1080
+ font-size: 10px;
1081
+ "
1082
+ >{{ errorCount() }}</span
1083
+ >
1084
+ </button>
1085
+
1086
+ <div
1087
+ *ngIf="isOpen()"
1088
+ style="
1089
+ position: fixed;
1090
+ right: 16px;
1091
+ bottom: 16px;
1092
+ z-index: 99999;
1093
+ width: 360px;
1094
+ max-height: 420px;
1095
+ background: #0f172a;
1096
+ color: #f8fafc;
1097
+ border: 1px solid #334155;
1098
+ border-radius: 12px;
1099
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
1100
+ display: flex;
1101
+ flex-direction: column;
1102
+ font-family: monospace, sans-serif;
1103
+ font-size: 12px;
1104
+ overflow: hidden;
1105
+ "
1106
+ >
1107
+ <div
1108
+ style="
1109
+ padding: 10px 14px;
1110
+ background: #1e293b;
1111
+ display: flex;
1112
+ justify-content: space-between;
1113
+ align-items: center;
1114
+ border-bottom: 1px solid #334155;
1115
+ "
1116
+ >
1117
+ <span style="font-weight: bold; color: #38bdf8;">🛠️ Form DevTools</span>
1118
+ <button
1119
+ type="button"
1120
+ (click)="isOpen.set(false)"
1121
+ style="background: transparent; border: none; color: #94a3b8; font-size: 14px; cursor: pointer;"
1122
+ >
1123
+
1124
+ </button>
1125
+ </div>
1126
+
1127
+ <div
1128
+ style="display: flex; background: #1e293b; border-bottom: 1px solid #334155;"
1129
+ >
1130
+ <button
1131
+ type="button"
1132
+ *ngFor="let tab of tabs"
1133
+ (click)="activeTab.set(tab)"
1134
+ [style.background]="activeTab() === tab ? '#0f172a' : 'transparent'"
1135
+ [style.color]="activeTab() === tab ? '#38bdf8' : '#94a3b8'"
1136
+ style="flex: 1; padding: 6px 0; border: none; cursor: pointer; text-transform: capitalize; font-size: 11px;"
1137
+ >
1138
+ {{ tab
1139
+ }}{{
1140
+ tab === 'errors' && errorCount() > 0
1141
+ ? ' (' + errorCount() + ')'
1142
+ : ''
1143
+ }}
1144
+ </button>
1145
+ </div>
1146
+
1147
+ <div style="padding: 12px; overflow-y: auto; flex: 1;">
1148
+ <pre
1149
+ *ngIf="activeTab() === 'data'"
1150
+ style="margin: 0; white-space: pre-wrap; word-break: break-all; color: #a7f3d0;"
1151
+ >
1152
+ {{ data | json }}
1153
+ </pre>
1154
+ <pre
1155
+ *ngIf="activeTab() === 'errors'"
1156
+ style="margin: 0; white-space: pre-wrap; word-break: break-all; color: #f87171;"
1157
+ >
1158
+ {{ errors | json }}
1159
+ </pre>
1160
+ <div *ngIf="activeTab() === 'meta'">
1161
+ <div>isDirty: {{ isDirty }}</div>
1162
+ <pre style="margin: 4px 0 0 0; color: #cbd5e1;">{{
1163
+ touched | json
1164
+ }}</pre>
1165
+ </div>
1166
+ <div *ngIf="activeTab() === 'fields'">
1167
+ <div
1168
+ *ngFor="let f of fields"
1169
+ style="padding: 6px; margin-bottom: 6px; background: #1e293b; border-radius: 4px;"
1170
+ >
1171
+ <div style="color: #38bdf8; font-weight: bold;">{{ f.name }}</div>
1172
+ <div style="color: #94a3b8; font-size: 10px;">
1173
+ type: {{ f.type }}
1174
+ </div>
1175
+ </div>
1176
+ </div>
1177
+ </div>
1178
+ </div>
1179
+ `,
1180
+ }]
1181
+ }], propDecorators: { data: [{
1182
+ type: Input
1183
+ }], errors: [{
1184
+ type: Input
1185
+ }], touched: [{
1186
+ type: Input
1187
+ }], isDirty: [{
1188
+ type: Input
1189
+ }], fields: [{
1190
+ type: Input
1191
+ }] } });
1192
+
1193
+ function createDynamicFormStore(options) {
1194
+ const fields = options.fields;
1195
+ const initialValues = options.initialValues || {};
1196
+ const validateOnBlur = options.validateOnBlur ?? true;
1197
+ const validateOnChange = options.validateOnChange ?? false;
1198
+ const data = signal(applyComputedValues(fields, initialValues));
1199
+ const errors = signal({});
1200
+ const isDirty = signal(false);
1201
+ const touched = signal({});
1202
+ const isSubmitting = signal(false);
1203
+ const isSubmitted = signal(false);
1204
+ const isValid = computed(() => Object.keys(errors()).length === 0);
1205
+ function validate() {
1206
+ const res = validateFields(fields, data());
1207
+ errors.set(res.errors);
1208
+ return res.valid;
1209
+ }
1210
+ function handleChange(newData) {
1211
+ const next = applyComputedValues(fields, newData);
1212
+ data.set(next);
1213
+ isDirty.set(true);
1214
+ if (validateOnChange) {
1215
+ const res = validateFields(fields, next);
1216
+ errors.set(res.errors);
1217
+ }
1218
+ }
1219
+ function setFieldValue(name, value) {
1220
+ handleChange({ ...data(), [name]: value });
1221
+ }
1222
+ function setFieldTouched(name, isTouched = true) {
1223
+ touched.set({ ...touched(), [name]: isTouched });
1224
+ }
1225
+ function handleBlur(fieldName) {
1226
+ setFieldTouched(fieldName, true);
1227
+ if (validateOnBlur) {
1228
+ const res = validateFields(fields, data());
1229
+ errors.set(res.errors);
1230
+ }
1231
+ }
1232
+ function reset(newValues) {
1233
+ const seed = newValues ?? initialValues;
1234
+ const next = applyComputedValues(fields, seed);
1235
+ data.set(next);
1236
+ errors.set({});
1237
+ isDirty.set(false);
1238
+ touched.set({});
1239
+ isSubmitting.set(false);
1240
+ isSubmitted.set(false);
1241
+ }
1242
+ /**
1243
+ * Returns a submit handler, mirroring the React and Vue `useDynamicForm`
1244
+ * hooks. Bind it once and use it as the `(ngSubmit)` handler:
1245
+ * `onSubmit = this.store.handleSubmit(data => ...)`.
1246
+ */
1247
+ function handleSubmit(onValid, onInvalid) {
1248
+ return async (e) => {
1249
+ if (e && typeof e.preventDefault === 'function') {
1250
+ e.preventDefault();
1251
+ }
1252
+ isSubmitting.set(true);
1253
+ try {
1254
+ const res = validateFields(fields, data());
1255
+ errors.set(res.errors);
1256
+ isSubmitted.set(true);
1257
+ if (res.valid) {
1258
+ await onValid(data());
1259
+ }
1260
+ else if (onInvalid) {
1261
+ onInvalid(res.errors);
1262
+ }
1263
+ }
1264
+ finally {
1265
+ isSubmitting.set(false);
1266
+ }
1267
+ };
1268
+ }
1269
+ return {
1270
+ data,
1271
+ errors,
1272
+ isValid,
1273
+ isDirty,
1274
+ touched,
1275
+ isSubmitting,
1276
+ isSubmitted,
1277
+ setFieldValue,
1278
+ setFieldTouched,
1279
+ handleChange,
1280
+ handleBlur,
1281
+ reset,
1282
+ validate,
1283
+ handleSubmit,
1284
+ };
1285
+ }
1286
+
742
1287
  class LayoutRegistry {
743
1288
  layouts = new Map();
744
1289
  register(type, component) {
@@ -759,8 +1304,8 @@ class ColumnLayout {
759
1304
  get gap() {
760
1305
  return this.config?.gap ?? 12;
761
1306
  }
762
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ColumnLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
763
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: ColumnLayout, isStandalone: true, selector: "dfk-column-layout", inputs: { config: "config", template: "template" }, ngImport: i0, template: `<div
1307
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ColumnLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
1308
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: ColumnLayout, isStandalone: true, selector: "dfk-column-layout", inputs: { config: "config", template: "template" }, ngImport: i0, template: `<div
764
1309
  [style.display]="'flex'"
765
1310
  [style.flexDirection]="'column'"
766
1311
  [style.gap]="gap + 'px'"
@@ -768,7 +1313,7 @@ class ColumnLayout {
768
1313
  <ng-container *ngTemplateOutlet="template"></ng-container>
769
1314
  </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
770
1315
  }
771
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ColumnLayout, decorators: [{
1316
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ColumnLayout, decorators: [{
772
1317
  type: Component,
773
1318
  args: [{
774
1319
  selector: 'dfk-column-layout',
@@ -793,8 +1338,8 @@ class RowLayout {
793
1338
  get gap() {
794
1339
  return this.config?.gap ?? 12;
795
1340
  }
796
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: RowLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
797
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: RowLayout, isStandalone: true, selector: "dfk-row-layout", inputs: { config: "config", template: "template" }, ngImport: i0, template: `<div
1341
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: RowLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
1342
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: RowLayout, isStandalone: true, selector: "dfk-row-layout", inputs: { config: "config", template: "template" }, ngImport: i0, template: `<div
798
1343
  [style.display]="'flex'"
799
1344
  [style.flexDirection]="'row'"
800
1345
  [style.gap]="gap + 'px'"
@@ -802,7 +1347,7 @@ class RowLayout {
802
1347
  <ng-container *ngTemplateOutlet="template"></ng-container>
803
1348
  </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
804
1349
  }
805
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: RowLayout, decorators: [{
1350
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: RowLayout, decorators: [{
806
1351
  type: Component,
807
1352
  args: [{
808
1353
  selector: 'dfk-row-layout',
@@ -830,8 +1375,8 @@ class GridLayout {
830
1375
  get gap() {
831
1376
  return this.config?.gap ?? 12;
832
1377
  }
833
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GridLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
834
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: GridLayout, isStandalone: true, selector: "dfk-grid-layout", inputs: { config: "config", template: "template" }, ngImport: i0, template: `<div
1378
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: GridLayout, deps: [], target: i0.ɵɵFactoryTarget.Component });
1379
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: GridLayout, isStandalone: true, selector: "dfk-grid-layout", inputs: { config: "config", template: "template" }, ngImport: i0, template: `<div
835
1380
  [style.display]="'grid'"
836
1381
  [style.gridTemplateColumns]="'repeat(' + columns + ', 1fr)'"
837
1382
  [style.gap]="gap + 'px'"
@@ -839,7 +1384,7 @@ class GridLayout {
839
1384
  <ng-container *ngTemplateOutlet="template"></ng-container>
840
1385
  </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
841
1386
  }
842
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GridLayout, decorators: [{
1387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: GridLayout, decorators: [{
843
1388
  type: Component,
844
1389
  args: [{
845
1390
  selector: 'dfk-grid-layout',
@@ -863,8 +1408,8 @@ layoutRegistry.register('row', RowLayout);
863
1408
  layoutRegistry.register('grid', GridLayout);
864
1409
 
865
1410
  class DynamicFieldKitModule {
866
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DynamicFieldKitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
867
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: DynamicFieldKitModule, imports: [CommonModule,
1411
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicFieldKitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1412
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.25", ngImport: i0, type: DynamicFieldKitModule, imports: [CommonModule,
868
1413
  DynamicInput,
869
1414
  FieldInput,
870
1415
  MultiFieldInput,
@@ -876,7 +1421,7 @@ class DynamicFieldKitModule {
876
1421
  ColumnLayout,
877
1422
  RowLayout,
878
1423
  GridLayout] });
879
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DynamicFieldKitModule, imports: [CommonModule,
1424
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicFieldKitModule, imports: [CommonModule,
880
1425
  DynamicInput,
881
1426
  FieldInput,
882
1427
  MultiFieldInput,
@@ -884,7 +1429,7 @@ class DynamicFieldKitModule {
884
1429
  RowLayout,
885
1430
  GridLayout] });
886
1431
  }
887
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DynamicFieldKitModule, decorators: [{
1432
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: DynamicFieldKitModule, decorators: [{
888
1433
  type: NgModule,
889
1434
  args: [{
890
1435
  imports: [
@@ -914,5 +1459,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
914
1459
  * Generated bundle index. Do not edit.
915
1460
  */
916
1461
 
917
- export { BaseInputComponent, ColumnLayout, DynamicFieldKitModule, DynamicInput, FIELD_REGISTRY, FieldInput, GridLayout, LayoutRegistry, MultiFieldInput, RowLayout, layoutRegistry };
918
- //# sourceMappingURL=dynamic-field-kit-angular.mjs.map
1462
+ export { BaseInputComponent, ColumnLayout, DynamicFieldKitModule, DynamicFormDevToolsComponent, DynamicInput, FIELD_REGISTRY, FieldInput, GridLayout, LayoutRegistry, MultiFieldInput, RowLayout, createDynamicFormStore, layoutRegistry };