@ng-forge/dynamic-forms 0.3.1 → 0.5.0
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/README.md +5 -1
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs +37 -66
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-WGww2nXx.mjs} +3572 -346
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-WGww2nXx.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs → ng-forge-dynamic-forms-page-field.component-CrO9WTDw.mjs} +5 -5
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs.map → ng-forge-dynamic-forms-page-field.component-CrO9WTDw.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms-schema.mjs +92 -0
- package/fesm2022/ng-forge-dynamic-forms-schema.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-CfDZFTyf.mjs → ng-forge-dynamic-forms-text-field.component-BcFx_kOz.mjs} +5 -5
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-CfDZFTyf.mjs.map → ng-forge-dynamic-forms-text-field.component-BcFx_kOz.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
- package/package.json +13 -12
- package/types/ng-forge-dynamic-forms-integration.d.ts +61 -32
- package/types/ng-forge-dynamic-forms-schema.d.ts +178 -0
- package/types/ng-forge-dynamic-forms.d.ts +1173 -240
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-0iXHLraC.mjs +0 -31
- package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-0iXHLraC.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-testing.mjs +0 -971
- package/fesm2022/ng-forge-dynamic-forms-testing.mjs.map +0 -1
- package/types/ng-forge-dynamic-forms-testing.d.ts +0 -597
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { inject, DestroyRef, Injector, input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { NgComponentOutlet } from '@angular/common';
|
|
4
4
|
import { outputFromObservable } from '@angular/core/rxjs-interop';
|
|
5
|
-
import { i as injectFieldRegistry, E as EventBus, D as DynamicFormLogger, v as validatePageNesting, d as derivedFromDeferred, c as createFieldResolutionPipe, e as emitComponentInitialized } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-
|
|
5
|
+
import { i as injectFieldRegistry, E as EventBus, D as DynamicFormLogger, v as validatePageNesting, d as derivedFromDeferred, c as createFieldResolutionPipe, e as emitComponentInitialized } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-WGww2nXx.mjs';
|
|
6
6
|
import { explicitEffect } from 'ngxtension/explicit-effect';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -91,14 +91,14 @@ class PageFieldComponent {
|
|
|
91
91
|
}
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0
|
|
95
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0
|
|
94
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: PageFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
95
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: PageFieldComponent, isStandalone: true, selector: "section[page-field]", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: true, transformFunction: null }, isVisible: { classPropertyName: "isVisible", publicName: "isVisible", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { nextPage: "nextPage", previousPage: "previousPage", pageChange: "pageChange" }, host: { properties: { "class": "hostClasses()", "class.disabled": "disabled()", "class.df-page-visible": "isVisible()", "class.df-page-hidden": "!isVisible()", "attr.aria-hidden": "!isVisible()", "attr.data-page-index": "pageIndex()", "id": "`${key()}`", "attr.data-testid": "key()" } }, ngImport: i0, template: `
|
|
96
96
|
@for (field of resolvedFields(); track field.key) {
|
|
97
97
|
<ng-container *ngComponentOutlet="field.component; injector: field.injector; inputs: field.inputs()" />
|
|
98
98
|
}
|
|
99
99
|
`, isInline: true, styles: [":host,.df-form{--df-grid-columns: 12;--df-grid-gap: .5rem;--df-grid-row-gap: .5rem;--df-breakpoint-sm: 576px;--df-breakpoint-md: 768px;--df-breakpoint-lg: 992px;--df-breakpoint-xl: 1200px;--df-grid-gap-sm: .5rem;--df-grid-gap-md: .5rem;--df-grid-gap-lg: .5rem;--df-grid-gap-xl: .5rem;--df-grid-row-gap-sm: .5rem;--df-grid-row-gap-md: .5rem;--df-grid-row-gap-lg: .5rem;--df-grid-row-gap-xl: .5rem;--df-group-gap: var(--df-grid-gap);--df-group-padding: var(--df-grid-gap)}.df-form{display:grid;grid-template-columns:1fr;gap:var(--df-grid-row-gap);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);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);--df-grid-row-gap: var(--df-grid-row-gap-sm)}.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),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);--df-grid-row-gap: var(--df-grid-row-gap-md)}.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);--df-grid-row-gap: var(--df-grid-row-gap-lg)}.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);--df-grid-row-gap: var(--df-grid-row-gap-xl)}.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;width:100%;gap:var(--df-grid-row-gap);transition:opacity .2s ease-in-out}:host.df-page-spacing-custom{--df-grid-row-gap: var(--page-custom-spacing, 1.5rem)}:host.df-page-visible{opacity:1}:host.df-page-hidden{display:none;opacity:0;pointer-events:none}:host[aria-hidden=true]{pointer-events:none;visibility:hidden}@media(prefers-reduced-motion:no-preference){:host{transition:opacity .3s ease-in-out,transform .3s ease-in-out}:host.df-page-visible{transform:translate(0)}:host.df-page-hidden{transform:translate(-10px)}}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
100
100
|
}
|
|
101
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0
|
|
101
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: PageFieldComponent, decorators: [{
|
|
102
102
|
type: Component,
|
|
103
103
|
args: [{ selector: 'section[page-field]', imports: [NgComponentOutlet], template: `
|
|
104
104
|
@for (field of resolvedFields(); track field.key) {
|
|
@@ -117,4 +117,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
117
117
|
}], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], pageIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageIndex", required: true }] }], isVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "isVisible", required: true }] }], nextPage: [{ type: i0.Output, args: ["nextPage"] }], previousPage: [{ type: i0.Output, args: ["previousPage"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }] } });
|
|
118
118
|
|
|
119
119
|
export { PageFieldComponent as default };
|
|
120
|
-
//# sourceMappingURL=ng-forge-dynamic-forms-page-field.component-
|
|
120
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-page-field.component-CrO9WTDw.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs","sources":["../../../../packages/dynamic-forms/src/lib/fields/page/page-field.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, DestroyRef, inject, Injector, input } from '@angular/core';\nimport { NgComponentOutlet } from '@angular/common';\nimport { outputFromObservable } from '@angular/core/rxjs-interop';\nimport { derivedFromDeferred } from '../../utils/derived-from-deferred/derived-from-deferred';\nimport { createFieldResolutionPipe, ResolvedField } from '../../utils/resolve-field/resolve-field';\nimport { emitComponentInitialized } from '../../utils/emit-initialization/emit-initialization';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { PageField, validatePageNesting } from '../../definitions/default/page-field';\nimport { injectFieldRegistry } from '../../utils/inject-field-registry/inject-field-registry';\nimport { EventBus } from '../../events/event.bus';\nimport { NextPageEvent, PageChangeEvent, PreviousPageEvent } from '../../events/constants';\nimport { FieldDef } from '../../definitions/base/field-def';\nimport { DynamicFormLogger } from '../../providers/features/logger/logger.token';\n\n/**\n * Renders a single page in multi-page (wizard) forms.\n *\n * Visibility is controlled by the PageOrchestrator via the isVisible input.\n * Pages cannot be nested within other pages - validation prevents this.\n * Field values are flattened into the parent form (no nesting under page key).\n */\n@Component({\n selector: 'section[page-field]',\n imports: [NgComponentOutlet],\n template: `\n @for (field of resolvedFields(); track field.key) {\n <ng-container *ngComponentOutlet=\"field.component; injector: field.injector; inputs: field.inputs()\" />\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 private readonly eventBus = inject(EventBus);\n private readonly logger = inject(DynamicFormLogger);\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(() => {\n const base = 'df-field df-page-field';\n const custom = this.className();\n return custom ? `${base} ${custom}` : base;\n });\n\n readonly disabled = computed(() => this.field().disabled || false);\n\n readonly isValid = computed(() => {\n const pageField = this.field();\n const valid = validatePageNesting(pageField);\n\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 return valid;\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 // ─────────────────────────────────────────────────────────────────────────────\n // Constructor\n // ─────────────────────────────────────────────────────────────────────────────\n\n constructor() {\n this.setupEffects();\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n private setupEffects(): void {\n // Emit initialization event when fields are resolved\n explicitEffect([this.resolvedFields], ([fields]) => {\n if (fields.length > 0) {\n emitComponentInitialized(this.eventBus, 'page', this.field().key, this.injector);\n }\n });\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-page-field.component-CrO9WTDw.mjs","sources":["../../../../packages/dynamic-forms/src/lib/fields/page/page-field.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, DestroyRef, inject, Injector, input } from '@angular/core';\nimport { NgComponentOutlet } from '@angular/common';\nimport { outputFromObservable } from '@angular/core/rxjs-interop';\nimport { derivedFromDeferred } from '../../utils/derived-from-deferred/derived-from-deferred';\nimport { createFieldResolutionPipe, ResolvedField } from '../../utils/resolve-field/resolve-field';\nimport { emitComponentInitialized } from '../../utils/emit-initialization/emit-initialization';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { PageField, validatePageNesting } from '../../definitions/default/page-field';\nimport { injectFieldRegistry } from '../../utils/inject-field-registry/inject-field-registry';\nimport { EventBus } from '../../events/event.bus';\nimport { NextPageEvent, PageChangeEvent, PreviousPageEvent } from '../../events/constants';\nimport { FieldDef } from '../../definitions/base/field-def';\nimport { DynamicFormLogger } from '../../providers/features/logger/logger.token';\n\n/**\n * Renders a single page in multi-page (wizard) forms.\n *\n * Visibility is controlled by the PageOrchestrator via the isVisible input.\n * Pages cannot be nested within other pages - validation prevents this.\n * Field values are flattened into the parent form (no nesting under page key).\n */\n@Component({\n selector: 'section[page-field]',\n imports: [NgComponentOutlet],\n template: `\n @for (field of resolvedFields(); track field.key) {\n <ng-container *ngComponentOutlet=\"field.component; injector: field.injector; inputs: field.inputs()\" />\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 private readonly eventBus = inject(EventBus);\n private readonly logger = inject(DynamicFormLogger);\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(() => {\n const base = 'df-field df-page-field';\n const custom = this.className();\n return custom ? `${base} ${custom}` : base;\n });\n\n readonly disabled = computed(() => this.field().disabled || false);\n\n readonly isValid = computed(() => {\n const pageField = this.field();\n const valid = validatePageNesting(pageField);\n\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 return valid;\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 // ─────────────────────────────────────────────────────────────────────────────\n // Constructor\n // ─────────────────────────────────────────────────────────────────────────────\n\n constructor() {\n this.setupEffects();\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n private setupEffects(): void {\n // Emit initialization event when fields are resolved\n explicitEffect([this.resolvedFields], ([fields]) => {\n if (fields.length > 0) {\n emitComponentInitialized(this.eventBus, 'page', this.field().key, this.injector);\n }\n });\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal marker symbol to identify StandardSchemaMarker instances.
|
|
3
|
+
* Uses ɵ prefix following Angular's convention for internal APIs.
|
|
4
|
+
*/
|
|
5
|
+
const STANDARD_SCHEMA_KIND = 'standardSchema';
|
|
6
|
+
/**
|
|
7
|
+
* Wraps a Standard Schema compliant schema for use with dynamic forms.
|
|
8
|
+
*
|
|
9
|
+
* This function creates a marker wrapper around schemas that implement the
|
|
10
|
+
* Standard Schema spec (Zod, Valibot, ArkType, etc.), allowing the dynamic
|
|
11
|
+
* forms system to identify and use them for validation.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - The inferred type that the schema validates to
|
|
14
|
+
* @param schema - A schema implementing the Standard Schema V1 spec
|
|
15
|
+
* @returns A wrapped schema marker that can be passed to dynamic form configuration
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { z } from 'zod';
|
|
20
|
+
* import { standardSchema } from '@ng-forge/dynamic-forms/schema';
|
|
21
|
+
*
|
|
22
|
+
* const loginSchema = z.object({
|
|
23
|
+
* email: z.string().email('Invalid email format'),
|
|
24
|
+
* password: z.string().min(8, 'Password must be at least 8 characters'),
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Wrap for use with dynamic forms
|
|
28
|
+
* const formSchema = standardSchema(loginSchema);
|
|
29
|
+
*
|
|
30
|
+
* // Use in form configuration
|
|
31
|
+
* const formConfig = {
|
|
32
|
+
* schema: formSchema,
|
|
33
|
+
* fields: [
|
|
34
|
+
* input({ key: 'email', label: 'Email' }),
|
|
35
|
+
* input({ key: 'password', label: 'Password', props: { type: 'password' } }),
|
|
36
|
+
* ],
|
|
37
|
+
* };
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function standardSchema(schema) {
|
|
41
|
+
return {
|
|
42
|
+
ɵkind: STANDARD_SCHEMA_KIND,
|
|
43
|
+
schema,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Type guard to check if a value is a StandardSchemaMarker.
|
|
48
|
+
*
|
|
49
|
+
* This is useful when processing form configuration to determine if a schema
|
|
50
|
+
* has been provided and should be used for validation.
|
|
51
|
+
*
|
|
52
|
+
* @param value - The value to check
|
|
53
|
+
* @returns True if the value is a StandardSchemaMarker, false otherwise
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import { isStandardSchemaMarker } from '@ng-forge/dynamic-forms/schema';
|
|
58
|
+
*
|
|
59
|
+
* function processFormConfig(config: FormConfig) {
|
|
60
|
+
* if (config.schema && isStandardSchemaMarker(config.schema)) {
|
|
61
|
+
* // Use the schema for validation
|
|
62
|
+
* const result = config.schema.schema['~standard'].validate(formValue);
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function isStandardSchemaMarker(value) {
|
|
68
|
+
return (typeof value === 'object' &&
|
|
69
|
+
value !== null &&
|
|
70
|
+
'ɵkind' in value &&
|
|
71
|
+
value.ɵkind === STANDARD_SCHEMA_KIND &&
|
|
72
|
+
'schema' in value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @ng-forge/dynamic-forms/schema
|
|
77
|
+
*
|
|
78
|
+
* Schema integration API for using Standard Schema compliant validation libraries
|
|
79
|
+
* (Zod, Valibot, ArkType, etc.) with dynamic forms.
|
|
80
|
+
*
|
|
81
|
+
* This entrypoint provides:
|
|
82
|
+
* - `standardSchema()` - Wrapper function to mark schemas for use with forms
|
|
83
|
+
* - `isStandardSchemaMarker()` - Type guard for schema detection
|
|
84
|
+
* - Type definitions for form schema configuration
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Generated bundle index. Do not edit.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
export { isStandardSchemaMarker, standardSchema };
|
|
92
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-schema.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-schema.mjs","sources":["../../../../packages/dynamic-forms/schema/src/standard-schema-marker.ts","../../../../packages/dynamic-forms/schema/src/public_api.ts","../../../../packages/dynamic-forms/schema/src/ng-forge-dynamic-forms-schema.ts"],"sourcesContent":["import type { SchemaPath, SchemaPathTree } from '@angular/forms/signals';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\n\n/**\n * Internal marker symbol to identify StandardSchemaMarker instances.\n * Uses ɵ prefix following Angular's convention for internal APIs.\n */\nexport const STANDARD_SCHEMA_KIND = 'standardSchema' as const;\n\n/**\n * Angular schema callback function type.\n * This is the raw callback that Angular's schema() function accepts.\n *\n * Use this when you want to write Angular schema validation directly\n * without any wrapper. This is ideal for Angular-only projects that\n * want full access to Angular's form validation APIs.\n *\n * @typeParam T - The form value type\n *\n * @example\n * ```typescript\n * import { FormConfig } from '@ng-forge/dynamic-forms';\n * import { validateTree } from '@angular/forms/signals';\n *\n * const config = {\n * // Raw callback - no wrapper needed!\n * schema: (path) => {\n * validateTree(path, (ctx) => {\n * const { password, confirmPassword } = ctx.value();\n * if (password !== confirmPassword) {\n * return [{ kind: 'passwordMismatch', fieldTree: ctx.fieldTreeOf(path).confirmPassword }];\n * }\n * return null;\n * });\n * },\n * fields: [\n * { key: 'password', type: 'input', label: 'Password', required: true },\n * { key: 'confirmPassword', type: 'input', label: 'Confirm', required: true,\n * validationMessages: { passwordMismatch: 'Passwords must match' } },\n * ],\n * } as const satisfies FormConfig;\n * ```\n */\nexport type AngularSchemaCallback<T = unknown> = (path: SchemaPath<T> & SchemaPathTree<T>) => void;\n\n/**\n * Wrapper interface that marks a schema as implementing the Standard Schema spec.\n * This allows the dynamic forms system to identify and use standard-compliant schemas\n * for validation without coupling to any specific schema library.\n *\n * The `out` variance modifier makes this type covariant in T, meaning a\n * StandardSchemaMarker<SpecificType> is assignable to StandardSchemaMarker<BroaderType>.\n * This enables Zod/Valibot schemas to be used with FormConfig's inferred TValue.\n *\n * @typeParam T - The inferred type that the schema validates to (covariant)\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n * import { standardSchema } from '@ng-forge/dynamic-forms/schema';\n *\n * const userSchema = z.object({\n * name: z.string(),\n * email: z.string().email(),\n * });\n *\n * // Wrap the Zod schema with standardSchema marker\n * const formSchema = standardSchema(userSchema);\n * ```\n */\nexport interface StandardSchemaMarker<out T = unknown> {\n /**\n * Internal marker identifying this as a standard schema wrapper.\n * @internal\n */\n readonly ɵkind: typeof STANDARD_SCHEMA_KIND;\n\n /**\n * The underlying schema that implements the Standard Schema spec.\n */\n readonly schema: StandardSchemaV1<T>;\n}\n\n/**\n * Type alias for form schemas that can be used with dynamic forms.\n * Supports both Standard Schema compliant schemas (Zod, Valibot, ArkType)\n * and raw Angular schema callbacks.\n *\n * The covariance from StandardSchemaMarker flows through, allowing\n * schemas with specific types to be assigned to broader form value types.\n *\n * @typeParam T - The inferred type that the schema validates to\n *\n * @example Standard Schema (Zod)\n * ```typescript\n * import { z } from 'zod';\n * import { standardSchema } from '@ng-forge/dynamic-forms/schema';\n *\n * const config = {\n * schema: standardSchema(z.object({ ... })),\n * fields: [...],\n * };\n * ```\n *\n * @example Angular Schema Callback\n * ```typescript\n * import { validateTree } from '@angular/forms/signals';\n *\n * const config = {\n * schema: (path) => {\n * validateTree(path, (ctx) => { ... });\n * },\n * fields: [...],\n * };\n * ```\n */\nexport type FormSchema<T = unknown> = StandardSchemaMarker<T> | AngularSchemaCallback<T>;\n\n/**\n * Wraps a Standard Schema compliant schema for use with dynamic forms.\n *\n * This function creates a marker wrapper around schemas that implement the\n * Standard Schema spec (Zod, Valibot, ArkType, etc.), allowing the dynamic\n * forms system to identify and use them for validation.\n *\n * @typeParam T - The inferred type that the schema validates to\n * @param schema - A schema implementing the Standard Schema V1 spec\n * @returns A wrapped schema marker that can be passed to dynamic form configuration\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n * import { standardSchema } from '@ng-forge/dynamic-forms/schema';\n *\n * const loginSchema = z.object({\n * email: z.string().email('Invalid email format'),\n * password: z.string().min(8, 'Password must be at least 8 characters'),\n * });\n *\n * // Wrap for use with dynamic forms\n * const formSchema = standardSchema(loginSchema);\n *\n * // Use in form configuration\n * const formConfig = {\n * schema: formSchema,\n * fields: [\n * input({ key: 'email', label: 'Email' }),\n * input({ key: 'password', label: 'Password', props: { type: 'password' } }),\n * ],\n * };\n * ```\n */\nexport function standardSchema<T>(schema: StandardSchemaV1<T>): StandardSchemaMarker<T> {\n return {\n ɵkind: STANDARD_SCHEMA_KIND,\n schema,\n };\n}\n\n/**\n * Type guard to check if a value is a StandardSchemaMarker.\n *\n * This is useful when processing form configuration to determine if a schema\n * has been provided and should be used for validation.\n *\n * @param value - The value to check\n * @returns True if the value is a StandardSchemaMarker, false otherwise\n *\n * @example\n * ```typescript\n * import { isStandardSchemaMarker } from '@ng-forge/dynamic-forms/schema';\n *\n * function processFormConfig(config: FormConfig) {\n * if (config.schema && isStandardSchemaMarker(config.schema)) {\n * // Use the schema for validation\n * const result = config.schema.schema['~standard'].validate(formValue);\n * }\n * }\n * ```\n */\nexport function isStandardSchemaMarker(value: unknown): value is StandardSchemaMarker {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'ɵkind' in value &&\n (value as StandardSchemaMarker).ɵkind === STANDARD_SCHEMA_KIND &&\n 'schema' in value\n );\n}\n\n/**\n * Extracts the output type from a Standard Schema.\n * Works with Zod, Valibot, ArkType, and other Standard Schema compliant libraries.\n */\nexport type InferSchemaOutput<T> = T extends StandardSchemaV1<infer Output> ? Output : never;\n","/**\n * @ng-forge/dynamic-forms/schema\n *\n * Schema integration API for using Standard Schema compliant validation libraries\n * (Zod, Valibot, ArkType, etc.) with dynamic forms.\n *\n * This entrypoint provides:\n * - `standardSchema()` - Wrapper function to mark schemas for use with forms\n * - `isStandardSchemaMarker()` - Type guard for schema detection\n * - Type definitions for form schema configuration\n */\n\nexport { standardSchema, isStandardSchemaMarker } from './standard-schema-marker';\nexport type { StandardSchemaMarker, FormSchema, InferSchemaOutput, AngularSchemaCallback } from './standard-schema-marker';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"AAGA;;;AAGG;AACI,MAAM,oBAAoB,GAAG,gBAAyB;AA+G7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;AACG,SAAU,cAAc,CAAI,MAA2B,EAAA;IAC3D,OAAO;AACL,QAAA,KAAK,EAAE,oBAAoB;QAC3B,MAAM;KACP;AACH;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,sBAAsB,CAAC,KAAc,EAAA;AACnD,IAAA,QACE,OAAO,KAAK,KAAK,QAAQ;AACzB,QAAA,KAAK,KAAK,IAAI;AACd,QAAA,OAAO,IAAI,KAAK;QACf,KAA8B,CAAC,KAAK,KAAK,oBAAoB;QAC9D,QAAQ,IAAI,KAAK;AAErB;;AC5LA;;;;;;;;;;AAUG;;ACVH;;AAEG;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { AsyncPipe } from '@angular/common';
|
|
4
|
-
import { a as DynamicTextPipe } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-
|
|
4
|
+
import { a as DynamicTextPipe } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-WGww2nXx.mjs';
|
|
5
5
|
|
|
6
6
|
class TextFieldComponent {
|
|
7
7
|
key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
|
|
@@ -11,8 +11,8 @@ class TextFieldComponent {
|
|
|
11
11
|
hidden = input(...(ngDevMode ? [undefined, { debugName: "hidden" }] : []));
|
|
12
12
|
props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
|
|
13
13
|
elementType = computed(() => this.props()?.elementType || 'p', ...(ngDevMode ? [{ debugName: "elementType" }] : []));
|
|
14
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0
|
|
15
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0
|
|
14
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TextFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
15
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TextFieldComponent, isStandalone: true, selector: "df-text", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "hidden() || null" } }, ngImport: i0, template: `
|
|
16
16
|
@switch (elementType()) {
|
|
17
17
|
@case ('p') {
|
|
18
18
|
<p class="df-text df-text-p" [class]="className() || ''">
|
|
@@ -57,7 +57,7 @@ class TextFieldComponent {
|
|
|
57
57
|
}
|
|
58
58
|
`, isInline: true, styles: [":host([hidden]){display:none!important}.df-text{font-size:var(--df-text-font-size, 1rem);font-family:var(--df-text-font-family, inherit);font-weight:var(--df-text-font-weight, normal);color:var(--df-text-color, inherit);line-height:var(--df-text-line-height, 1.5);text-align:var(--df-text-text-align, inherit);letter-spacing:var(--df-text-letter-spacing, normal);text-decoration:var(--df-text-text-decoration, none);text-transform:var(--df-text-text-transform, none);margin:var(--df-text-margin, 0);padding:var(--df-text-padding, 0)}.df-text-h1{font-size:var(--df-text-h1-font-size, 2rem);font-weight:var(--df-text-h1-font-weight, bold);margin:var(--df-text-h1-margin, 0)}.df-text-h2{font-size:var(--df-text-h2-font-size, 1.75rem);font-weight:var(--df-text-h2-font-weight, bold);margin:var(--df-text-h2-margin, 0)}.df-text-h3{font-size:var(--df-text-h3-font-size, 1.5rem);font-weight:var(--df-text-h3-font-weight, bold);margin:var(--df-text-h3-margin, 0)}.df-text-h4{font-size:var(--df-text-h4-font-size, 1.25rem);font-weight:var(--df-text-h4-font-weight, bold);margin:var(--df-text-h4-margin, 0)}.df-text-h5{font-size:var(--df-text-h5-font-size, 1.125rem);font-weight:var(--df-text-h5-font-weight, bold);margin:var(--df-text-h5-margin, 0)}.df-text-h6{font-size:var(--df-text-h6-font-size, 1rem);font-weight:var(--df-text-h6-font-weight, bold);margin:var(--df-text-h6-margin, 0)}.df-text-p{font-size:var(--df-text-p-font-size, 1rem);margin:var(--df-text-p-margin, 0)}.df-text-span{display:var(--df-text-span-display, inline)}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
59
59
|
}
|
|
60
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0
|
|
60
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TextFieldComponent, decorators: [{
|
|
61
61
|
type: Component,
|
|
62
62
|
args: [{ selector: 'df-text', template: `
|
|
63
63
|
@switch (elementType()) {
|
|
@@ -110,4 +110,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
|
|
|
110
110
|
}], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }] } });
|
|
111
111
|
|
|
112
112
|
export { TextFieldComponent as default };
|
|
113
|
-
//# sourceMappingURL=ng-forge-dynamic-forms-text-field.component-
|
|
113
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-text-field.component-BcFx_kOz.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-text-field.component-
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-text-field.component-BcFx_kOz.mjs","sources":["../../../../packages/dynamic-forms/src/lib/fields/text/text-field.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { AsyncPipe } from '@angular/common';\nimport { DynamicTextPipe } from '../../pipes/dynamic-text/dynamic-text.pipe';\nimport { TextProps } from '../../definitions/default/text-field';\nimport { DynamicText } from '../../models/types/dynamic-text';\n\n@Component({\n selector: 'df-text',\n template: `\n @switch (elementType()) {\n @case ('p') {\n <p class=\"df-text df-text-p\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </p>\n }\n @case ('h1') {\n <h1 class=\"df-text df-text-h1\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </h1>\n }\n @case ('h2') {\n <h2 class=\"df-text df-text-h2\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </h2>\n }\n @case ('h3') {\n <h3 class=\"df-text df-text-h3\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </h3>\n }\n @case ('h4') {\n <h4 class=\"df-text df-text-h4\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </h4>\n }\n @case ('h5') {\n <h5 class=\"df-text df-text-h5\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </h5>\n }\n @case ('h6') {\n <h6 class=\"df-text df-text-h6\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </h6>\n }\n @case ('span') {\n <span class=\"df-text df-text-span\" [class]=\"className() || ''\">\n {{ label() | dynamicText | async }}\n </span>\n }\n }\n `,\n styleUrl: './text-field.component.scss',\n imports: [AsyncPipe, DynamicTextPipe],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[id]': '`${key()}`',\n '[attr.data-testid]': 'key()',\n '[attr.hidden]': 'hidden() || null',\n },\n})\nexport default class TextFieldComponent {\n readonly key = input.required<string>();\n readonly label = input.required<DynamicText>();\n readonly className = input<string>();\n readonly tabIndex = input<number>();\n readonly hidden = input<boolean>();\n readonly props = input<TextProps>();\n\n readonly elementType = computed(() => this.props()?.elementType || 'p');\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { Q as ARRAY_CONTEXT, A as AddArrayItemEvent, Y as ArrayFieldComponent, a3 as BUILT_IN_FIELDS, C as ConsoleLogger, T as DEFAULT_PROPS, U as DEFAULT_VALIDATION_MESSAGES, b as DynamicForm, B as DynamicFormError, D as DynamicFormLogger, a as DynamicTextPipe, E as EventBus, O as FIELD_REGISTRY, V as FIELD_SIGNAL_CONTEXT, W as FORM_OPTIONS, F as FormClearEvent, u as FormResetEvent, Z as GroupFieldComponent, x as NextPageEvent, N as NoopLogger, P as PageChangeEvent, y as PreviousPageEvent, R as RemoveArrayItemEvent, a8 as RootFormRegistryService, _ as RowFieldComponent, S as SubmitEvent, a7 as applyMetaToElement, $ as applyValidator, a0 as applyValidators, I as arrayFieldMapper, G as baseFieldMapper, H as buildBaseInputs, X as dynamicTextToObservable, z as formConfig, a1 as getArrayLength, J as groupFieldMapper, a6 as interpolateParams, l as isArrayField, h as isCheckedField, m as isContainerField, n as isDisplayOnlyField, a4 as isEqual, f as isFormStateCondition, o as isGroupField, q as isLeafField, s as isPageField, k as isRowField, t as isValueBearingField, j as isValueField, a5 as omit, K as pageFieldMapper, p as provideDynamicForm, g as resolveNextButtonDisabled, r as resolveSubmitButtonDisabled, a2 as resolveTokens, L as rowFieldMapper, M as textFieldMapper, w as withLoggerConfig } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-WGww2nXx.mjs';
|
|
2
2
|
//# sourceMappingURL=ng-forge-dynamic-forms.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-forge/dynamic-forms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Type-safe, signal-powered dynamic forms for Angular. Build complex forms from configuration with full TypeScript inference.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,15 +31,19 @@
|
|
|
31
31
|
],
|
|
32
32
|
"sideEffects": false,
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
34
|
+
"node": ">=20"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@angular/common": "
|
|
38
|
-
"@angular/core": "
|
|
39
|
-
"@angular/forms": "
|
|
40
|
-
"
|
|
37
|
+
"@angular/common": "~21.1.0",
|
|
38
|
+
"@angular/core": "~21.1.0",
|
|
39
|
+
"@angular/forms": "~21.1.0",
|
|
40
|
+
"@standard-schema/spec": "^1.0.0",
|
|
41
41
|
"rxjs": ">=7.0.0"
|
|
42
42
|
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"ngxtension": ">=4.0.0",
|
|
45
|
+
"tslib": "^2.3.0"
|
|
46
|
+
},
|
|
43
47
|
"module": "fesm2022/ng-forge-dynamic-forms.mjs",
|
|
44
48
|
"typings": "types/ng-forge-dynamic-forms.d.ts",
|
|
45
49
|
"exports": {
|
|
@@ -54,12 +58,9 @@
|
|
|
54
58
|
"types": "./types/ng-forge-dynamic-forms-integration.d.ts",
|
|
55
59
|
"default": "./fesm2022/ng-forge-dynamic-forms-integration.mjs"
|
|
56
60
|
},
|
|
57
|
-
"./
|
|
58
|
-
"types": "./types/ng-forge-dynamic-forms-
|
|
59
|
-
"default": "./fesm2022/ng-forge-dynamic-forms-
|
|
61
|
+
"./schema": {
|
|
62
|
+
"types": "./types/ng-forge-dynamic-forms-schema.d.ts",
|
|
63
|
+
"default": "./fesm2022/ng-forge-dynamic-forms-schema.mjs"
|
|
60
64
|
}
|
|
61
|
-
},
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"tslib": "^2.3.0"
|
|
64
65
|
}
|
|
65
66
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FormEvent, FieldDef, FormEventConstructor, BaseCheckedField, BaseValueField, DynamicText, FieldMeta, FieldOption, ValidationMessages } from '@ng-forge/dynamic-forms';
|
|
2
|
-
|
|
3
|
-
import { Signal, Injector, ElementRef
|
|
2
|
+
export { isEqual } from '@ng-forge/dynamic-forms';
|
|
3
|
+
import { Signal, Injector, ElementRef } from '@angular/core';
|
|
4
4
|
import { FieldTree } from '@angular/forms/signals';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -132,30 +132,69 @@ interface InputMeta extends FieldMeta {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* HTML input types
|
|
135
|
+
* All valid HTML input types per MDN specification.
|
|
136
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types
|
|
136
137
|
*/
|
|
137
|
-
type
|
|
138
|
+
type HtmlInputType = 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'datetime-local' | 'month' | 'week' | 'time' | 'color' | 'range' | 'checkbox' | 'radio' | 'file' | 'hidden' | 'button' | 'submit' | 'reset' | 'image';
|
|
138
139
|
/**
|
|
139
|
-
*
|
|
140
|
+
* Input types supported by InputField.
|
|
141
|
+
* Other HTML input types have dedicated field implementations:
|
|
142
|
+
* - checkbox → CheckboxField
|
|
143
|
+
* - radio → RadioField
|
|
144
|
+
* - range → SliderField
|
|
145
|
+
* - date/time → DatepickerField
|
|
146
|
+
* - file, hidden, button, etc. → dedicated fields
|
|
140
147
|
*/
|
|
141
|
-
type
|
|
148
|
+
type InputType = Extract<HtmlInputType, 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search'>;
|
|
142
149
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
150
|
+
* Infers the TypeScript value type for a given input type.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* type NumberValue = InferInputValue<'number'>; // number
|
|
154
|
+
* type TextValue = InferInputValue<'text'>; // string
|
|
155
|
+
* type DateValue = InferInputValue<'date'>; // string (extended types)
|
|
156
|
+
*/
|
|
157
|
+
type InferInputValue<T extends HtmlInputType> = T extends 'number' ? number : string;
|
|
158
|
+
/**
|
|
159
|
+
* @deprecated Use `InferInputValue` instead. Will be removed in v1.0.0.
|
|
160
|
+
*/
|
|
161
|
+
type InputTypeToValueType<T extends InputType> = InferInputValue<T>;
|
|
162
|
+
/**
|
|
163
|
+
* Props for input fields with optional type specification.
|
|
164
|
+
* Generic parameter allows extending InputType with additional HtmlInputType values.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* // Default usage
|
|
168
|
+
* interface MyProps extends InputProps { ... }
|
|
169
|
+
*
|
|
170
|
+
* // Extended input types (e.g., supporting date inputs)
|
|
171
|
+
* type ExtendedType = InputType | 'date' | 'time';
|
|
172
|
+
* interface ExtendedProps extends InputProps<ExtendedType> { ... }
|
|
145
173
|
*/
|
|
146
|
-
interface InputProps<T extends
|
|
174
|
+
interface InputProps<T extends HtmlInputType = InputType> {
|
|
147
175
|
/**
|
|
148
176
|
* The HTML input type. Determines the value type:
|
|
149
177
|
* - 'number': value will be number
|
|
150
|
-
* -
|
|
178
|
+
* - All other types: value will be string
|
|
151
179
|
*/
|
|
152
180
|
type?: T;
|
|
153
181
|
placeholder?: DynamicText;
|
|
154
182
|
}
|
|
155
183
|
/**
|
|
156
|
-
* Input types that produce
|
|
184
|
+
* Input types that produce numeric values.
|
|
185
|
+
* Currently only 'number' produces a numeric value in HTML inputs.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* type Numeric = NumericInputType; // 'number'
|
|
189
|
+
*/
|
|
190
|
+
type NumericInputType<T extends HtmlInputType = InputType> = Extract<T, 'number'>;
|
|
191
|
+
/**
|
|
192
|
+
* Input types that produce string values.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* type Strings = StringInputType; // Exclude<InputType, 'number'>
|
|
157
196
|
*/
|
|
158
|
-
type StringInputType = Exclude<
|
|
197
|
+
type StringInputType<T extends HtmlInputType = InputType> = Exclude<T, 'number'>;
|
|
159
198
|
/**
|
|
160
199
|
* Number input field with strict number value type.
|
|
161
200
|
* When props.type is 'number', value must be number.
|
|
@@ -179,11 +218,11 @@ interface NumberInputField<TProps extends {
|
|
|
179
218
|
interface StringInputField<TProps extends {
|
|
180
219
|
type?: string;
|
|
181
220
|
} = InputProps> extends BaseValueField<TProps & {
|
|
182
|
-
type?:
|
|
221
|
+
type?: Exclude<TProps['type'], 'number'>;
|
|
183
222
|
}, string, InputMeta> {
|
|
184
223
|
type: 'input';
|
|
185
224
|
props?: TProps & {
|
|
186
|
-
type?:
|
|
225
|
+
type?: Exclude<TProps['type'], 'number'>;
|
|
187
226
|
};
|
|
188
227
|
}
|
|
189
228
|
/**
|
|
@@ -345,21 +384,20 @@ interface ToggleField<TProps> extends BaseCheckedField<TProps> {
|
|
|
345
384
|
}
|
|
346
385
|
|
|
347
386
|
/**
|
|
348
|
-
* Context for value field mapping, containing resolved field tree
|
|
387
|
+
* Context for value field mapping, containing resolved field tree.
|
|
349
388
|
* Used by specialized mappers to avoid duplicate context resolution.
|
|
350
389
|
*/
|
|
351
390
|
interface ValueFieldContext {
|
|
352
391
|
fieldTree: FieldTree<unknown> | undefined;
|
|
353
|
-
defaultValidationMessages: ValidationMessages | undefined;
|
|
354
392
|
}
|
|
355
393
|
/**
|
|
356
|
-
* Resolves the field tree
|
|
394
|
+
* Resolves the field tree from the form context.
|
|
357
395
|
* Must be called within an injection context.
|
|
358
396
|
*
|
|
359
397
|
* Uses type-safe field tree utilities to access child FieldTrees from the parent form.
|
|
360
398
|
*
|
|
361
399
|
* @param fieldKey The key of the field to resolve
|
|
362
|
-
* @returns The resolved context with field tree
|
|
400
|
+
* @returns The resolved context with field tree
|
|
363
401
|
*/
|
|
364
402
|
declare function resolveValueFieldContext(fieldKey: string): ValueFieldContext;
|
|
365
403
|
/**
|
|
@@ -368,9 +406,11 @@ declare function resolveValueFieldContext(fieldKey: string): ValueFieldContext;
|
|
|
368
406
|
*
|
|
369
407
|
* @param fieldDef The value field definition
|
|
370
408
|
* @param ctx The resolved value field context
|
|
409
|
+
* @param defaultProps Default props from the form configuration (may be undefined if not configured)
|
|
410
|
+
* @param defaultValidationMessages Default validation messages from the form configuration (may be undefined if not configured)
|
|
371
411
|
* @returns Record of input names to values
|
|
372
412
|
*/
|
|
373
|
-
declare function buildValueFieldInputs<TProps, TValue = unknown>(fieldDef: BaseValueField<TProps, TValue>, ctx: ValueFieldContext): Record<string, unknown>;
|
|
413
|
+
declare function buildValueFieldInputs<TProps, TValue = unknown>(fieldDef: BaseValueField<TProps, TValue>, ctx: ValueFieldContext, defaultProps?: Record<string, unknown>, defaultValidationMessages?: ValidationMessages): Record<string, unknown>;
|
|
374
414
|
/**
|
|
375
415
|
* Maps a value field definition to component inputs.
|
|
376
416
|
*
|
|
@@ -463,11 +503,6 @@ declare function createResolvedErrorsSignal<T>(field: Signal<FieldTree<T>>, vali
|
|
|
463
503
|
*/
|
|
464
504
|
declare function shouldShowErrors<T>(field: Signal<FieldTree<T>>): Signal<boolean>;
|
|
465
505
|
|
|
466
|
-
/**
|
|
467
|
-
* Performs a deep equality comparison between two values
|
|
468
|
-
*/
|
|
469
|
-
declare function isEqual(a: unknown, b: unknown): boolean;
|
|
470
|
-
|
|
471
506
|
/**
|
|
472
507
|
* Configuration options for setupMetaTracking.
|
|
473
508
|
*/
|
|
@@ -533,11 +568,5 @@ interface MetaTrackingOptions {
|
|
|
533
568
|
*/
|
|
534
569
|
declare function setupMetaTracking(elementRef: ElementRef<HTMLElement>, meta: Signal<FieldMeta | undefined>, options?: MetaTrackingOptions): void;
|
|
535
570
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<ValueInArrayPipe, never>;
|
|
539
|
-
static ɵpipe: i0.ɵɵPipeDeclaration<ValueInArrayPipe, "inArray", true>;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
export { ValueInArrayPipe, buildValueFieldInputs, checkboxFieldMapper, createResolvedErrorsSignal, datepickerFieldMapper, isEqual, optionsFieldMapper, resolveValueFieldContext, setupMetaTracking, shouldShowErrors, valueFieldMapper };
|
|
543
|
-
export type { Autocapitalize, AutocompleteValue, ButtonField, CheckboxField, DatepickerField, DatepickerProps, EnterKeyHint, EventArgs, FieldWithOptions, InputField, InputMeta, InputMode, InputProps, InputType, InputTypeToValueType, MetaTrackingOptions, MultiCheckboxField, RadioField, ResolvedError, SelectField, SelectProps, SliderField, StringInputType, TextareaField, TextareaMeta, TextareaProps, TextareaWrap, ToggleField, ValueFieldContext };
|
|
571
|
+
export { buildValueFieldInputs, checkboxFieldMapper, createResolvedErrorsSignal, datepickerFieldMapper, optionsFieldMapper, resolveValueFieldContext, setupMetaTracking, shouldShowErrors, valueFieldMapper };
|
|
572
|
+
export type { Autocapitalize, AutocompleteValue, ButtonField, CheckboxField, DatepickerField, DatepickerProps, EnterKeyHint, EventArgs, FieldWithOptions, HtmlInputType, InferInputValue, InputField, InputMeta, InputMode, InputProps, InputType, InputTypeToValueType, MetaTrackingOptions, MultiCheckboxField, NumericInputType, RadioField, ResolvedError, SelectField, SelectProps, SliderField, StringInputType, TextareaField, TextareaMeta, TextareaProps, TextareaWrap, ToggleField, ValueFieldContext };
|