@dynamic-field-kit/angular 1.2.10 → 1.4.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/CHANGELOG.md +19 -0
- package/README.md +113 -4
- package/dist/README.md +113 -4
- package/dist/components/BaseInput.d.ts +23 -11
- package/dist/components/DynamicInput.d.ts +19 -8
- package/dist/components/FieldInput.d.ts +15 -7
- package/dist/components/MultiFieldInput.d.ts +30 -4
- package/dist/esm2022/components/BaseInput.mjs +17 -18
- package/dist/esm2022/components/DynamicInput.mjs +166 -84
- package/dist/esm2022/components/FieldInput.mjs +54 -26
- package/dist/esm2022/components/MultiFieldInput.mjs +282 -29
- package/dist/esm2022/fieldRegistryToken.mjs +12 -0
- package/dist/esm2022/layout/defaultLayouts.mjs +70 -23
- package/dist/esm2022/layout/index.mjs +2 -1
- package/dist/esm2022/layout/layoutRegistry.mjs +14 -0
- package/dist/esm2022/public-api.mjs +6 -2
- package/dist/esm2022/types/layout.mjs +1 -1
- package/dist/fesm2022/dynamic-field-kit-angular.mjs +604 -173
- package/dist/fesm2022/dynamic-field-kit-angular.mjs.map +1 -1
- package/dist/fieldRegistryToken.d.ts +3 -0
- package/dist/layout/defaultLayouts.d.ts +21 -3
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/layoutRegistry.d.ts +12 -0
- package/dist/public-api.d.ts +5 -2
- package/dist/types/layout.d.ts +4 -1
- package/package.json +19 -8
- package/src/components/BaseInput.ts +36 -10
- package/src/components/DynamicInput.ts +196 -104
- package/src/components/FieldInput.ts +43 -18
- package/src/components/MultiFieldInput.ts +275 -19
- package/src/fieldRegistryToken.ts +15 -0
- package/src/layout/defaultLayouts.ts +42 -10
- package/src/layout/index.ts +1 -0
- package/src/layout/layoutRegistry.ts +25 -0
- package/src/public-api.ts +40 -24
- package/src/types/layout.ts +14 -1
- package/test/DynamicInput.spec.ts +230 -0
- package/test/FieldInput.spec.ts +146 -0
- package/test/MultiFieldInput.spec.ts +256 -0
- package/test/helpers/renderers.ts +89 -0
- package/test/layout.spec.ts +119 -0
- package/test/publicApi.spec.ts +64 -0
- package/test/setup.ts +12 -0
- package/test/smoke.spec.ts +27 -0
- package/tsconfig.json +13 -13
- package/tsconfig.spec.json +9 -0
- package/vitest.config.ts +30 -0
- package/src/adapters/tailwind.ts +0 -13
- package/src/components/imports.ts +0 -3
- package/src/examples/index.ts +0 -4
- package/src/examples/registerExample.ts +0 -7
- package/src/examples/text-field.component.ts +0 -18
- package/src/types.ts +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @dynamic-field-kit/angular
|
|
2
|
+
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 132f74b: Framework adapters: validation support, scoped field registries via dependency
|
|
8
|
+
injection, and unified cross-framework layout types.
|
|
9
|
+
|
|
10
|
+
- Validation wired through `DynamicInput` / `FieldInput` / `MultiFieldInput`.
|
|
11
|
+
- Scoped `FieldRegistry` injection (React context, Vue provide/inject, Angular
|
|
12
|
+
`FIELD_REGISTRY` token) so consumers can supply their own registry.
|
|
13
|
+
- Shared layout type definitions aligned across React, Vue, and Angular.
|
|
14
|
+
|
|
15
|
+
Requires `@dynamic-field-kit/core@^1.3.0` (peer dependency) for the new
|
|
16
|
+
validation and layout APIs.
|
|
17
|
+
|
|
18
|
+
Note: `@dynamic-field-kit/core` is a peer dependency (not bundled). Consumers
|
|
19
|
+
must install it alongside the adapter.
|
package/README.md
CHANGED
|
@@ -12,9 +12,7 @@ Demo app: https://github.com/vannt-dev/dynamic-field-kit-demo
|
|
|
12
12
|
npm install @dynamic-field-kit/core @dynamic-field-kit/angular
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Note:
|
|
16
|
-
|
|
17
|
-
- Install with core: `npm install @dynamic-field-kit/core @dynamic-field-kit/angular`
|
|
15
|
+
Note: `@dynamic-field-kit/core`, `@angular/core`, and `@angular/common` are **peer dependencies** — this adapter does not bundle or auto-install them, so add them to your app explicitly (as shown above). Keep a single `@dynamic-field-kit/core` version across all adapters so they share one registry.
|
|
18
16
|
|
|
19
17
|
If you need to pin versions explicitly:
|
|
20
18
|
|
|
@@ -29,6 +27,9 @@ npm install @dynamic-field-kit/core@^1.0.12 @dynamic-field-kit/angular@^1.2.3
|
|
|
29
27
|
- `MultiFieldInput`
|
|
30
28
|
- `DynamicFieldKitModule`
|
|
31
29
|
- `fieldRegistry`
|
|
30
|
+
- `FieldRegistry` (class, for scoped registries)
|
|
31
|
+
- `FIELD_REGISTRY` (injection token)
|
|
32
|
+
- `validateField` / `validateFields` / `resolveDisabled` / `resolveReadOnly` / `ValidationResult`
|
|
32
33
|
|
|
33
34
|
## Basic setup (Angular 19+)
|
|
34
35
|
|
|
@@ -88,6 +89,113 @@ export class AppComponent {
|
|
|
88
89
|
></dfk-multi-field-input>
|
|
89
90
|
```
|
|
90
91
|
|
|
92
|
+
## Layouts
|
|
93
|
+
|
|
94
|
+
`MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` (mobile/desktop with a custom breakpoint), matching the React and Vue adapters:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<dfk-multi-field-input
|
|
98
|
+
[fieldDescriptions]="fields"
|
|
99
|
+
[layout]="{ type: 'grid', columns: 3, gap: 16 }"
|
|
100
|
+
></dfk-multi-field-input>
|
|
101
|
+
|
|
102
|
+
<dfk-multi-field-input
|
|
103
|
+
[fieldDescriptions]="fields"
|
|
104
|
+
[layout]="{
|
|
105
|
+
type: 'responsive',
|
|
106
|
+
mobile: 'column',
|
|
107
|
+
desktop: { type: 'grid', columns: 2, gap: 12 }
|
|
108
|
+
}"
|
|
109
|
+
></dfk-multi-field-input>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Derived fields with `computeValue`
|
|
113
|
+
|
|
114
|
+
Give a field a `computeValue` to derive its value from the rest of the form data whenever any field changes:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
fields: FieldDescription[] = [
|
|
118
|
+
{ name: 'firstName', type: 'text' },
|
|
119
|
+
{ name: 'lastName', type: 'text' },
|
|
120
|
+
{
|
|
121
|
+
name: 'fullName',
|
|
122
|
+
type: 'text',
|
|
123
|
+
computeValue: (data) => `${data.firstName ?? ''} ${data.lastName ?? ''}`.trim(),
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Validation & conditions
|
|
129
|
+
|
|
130
|
+
Declare a `validate` hook and dynamic `disabledCondition`/`readOnlyCondition`;
|
|
131
|
+
your renderer component receives `error`, `disabled`, and `readOnly` inputs, and
|
|
132
|
+
`dfk-multi-field-input` emits `(validityChange)`:
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<dfk-multi-field-input
|
|
136
|
+
[fieldDescriptions]="fields"
|
|
137
|
+
[properties]="data"
|
|
138
|
+
(onChange)="onChange($event)"
|
|
139
|
+
(validityChange)="canSubmit = $event.valid"
|
|
140
|
+
></dfk-multi-field-input>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For submit-time whole-form validation, call `validateFields(fields, data)`.
|
|
144
|
+
|
|
145
|
+
## Repeatable field groups
|
|
146
|
+
|
|
147
|
+
A field with `fields` renders as a repeatable group: `data[name]` becomes an array of items, each shaped by the nested `fields`, with "Add"/"Remove" controls rendered automatically.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
fields: FieldDescription[] = [
|
|
151
|
+
{
|
|
152
|
+
name: 'contacts',
|
|
153
|
+
type: 'group',
|
|
154
|
+
label: 'Contacts',
|
|
155
|
+
fields: [
|
|
156
|
+
{ name: 'email', type: 'text', label: 'Email' },
|
|
157
|
+
{ name: 'phone', type: 'text', label: 'Phone' },
|
|
158
|
+
],
|
|
159
|
+
defaultItem: { email: '', phone: '' },
|
|
160
|
+
keyField: 'id', // optional: stable trackBy key instead of the array index
|
|
161
|
+
minItems: 1,
|
|
162
|
+
maxItems: 5,
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```html
|
|
168
|
+
<dfk-multi-field-input [fieldDescriptions]="fields"></dfk-multi-field-input>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Scoped registries
|
|
172
|
+
|
|
173
|
+
`fieldRegistry` is a process-wide singleton. To give a component or route its own renderers, provide the `FIELD_REGISTRY` token with an isolated `FieldRegistry`. Components without an override keep using the global singleton.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { FieldRegistry, FIELD_REGISTRY } from '@dynamic-field-kit/angular';
|
|
177
|
+
|
|
178
|
+
const registry = new FieldRegistry();
|
|
179
|
+
registry.register('text', TextFieldComponent as any);
|
|
180
|
+
|
|
181
|
+
@Component({
|
|
182
|
+
selector: 'app-scoped-form',
|
|
183
|
+
standalone: true,
|
|
184
|
+
imports: [MultiFieldInput],
|
|
185
|
+
providers: [{ provide: FIELD_REGISTRY, useValue: registry }],
|
|
186
|
+
template: `<dfk-multi-field-input [fieldDescriptions]="fields" />`,
|
|
187
|
+
})
|
|
188
|
+
export class ScopedFormComponent {}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Passing renderer-specific props
|
|
192
|
+
|
|
193
|
+
The generic adapter forwards only the shared `FieldRendererProps`. For inputs specific to one renderer (e.g. `acceptFile`, `maxLength`), pass them per field via `FieldDescription.props`; they are set on the renderer instance verbatim.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
{ name: 'avatar', type: 'file', props: { acceptFile: 'image/*' } }
|
|
197
|
+
```
|
|
198
|
+
|
|
91
199
|
## Legacy setup (Angular 14 and earlier with NgModule)
|
|
92
200
|
|
|
93
201
|
```ts
|
|
@@ -118,7 +226,8 @@ declare module '@dynamic-field-kit/core' {
|
|
|
118
226
|
|
|
119
227
|
- Register Angular component classes in `fieldRegistry`.
|
|
120
228
|
- Do not register React or Vue renderers in the Angular adapter.
|
|
121
|
-
- `MultiFieldInput` supports `column`, `row`, and `
|
|
229
|
+
- `MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` layouts, and derives fields using `computeValue`.
|
|
230
|
+
- Fields with `fields` render as repeatable groups instead of going through `fieldRegistry`.
|
|
122
231
|
- The shared schema and field types still come from `@dynamic-field-kit/core`.
|
|
123
232
|
|
|
124
233
|
## License
|
package/dist/README.md
CHANGED
|
@@ -12,9 +12,7 @@ Demo app: https://github.com/vannt-dev/dynamic-field-kit-demo
|
|
|
12
12
|
npm install @dynamic-field-kit/core @dynamic-field-kit/angular
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Note:
|
|
16
|
-
|
|
17
|
-
- Install with core: `npm install @dynamic-field-kit/core @dynamic-field-kit/angular`
|
|
15
|
+
Note: `@dynamic-field-kit/core`, `@angular/core`, and `@angular/common` are **peer dependencies** — this adapter does not bundle or auto-install them, so add them to your app explicitly (as shown above). Keep a single `@dynamic-field-kit/core` version across all adapters so they share one registry.
|
|
18
16
|
|
|
19
17
|
If you need to pin versions explicitly:
|
|
20
18
|
|
|
@@ -29,6 +27,9 @@ npm install @dynamic-field-kit/core@^1.0.12 @dynamic-field-kit/angular@^1.2.3
|
|
|
29
27
|
- `MultiFieldInput`
|
|
30
28
|
- `DynamicFieldKitModule`
|
|
31
29
|
- `fieldRegistry`
|
|
30
|
+
- `FieldRegistry` (class, for scoped registries)
|
|
31
|
+
- `FIELD_REGISTRY` (injection token)
|
|
32
|
+
- `validateField` / `validateFields` / `resolveDisabled` / `resolveReadOnly` / `ValidationResult`
|
|
32
33
|
|
|
33
34
|
## Basic setup (Angular 19+)
|
|
34
35
|
|
|
@@ -88,6 +89,113 @@ export class AppComponent {
|
|
|
88
89
|
></dfk-multi-field-input>
|
|
89
90
|
```
|
|
90
91
|
|
|
92
|
+
## Layouts
|
|
93
|
+
|
|
94
|
+
`MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` (mobile/desktop with a custom breakpoint), matching the React and Vue adapters:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<dfk-multi-field-input
|
|
98
|
+
[fieldDescriptions]="fields"
|
|
99
|
+
[layout]="{ type: 'grid', columns: 3, gap: 16 }"
|
|
100
|
+
></dfk-multi-field-input>
|
|
101
|
+
|
|
102
|
+
<dfk-multi-field-input
|
|
103
|
+
[fieldDescriptions]="fields"
|
|
104
|
+
[layout]="{
|
|
105
|
+
type: 'responsive',
|
|
106
|
+
mobile: 'column',
|
|
107
|
+
desktop: { type: 'grid', columns: 2, gap: 12 }
|
|
108
|
+
}"
|
|
109
|
+
></dfk-multi-field-input>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Derived fields with `computeValue`
|
|
113
|
+
|
|
114
|
+
Give a field a `computeValue` to derive its value from the rest of the form data whenever any field changes:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
fields: FieldDescription[] = [
|
|
118
|
+
{ name: 'firstName', type: 'text' },
|
|
119
|
+
{ name: 'lastName', type: 'text' },
|
|
120
|
+
{
|
|
121
|
+
name: 'fullName',
|
|
122
|
+
type: 'text',
|
|
123
|
+
computeValue: (data) => `${data.firstName ?? ''} ${data.lastName ?? ''}`.trim(),
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Validation & conditions
|
|
129
|
+
|
|
130
|
+
Declare a `validate` hook and dynamic `disabledCondition`/`readOnlyCondition`;
|
|
131
|
+
your renderer component receives `error`, `disabled`, and `readOnly` inputs, and
|
|
132
|
+
`dfk-multi-field-input` emits `(validityChange)`:
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<dfk-multi-field-input
|
|
136
|
+
[fieldDescriptions]="fields"
|
|
137
|
+
[properties]="data"
|
|
138
|
+
(onChange)="onChange($event)"
|
|
139
|
+
(validityChange)="canSubmit = $event.valid"
|
|
140
|
+
></dfk-multi-field-input>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For submit-time whole-form validation, call `validateFields(fields, data)`.
|
|
144
|
+
|
|
145
|
+
## Repeatable field groups
|
|
146
|
+
|
|
147
|
+
A field with `fields` renders as a repeatable group: `data[name]` becomes an array of items, each shaped by the nested `fields`, with "Add"/"Remove" controls rendered automatically.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
fields: FieldDescription[] = [
|
|
151
|
+
{
|
|
152
|
+
name: 'contacts',
|
|
153
|
+
type: 'group',
|
|
154
|
+
label: 'Contacts',
|
|
155
|
+
fields: [
|
|
156
|
+
{ name: 'email', type: 'text', label: 'Email' },
|
|
157
|
+
{ name: 'phone', type: 'text', label: 'Phone' },
|
|
158
|
+
],
|
|
159
|
+
defaultItem: { email: '', phone: '' },
|
|
160
|
+
keyField: 'id', // optional: stable trackBy key instead of the array index
|
|
161
|
+
minItems: 1,
|
|
162
|
+
maxItems: 5,
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```html
|
|
168
|
+
<dfk-multi-field-input [fieldDescriptions]="fields"></dfk-multi-field-input>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Scoped registries
|
|
172
|
+
|
|
173
|
+
`fieldRegistry` is a process-wide singleton. To give a component or route its own renderers, provide the `FIELD_REGISTRY` token with an isolated `FieldRegistry`. Components without an override keep using the global singleton.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { FieldRegistry, FIELD_REGISTRY } from '@dynamic-field-kit/angular';
|
|
177
|
+
|
|
178
|
+
const registry = new FieldRegistry();
|
|
179
|
+
registry.register('text', TextFieldComponent as any);
|
|
180
|
+
|
|
181
|
+
@Component({
|
|
182
|
+
selector: 'app-scoped-form',
|
|
183
|
+
standalone: true,
|
|
184
|
+
imports: [MultiFieldInput],
|
|
185
|
+
providers: [{ provide: FIELD_REGISTRY, useValue: registry }],
|
|
186
|
+
template: `<dfk-multi-field-input [fieldDescriptions]="fields" />`,
|
|
187
|
+
})
|
|
188
|
+
export class ScopedFormComponent {}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Passing renderer-specific props
|
|
192
|
+
|
|
193
|
+
The generic adapter forwards only the shared `FieldRendererProps`. For inputs specific to one renderer (e.g. `acceptFile`, `maxLength`), pass them per field via `FieldDescription.props`; they are set on the renderer instance verbatim.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
{ name: 'avatar', type: 'file', props: { acceptFile: 'image/*' } }
|
|
197
|
+
```
|
|
198
|
+
|
|
91
199
|
## Legacy setup (Angular 14 and earlier with NgModule)
|
|
92
200
|
|
|
93
201
|
```ts
|
|
@@ -118,7 +226,8 @@ declare module '@dynamic-field-kit/core' {
|
|
|
118
226
|
|
|
119
227
|
- Register Angular component classes in `fieldRegistry`.
|
|
120
228
|
- Do not register React or Vue renderers in the Angular adapter.
|
|
121
|
-
- `MultiFieldInput` supports `column`, `row`, and `
|
|
229
|
+
- `MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` layouts, and derives fields using `computeValue`.
|
|
230
|
+
- Fields with `fields` render as repeatable groups instead of going through `fieldRegistry`.
|
|
122
231
|
- The shared schema and field types still come from `@dynamic-field-kit/core`.
|
|
123
232
|
|
|
124
233
|
## License
|
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
import { ChangeDetectorRef, EventEmitter } from '@angular/core';
|
|
1
|
+
import { ChangeDetectorRef, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
|
-
export
|
|
3
|
+
export interface FieldInputProps {
|
|
4
|
+
value?: unknown;
|
|
5
|
+
label?: string;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
readOnly?: boolean;
|
|
10
|
+
error?: string | string[];
|
|
11
|
+
options?: unknown[];
|
|
12
|
+
className?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare abstract class BaseInputComponent implements OnChanges {
|
|
4
16
|
protected cdr: ChangeDetectorRef;
|
|
5
|
-
value?:
|
|
17
|
+
value?: unknown;
|
|
6
18
|
label?: string;
|
|
7
19
|
placeholder?: string;
|
|
8
20
|
required?: boolean;
|
|
9
21
|
disabled?: boolean;
|
|
10
|
-
|
|
22
|
+
readOnly?: boolean;
|
|
23
|
+
error?: string | string[];
|
|
24
|
+
options?: unknown[];
|
|
11
25
|
className?: string;
|
|
12
26
|
description?: string;
|
|
13
|
-
|
|
14
|
-
acceptFile?: string;
|
|
15
|
-
maxLength?: number;
|
|
16
|
-
minNumber?: number;
|
|
17
|
-
maxNumber?: number;
|
|
18
|
-
valueChange: EventEmitter<any>;
|
|
27
|
+
valueChange: EventEmitter<unknown>;
|
|
19
28
|
constructor(cdr: ChangeDetectorRef);
|
|
29
|
+
ngOnChanges(_changes: SimpleChanges): void;
|
|
30
|
+
protected detectChanges(): void;
|
|
31
|
+
protected hasChanges(changes: SimpleChanges, prop: string): boolean;
|
|
20
32
|
static ɵfac: i0.ɵɵFactoryDeclaration<BaseInputComponent, never>;
|
|
21
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<BaseInputComponent, "ng-component", never, { "value": { "alias": "value"; "required": false; }; "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "
|
|
33
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<BaseInputComponent, "ng-component", never, { "value": { "alias": "value"; "required": false; }; "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "error": { "alias": "error"; "required": false; }; "options": { "alias": "options"; "required": false; }; "className": { "alias": "className"; "required": false; }; "description": { "alias": "description"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
22
34
|
}
|
|
@@ -1,24 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FieldTypeKey } from '@dynamic-field-kit/core';
|
|
1
|
+
import { AfterViewInit, EventEmitter, OnChanges, OnDestroy, SimpleChanges, ViewContainerRef } from '@angular/core';
|
|
2
|
+
import { FieldTypeKey, Properties } from '@dynamic-field-kit/core';
|
|
3
3
|
import { BaseInputComponent } from './BaseInput';
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
5
|
export declare class DynamicInput extends BaseInputComponent implements OnChanges, AfterViewInit, OnDestroy {
|
|
6
6
|
type: FieldTypeKey;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
extraProps?: Properties;
|
|
8
|
+
valueChange: EventEmitter<unknown>;
|
|
9
|
+
onChange: EventEmitter<unknown>;
|
|
10
|
+
private registry;
|
|
9
11
|
host: ViewContainerRef;
|
|
10
12
|
private compRef?;
|
|
11
13
|
private inputInstance?;
|
|
12
14
|
private subscriptions;
|
|
15
|
+
private supplied;
|
|
13
16
|
ngOnChanges(changes: SimpleChanges): void;
|
|
14
17
|
ngAfterViewInit(): void;
|
|
15
18
|
ngOnDestroy(): void;
|
|
19
|
+
private syncPropsToInstance;
|
|
20
|
+
private cleanup;
|
|
16
21
|
private cleanupSubscriptions;
|
|
22
|
+
private cleanupRenderedComponent;
|
|
17
23
|
private render;
|
|
18
|
-
private
|
|
19
|
-
private
|
|
24
|
+
private isComponentType;
|
|
25
|
+
private renderComponent;
|
|
26
|
+
private renderFallback;
|
|
27
|
+
private getFallbackProps;
|
|
28
|
+
private applyProps;
|
|
29
|
+
private applyExtraProps;
|
|
30
|
+
private bindOutputs;
|
|
20
31
|
private emitValue;
|
|
21
|
-
private
|
|
32
|
+
private renderError;
|
|
22
33
|
static ɵfac: i0.ɵɵFactoryDeclaration<DynamicInput, never>;
|
|
23
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicInput, "dfk-dynamic-input", never, { "type": { "alias": "type"; "required": false; }; }, { "valueChange": "valueChange"; "onChange": "onChange"; }, never, never, true, never>;
|
|
34
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicInput, "dfk-dynamic-input", never, { "type": { "alias": "type"; "required": false; }; "extraProps": { "alias": "extraProps"; "required": false; }; }, { "valueChange": "valueChange"; "onChange": "onChange"; }, never, never, true, never>;
|
|
24
35
|
}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { EventEmitter } from '@angular/core';
|
|
2
|
-
import { FieldDescription
|
|
1
|
+
import { ChangeDetectorRef, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { FieldDescription } from '@dynamic-field-kit/core';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class FieldInput {
|
|
4
|
+
export declare class FieldInput implements OnChanges {
|
|
5
|
+
private cdr;
|
|
5
6
|
fieldDescription?: FieldDescription;
|
|
6
|
-
|
|
7
|
+
value?: unknown;
|
|
8
|
+
options?: Record<string, unknown>[];
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
error?: string | string[];
|
|
7
12
|
onValueChangeField: EventEmitter<{
|
|
8
|
-
value:
|
|
13
|
+
value: unknown;
|
|
9
14
|
key: string;
|
|
10
15
|
}>;
|
|
11
|
-
|
|
16
|
+
shouldRender: boolean;
|
|
17
|
+
get resolvedOptions(): Record<string, unknown>[] | undefined;
|
|
18
|
+
constructor(cdr: ChangeDetectorRef);
|
|
19
|
+
ngOnChanges(_changes: SimpleChanges): void;
|
|
12
20
|
static ɵfac: i0.ɵɵFactoryDeclaration<FieldInput, never>;
|
|
13
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<FieldInput, "dfk-field-input", never, { "fieldDescription": { "alias": "fieldDescription"; "required": false; }; "
|
|
21
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FieldInput, "dfk-field-input", never, { "fieldDescription": { "alias": "fieldDescription"; "required": false; }; "value": { "alias": "value"; "required": false; }; "options": { "alias": "options"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, { "onValueChangeField": "onValueChangeField"; }, never, never, true, never>;
|
|
14
22
|
}
|
|
@@ -1,23 +1,49 @@
|
|
|
1
|
-
import { EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
|
1
|
+
import { ChangeDetectorRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
|
2
2
|
import { FieldDescription, Properties } from '@dynamic-field-kit/core';
|
|
3
|
-
import {
|
|
3
|
+
import type { ValidationResult } from '@dynamic-field-kit/core';
|
|
4
|
+
import { BaseLayoutConfig, LayoutConfig } from '../types/layout';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
5
6
|
export declare class MultiFieldInput implements OnInit, OnChanges {
|
|
7
|
+
private cdr;
|
|
6
8
|
fieldDescriptions: FieldDescription[];
|
|
7
9
|
properties?: Properties;
|
|
8
10
|
onChange: EventEmitter<Properties>;
|
|
11
|
+
validityChange: EventEmitter<ValidationResult>;
|
|
9
12
|
layout: LayoutConfig;
|
|
13
|
+
rootData?: Properties;
|
|
10
14
|
data: Properties;
|
|
11
15
|
visibleFields: FieldDescription[];
|
|
16
|
+
private isMobile;
|
|
17
|
+
constructor(cdr: ChangeDetectorRef);
|
|
18
|
+
onWindowResize(): void;
|
|
19
|
+
get resolvedLayout(): BaseLayoutConfig;
|
|
20
|
+
get resolvedLayoutType(): string;
|
|
21
|
+
get gap(): number;
|
|
22
|
+
get columns(): number;
|
|
12
23
|
trackByFn(index: number, field: FieldDescription): string | number;
|
|
24
|
+
trackByIndex(index: number): number;
|
|
25
|
+
private groupTrackByCache;
|
|
26
|
+
groupTrackBy(field: FieldDescription): (index: number, item: Properties) => unknown;
|
|
13
27
|
ngOnInit(): void;
|
|
14
28
|
ngOnChanges(_changes: SimpleChanges): void;
|
|
29
|
+
private updateIsMobile;
|
|
15
30
|
private init;
|
|
16
31
|
private updateVisibleFields;
|
|
17
32
|
onFieldChange(event: {
|
|
18
|
-
value:
|
|
33
|
+
value: unknown;
|
|
19
34
|
key: string;
|
|
20
35
|
}): void;
|
|
36
|
+
getItems(field: FieldDescription): Properties[];
|
|
37
|
+
getResolvedOptions(field: FieldDescription): Properties[] | undefined;
|
|
38
|
+
getDisabled(field: FieldDescription): boolean;
|
|
39
|
+
getReadOnly(field: FieldDescription): boolean;
|
|
40
|
+
getError(field: FieldDescription): string[] | undefined;
|
|
41
|
+
canAddItem(field: FieldDescription): boolean;
|
|
42
|
+
canRemoveItem(field: FieldDescription): boolean;
|
|
43
|
+
onGroupItemAdd(field: FieldDescription): void;
|
|
44
|
+
onGroupItemRemove(field: FieldDescription, index: number): void;
|
|
45
|
+
onGroupItemChange(field: FieldDescription, index: number, next: Properties): void;
|
|
46
|
+
private commitData;
|
|
21
47
|
static ɵfac: i0.ɵɵFactoryDeclaration<MultiFieldInput, never>;
|
|
22
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<MultiFieldInput, "dfk-multi-field-input", never, { "fieldDescriptions": { "alias": "fieldDescriptions"; "required": false; }; "properties": { "alias": "properties"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; }, { "onChange": "onChange"; }, never, never, true, never>;
|
|
48
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<MultiFieldInput, "dfk-multi-field-input", never, { "fieldDescriptions": { "alias": "fieldDescriptions"; "required": false; }; "properties": { "alias": "properties"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; "rootData": { "alias": "rootData"; "required": false; }; }, { "onChange": "onChange"; "validityChange": "validityChange"; }, never, never, true, never>;
|
|
23
49
|
}
|
|
@@ -7,21 +7,26 @@ export class BaseInputComponent {
|
|
|
7
7
|
placeholder;
|
|
8
8
|
required;
|
|
9
9
|
disabled;
|
|
10
|
+
readOnly;
|
|
11
|
+
error;
|
|
10
12
|
options;
|
|
11
13
|
className;
|
|
12
14
|
description;
|
|
13
|
-
errorMessage;
|
|
14
|
-
acceptFile;
|
|
15
|
-
maxLength;
|
|
16
|
-
minNumber;
|
|
17
|
-
maxNumber;
|
|
18
|
-
// Add more from mplis as needed
|
|
19
15
|
valueChange = new EventEmitter();
|
|
20
16
|
constructor(cdr) {
|
|
21
17
|
this.cdr = cdr;
|
|
22
18
|
}
|
|
19
|
+
ngOnChanges(_changes) {
|
|
20
|
+
this.detectChanges();
|
|
21
|
+
}
|
|
22
|
+
detectChanges() {
|
|
23
|
+
this.cdr.markForCheck();
|
|
24
|
+
}
|
|
25
|
+
hasChanges(changes, prop) {
|
|
26
|
+
return changes[prop] !== undefined;
|
|
27
|
+
}
|
|
23
28
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BaseInputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
24
|
-
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",
|
|
29
|
+
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 });
|
|
25
30
|
}
|
|
26
31
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BaseInputComponent, decorators: [{
|
|
27
32
|
type: Component,
|
|
@@ -38,23 +43,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
38
43
|
type: Input
|
|
39
44
|
}], disabled: [{
|
|
40
45
|
type: Input
|
|
46
|
+
}], readOnly: [{
|
|
47
|
+
type: Input
|
|
48
|
+
}], error: [{
|
|
49
|
+
type: Input
|
|
41
50
|
}], options: [{
|
|
42
51
|
type: Input
|
|
43
52
|
}], className: [{
|
|
44
53
|
type: Input
|
|
45
54
|
}], description: [{
|
|
46
55
|
type: Input
|
|
47
|
-
}], errorMessage: [{
|
|
48
|
-
type: Input
|
|
49
|
-
}], acceptFile: [{
|
|
50
|
-
type: Input
|
|
51
|
-
}], maxLength: [{
|
|
52
|
-
type: Input
|
|
53
|
-
}], minNumber: [{
|
|
54
|
-
type: Input
|
|
55
|
-
}], maxNumber: [{
|
|
56
|
-
type: Input
|
|
57
56
|
}], valueChange: [{
|
|
58
57
|
type: Output
|
|
59
58
|
}] } });
|
|
60
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzZUlucHV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvQmFzZUlucHV0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFFTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEdBRVAsTUFBTSxlQUFlLENBQUM7O0FBcUJ2QixNQUFNLE9BQWdCLGtCQUFrQjtJQWNoQjtJQWJiLEtBQUssQ0FBVztJQUNoQixLQUFLLENBQVU7SUFDZixXQUFXLENBQVU7SUFDckIsUUFBUSxDQUFXO0lBQ25CLFFBQVEsQ0FBVztJQUNuQixRQUFRLENBQVc7SUFDbkIsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQWE7SUFDcEIsU0FBUyxDQUFVO0lBQ25CLFdBQVcsQ0FBVTtJQUVwQixXQUFXLEdBQUcsSUFBSSxZQUFZLEVBQVcsQ0FBQztJQUVwRCxZQUFzQixHQUFzQjtRQUF0QixRQUFHLEdBQUgsR0FBRyxDQUFtQjtJQUFHLENBQUM7SUFFaEQsV0FBVyxDQUFDLFFBQXVCO1FBQ2pDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRVMsYUFBYTtRQUNyQixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFUyxVQUFVLENBQUMsT0FBc0IsRUFBRSxJQUFZO1FBQ3ZELE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLFNBQVMsQ0FBQztJQUNyQyxDQUFDO3dHQTFCbUIsa0JBQWtCOzRGQUFsQixrQkFBa0Isd1dBRjVCLEVBQUU7OzRGQUVRLGtCQUFrQjtrQkFIdkMsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsRUFBRTtpQkFDYjtzRkFFVSxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUksV0FBVztzQkFBcEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuLy8gTWlycm9ycyB0aGUgZnJhbWV3b3JrLWFnbm9zdGljIEZpZWxkUmVuZGVyZXJQcm9wcy4gRG9tYWluLXNwZWNpZmljIGlucHV0c1xuLy8gKGFjY2VwdEZpbGUsIG1heExlbmd0aCwgLi4uKSBpbnRlbnRpb25hbGx5IGxpdmUgb24gdGhlIGluZGl2aWR1YWwgcmVuZGVyZXIsXG4vLyBub3QgaGVyZSAtIHBhc3MgdGhlbSBwZXIgZmllbGQgdmlhIEZpZWxkRGVzY3JpcHRpb24ucHJvcHMgaW5zdGVhZC5cbmV4cG9ydCBpbnRlcmZhY2UgRmllbGRJbnB1dFByb3BzIHtcbiAgdmFsdWU/OiB1bmtub3duO1xuICBsYWJlbD86IHN0cmluZztcbiAgcGxhY2Vob2xkZXI/OiBzdHJpbmc7XG4gIHJlcXVpcmVkPzogYm9vbGVhbjtcbiAgZGlzYWJsZWQ/OiBib29sZWFuO1xuICByZWFkT25seT86IGJvb2xlYW47XG4gIGVycm9yPzogc3RyaW5nIHwgc3RyaW5nW107XG4gIG9wdGlvbnM/OiB1bmtub3duW107XG4gIGNsYXNzTmFtZT86IHN0cmluZztcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbkBDb21wb25lbnQoe1xuICB0ZW1wbGF0ZTogJycsXG59KVxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VJbnB1dENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCgpIHZhbHVlPzogdW5rbm93bjtcbiAgQElucHV0KCkgbGFiZWw/OiBzdHJpbmc7XG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyPzogc3RyaW5nO1xuICBASW5wdXQoKSByZXF1aXJlZD86IGJvb2xlYW47XG4gIEBJbnB1dCgpIGRpc2FibGVkPzogYm9vbGVhbjtcbiAgQElucHV0KCkgcmVhZE9ubHk/OiBib29sZWFuO1xuICBASW5wdXQoKSBlcnJvcj86IHN0cmluZyB8IHN0cmluZ1tdO1xuICBASW5wdXQoKSBvcHRpb25zPzogdW5rbm93bltdO1xuICBASW5wdXQoKSBjbGFzc05hbWU/OiBzdHJpbmc7XG4gIEBJbnB1dCgpIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuXG4gIEBPdXRwdXQoKSB2YWx1ZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8dW5rbm93bj4oKTtcblxuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgY2RyOiBDaGFuZ2VEZXRlY3RvclJlZikge31cblxuICBuZ09uQ2hhbmdlcyhfY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIHRoaXMuZGV0ZWN0Q2hhbmdlcygpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGRldGVjdENoYW5nZXMoKTogdm9pZCB7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgaGFzQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzLCBwcm9wOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gY2hhbmdlc1twcm9wXSAhPT0gdW5kZWZpbmVkO1xuICB9XG59XG4iXX0=
|