@dynamic-field-kit/angular 1.2.4 → 1.3.3
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 +116 -46
- package/angular.json +27 -0
- package/dist/README.md +188 -0
- package/dist/components/BaseInput.d.ts +40 -0
- package/dist/components/DynamicInput.d.ts +31 -0
- package/dist/components/FieldInput.d.ts +18 -0
- package/dist/components/MultiFieldInput.d.ts +40 -0
- package/dist/esm2022/components/BaseInput.mjs +68 -0
- package/dist/esm2022/components/DynamicInput.mjs +191 -0
- package/dist/esm2022/components/FieldInput.mjs +80 -0
- package/dist/esm2022/components/MultiFieldInput.mjs +264 -0
- package/{esm2020 → dist/esm2022}/dynamic-field-kit-angular.mjs +4 -4
- package/dist/esm2022/layout/defaultLayouts.mjs +114 -0
- package/dist/esm2022/layout/index.mjs +3 -0
- package/dist/esm2022/layout/layoutRegistry.mjs +14 -0
- package/dist/esm2022/lib/dynamic-field-kit.module.mjs +52 -0
- package/{esm2020 → dist/esm2022}/public-api.mjs +14 -14
- package/dist/esm2022/types/layout.mjs +2 -0
- package/dist/fesm2022/dynamic-field-kit-angular.mjs +771 -0
- package/dist/fesm2022/dynamic-field-kit-angular.mjs.map +1 -0
- package/{index.d.ts → dist/index.d.ts} +5 -5
- package/dist/layout/defaultLayouts.d.ts +31 -0
- package/dist/layout/index.d.ts +2 -0
- package/dist/layout/layoutRegistry.d.ts +12 -0
- package/{lib → dist/lib}/dynamic-field-kit.module.d.ts +11 -11
- package/{public-api.d.ts → dist/public-api.d.ts} +9 -9
- package/dist/types/layout.d.ts +25 -0
- package/karma.conf.js +37 -0
- package/ng-package.json +7 -0
- package/package.json +44 -28
- package/src/components/BaseInput.ts +60 -0
- package/src/components/DynamicInput.ts +224 -0
- package/src/components/FieldInput.ts +67 -0
- package/src/components/MultiFieldInput.ts +238 -0
- package/src/layout/defaultLayouts.ts +70 -0
- package/src/layout/index.ts +2 -0
- package/src/layout/layoutRegistry.ts +25 -0
- package/src/lib/dynamic-field-kit.module.ts +29 -0
- package/src/public-api.ts +24 -0
- package/src/types/layout.ts +36 -0
- package/test/DynamicInput.spec.ts +30 -0
- package/test/FieldInput.spec.ts +44 -0
- package/test/angular.spec.ts +102 -0
- package/test/integration.spec.ts +57 -0
- package/test/layouts.spec.ts +26 -0
- package/test.ts +12 -0
- package/tsconfig.json +13 -0
- package/tsconfig.spec.json +21 -0
- package/components/BaseInput.d.ts +0 -22
- package/components/DynamicInput.d.ts +0 -28
- package/components/FieldInput.d.ts +0 -14
- package/components/MultiFieldInput.d.ts +0 -23
- package/esm2020/components/BaseInput.mjs +0 -46
- package/esm2020/components/DynamicInput.mjs +0 -146
- package/esm2020/components/FieldInput.mjs +0 -66
- package/esm2020/components/MultiFieldInput.mjs +0 -79
- package/esm2020/layout/defaultLayouts.mjs +0 -43
- package/esm2020/layout/index.mjs +0 -2
- package/esm2020/lib/dynamic-field-kit.module.mjs +0 -20
- package/esm2020/types/layout.mjs +0 -2
- package/fesm2015/dynamic-field-kit-angular.mjs +0 -393
- package/fesm2015/dynamic-field-kit-angular.mjs.map +0 -1
- package/fesm2020/dynamic-field-kit-angular.mjs +0 -390
- package/fesm2020/dynamic-field-kit-angular.mjs.map +0 -1
- package/layout/defaultLayouts.d.ts +0 -13
- package/layout/index.d.ts +0 -1
- package/types/layout.d.ts +0 -1
package/README.md
CHANGED
|
@@ -12,6 +12,10 @@ 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: Core is shared runtime. Install core separately and ensure a single version is used across adapters to avoid duplicate registries.
|
|
16
|
+
|
|
17
|
+
- Install with core: `npm install @dynamic-field-kit/core @dynamic-field-kit/angular`
|
|
18
|
+
|
|
15
19
|
If you need to pin versions explicitly:
|
|
16
20
|
|
|
17
21
|
```bash
|
|
@@ -26,37 +30,52 @@ npm install @dynamic-field-kit/core@^1.0.12 @dynamic-field-kit/angular@^1.2.3
|
|
|
26
30
|
- `DynamicFieldKitModule`
|
|
27
31
|
- `fieldRegistry`
|
|
28
32
|
|
|
29
|
-
## Basic setup
|
|
33
|
+
## Basic setup (Angular 19+)
|
|
30
34
|
|
|
31
|
-
1. Import
|
|
35
|
+
1. Import the component and register fields before bootstrap.
|
|
32
36
|
|
|
33
37
|
```ts
|
|
34
|
-
import
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
import 'zone.js';
|
|
39
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
40
|
+
import { fieldRegistry } from '@dynamic-field-kit/angular';
|
|
41
|
+
import { AppComponent } from './app/app.component';
|
|
42
|
+
import { TextFieldComponent } from './app/components/text-field.component';
|
|
43
|
+
import { NumberFieldComponent } from './app/components/number-field.component';
|
|
44
|
+
|
|
45
|
+
fieldRegistry.register('text', TextFieldComponent as any);
|
|
46
|
+
fieldRegistry.register('number', NumberFieldComponent as any);
|
|
47
|
+
|
|
48
|
+
bootstrapApplication(AppComponent, {
|
|
49
|
+
providers: [],
|
|
50
|
+
}).catch((err) => console.error(err));
|
|
42
51
|
```
|
|
43
52
|
|
|
44
|
-
2.
|
|
53
|
+
2. Use the component in a standalone component.
|
|
45
54
|
|
|
46
55
|
```ts
|
|
47
|
-
import
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
import { Component } from '@angular/core';
|
|
57
|
+
import { CommonModule } from '@angular/common';
|
|
58
|
+
import { FieldDescription } from '@dynamic-field-kit/core';
|
|
59
|
+
import { MultiFieldInput } from '@dynamic-field-kit/angular';
|
|
60
|
+
|
|
61
|
+
@Component({
|
|
62
|
+
selector: 'app-root',
|
|
63
|
+
standalone: true,
|
|
64
|
+
imports: [CommonModule, MultiFieldInput],
|
|
65
|
+
templateUrl: './app.component.html',
|
|
66
|
+
})
|
|
67
|
+
export class AppComponent {
|
|
68
|
+
fields: FieldDescription[] = [
|
|
69
|
+
{ name: 'name', type: 'text', label: 'Name' },
|
|
70
|
+
{ name: 'age', type: 'number', label: 'Age' },
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
data: any = {};
|
|
74
|
+
|
|
75
|
+
onChange(data: any) {
|
|
76
|
+
this.data = data;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
60
79
|
```
|
|
61
80
|
|
|
62
81
|
3. Render your schema in a template.
|
|
@@ -69,39 +88,89 @@ platformBrowserDynamic()
|
|
|
69
88
|
></dfk-multi-field-input>
|
|
70
89
|
```
|
|
71
90
|
|
|
72
|
-
|
|
91
|
+
## Layouts
|
|
92
|
+
|
|
93
|
+
`MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` (mobile/desktop with a custom breakpoint), matching the React and Vue adapters:
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<dfk-multi-field-input
|
|
97
|
+
[fieldDescriptions]="fields"
|
|
98
|
+
[layout]="{ type: 'grid', columns: 3, gap: 16 }"
|
|
99
|
+
></dfk-multi-field-input>
|
|
100
|
+
|
|
101
|
+
<dfk-multi-field-input
|
|
102
|
+
[fieldDescriptions]="fields"
|
|
103
|
+
[layout]="{
|
|
104
|
+
type: 'responsive',
|
|
105
|
+
mobile: 'column',
|
|
106
|
+
desktop: { type: 'grid', columns: 2, gap: 12 }
|
|
107
|
+
}"
|
|
108
|
+
></dfk-multi-field-input>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Derived fields with `computeValue`
|
|
112
|
+
|
|
113
|
+
Give a field a `computeValue` to derive its value from the rest of the form data whenever any field changes:
|
|
73
114
|
|
|
74
115
|
```ts
|
|
75
|
-
|
|
76
|
-
|
|
116
|
+
fields: FieldDescription[] = [
|
|
117
|
+
{ name: 'firstName', type: 'text' },
|
|
118
|
+
{ name: 'lastName', type: 'text' },
|
|
119
|
+
{
|
|
120
|
+
name: 'fullName',
|
|
121
|
+
type: 'text',
|
|
122
|
+
computeValue: (data) => `${data.firstName ?? ''} ${data.lastName ?? ''}`.trim(),
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
```
|
|
77
126
|
|
|
78
|
-
|
|
79
|
-
selector: "app-root",
|
|
80
|
-
templateUrl: "./app.component.html",
|
|
81
|
-
})
|
|
82
|
-
export class AppComponent {
|
|
83
|
-
fields: FieldDescription[] = [
|
|
84
|
-
{ name: "name", type: "text", label: "Name" },
|
|
85
|
-
{ name: "age", type: "number", label: "Age" },
|
|
86
|
-
]
|
|
127
|
+
## Repeatable field groups
|
|
87
128
|
|
|
88
|
-
|
|
129
|
+
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.
|
|
89
130
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
131
|
+
```ts
|
|
132
|
+
fields: FieldDescription[] = [
|
|
133
|
+
{
|
|
134
|
+
name: 'contacts',
|
|
135
|
+
type: 'group',
|
|
136
|
+
label: 'Contacts',
|
|
137
|
+
fields: [
|
|
138
|
+
{ name: 'email', type: 'text', label: 'Email' },
|
|
139
|
+
{ name: 'phone', type: 'text', label: 'Phone' },
|
|
140
|
+
],
|
|
141
|
+
defaultItem: { email: '', phone: '' },
|
|
142
|
+
minItems: 1,
|
|
143
|
+
maxItems: 5,
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<dfk-multi-field-input [fieldDescriptions]="fields"></dfk-multi-field-input>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Legacy setup (Angular 14 and earlier with NgModule)
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
156
|
+
import { NgModule } from '@angular/core';
|
|
157
|
+
import { DynamicFieldKitModule } from '@dynamic-field-kit/angular';
|
|
158
|
+
|
|
159
|
+
@NgModule({
|
|
160
|
+
imports: [BrowserModule, DynamicFieldKitModule],
|
|
161
|
+
})
|
|
162
|
+
export class AppModule {}
|
|
94
163
|
```
|
|
95
164
|
|
|
96
165
|
## Type augmentation
|
|
97
166
|
|
|
98
167
|
```ts
|
|
99
|
-
import
|
|
168
|
+
import '@dynamic-field-kit/core';
|
|
100
169
|
|
|
101
|
-
declare module
|
|
170
|
+
declare module '@dynamic-field-kit/core' {
|
|
102
171
|
interface FieldTypeMap {
|
|
103
|
-
text: string
|
|
104
|
-
number: number
|
|
172
|
+
text: string;
|
|
173
|
+
number: number;
|
|
105
174
|
}
|
|
106
175
|
}
|
|
107
176
|
```
|
|
@@ -110,7 +179,8 @@ declare module "@dynamic-field-kit/core" {
|
|
|
110
179
|
|
|
111
180
|
- Register Angular component classes in `fieldRegistry`.
|
|
112
181
|
- Do not register React or Vue renderers in the Angular adapter.
|
|
113
|
-
- `MultiFieldInput` supports `column`, `row`, and `
|
|
182
|
+
- `MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` layouts, and derives fields using `computeValue`.
|
|
183
|
+
- Fields with `fields` render as repeatable groups instead of going through `fieldRegistry`.
|
|
114
184
|
- The shared schema and field types still come from `@dynamic-field-kit/core`.
|
|
115
185
|
|
|
116
186
|
## License
|
package/angular.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"newProjectRoot": "projects",
|
|
5
|
+
"projects": {
|
|
6
|
+
"dynamic-field-kit-angular": {
|
|
7
|
+
"projectType": "library",
|
|
8
|
+
"root": "",
|
|
9
|
+
"sourceRoot": "src",
|
|
10
|
+
"prefix": "dfk",
|
|
11
|
+
"architect": {
|
|
12
|
+
"test": {
|
|
13
|
+
"builder": "@angular-devkit/build-angular:karma",
|
|
14
|
+
"options": {
|
|
15
|
+
"main": "test.ts",
|
|
16
|
+
"polyfills": ["zone.js"],
|
|
17
|
+
"tsConfig": "tsconfig.spec.json",
|
|
18
|
+
"karmaConfig": "karma.conf.js",
|
|
19
|
+
"assets": [],
|
|
20
|
+
"styles": [],
|
|
21
|
+
"scripts": []
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# @dynamic-field-kit/angular
|
|
2
|
+
|
|
3
|
+
Angular adapter for `@dynamic-field-kit/core`.
|
|
4
|
+
|
|
5
|
+
This package provides Angular components and a convenience module that render field schemas defined with `@dynamic-field-kit/core`.
|
|
6
|
+
|
|
7
|
+
Demo app: https://github.com/vannt-dev/dynamic-field-kit-demo
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @dynamic-field-kit/core @dynamic-field-kit/angular
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Note: Core is shared runtime. Install core separately and ensure a single version is used across adapters to avoid duplicate registries.
|
|
16
|
+
|
|
17
|
+
- Install with core: `npm install @dynamic-field-kit/core @dynamic-field-kit/angular`
|
|
18
|
+
|
|
19
|
+
If you need to pin versions explicitly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @dynamic-field-kit/core@^1.0.12 @dynamic-field-kit/angular@^1.2.3
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What it exports
|
|
26
|
+
|
|
27
|
+
- `DynamicInput`
|
|
28
|
+
- `FieldInput`
|
|
29
|
+
- `MultiFieldInput`
|
|
30
|
+
- `DynamicFieldKitModule`
|
|
31
|
+
- `fieldRegistry`
|
|
32
|
+
|
|
33
|
+
## Basic setup (Angular 19+)
|
|
34
|
+
|
|
35
|
+
1. Import the component and register fields before bootstrap.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import 'zone.js';
|
|
39
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
40
|
+
import { fieldRegistry } from '@dynamic-field-kit/angular';
|
|
41
|
+
import { AppComponent } from './app/app.component';
|
|
42
|
+
import { TextFieldComponent } from './app/components/text-field.component';
|
|
43
|
+
import { NumberFieldComponent } from './app/components/number-field.component';
|
|
44
|
+
|
|
45
|
+
fieldRegistry.register('text', TextFieldComponent as any);
|
|
46
|
+
fieldRegistry.register('number', NumberFieldComponent as any);
|
|
47
|
+
|
|
48
|
+
bootstrapApplication(AppComponent, {
|
|
49
|
+
providers: [],
|
|
50
|
+
}).catch((err) => console.error(err));
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
2. Use the component in a standalone component.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { Component } from '@angular/core';
|
|
57
|
+
import { CommonModule } from '@angular/common';
|
|
58
|
+
import { FieldDescription } from '@dynamic-field-kit/core';
|
|
59
|
+
import { MultiFieldInput } from '@dynamic-field-kit/angular';
|
|
60
|
+
|
|
61
|
+
@Component({
|
|
62
|
+
selector: 'app-root',
|
|
63
|
+
standalone: true,
|
|
64
|
+
imports: [CommonModule, MultiFieldInput],
|
|
65
|
+
templateUrl: './app.component.html',
|
|
66
|
+
})
|
|
67
|
+
export class AppComponent {
|
|
68
|
+
fields: FieldDescription[] = [
|
|
69
|
+
{ name: 'name', type: 'text', label: 'Name' },
|
|
70
|
+
{ name: 'age', type: 'number', label: 'Age' },
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
data: any = {};
|
|
74
|
+
|
|
75
|
+
onChange(data: any) {
|
|
76
|
+
this.data = data;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
3. Render your schema in a template.
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<dfk-multi-field-input
|
|
85
|
+
[fieldDescriptions]="fields"
|
|
86
|
+
[properties]="data"
|
|
87
|
+
(onChange)="onChange($event)"
|
|
88
|
+
></dfk-multi-field-input>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Layouts
|
|
92
|
+
|
|
93
|
+
`MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` (mobile/desktop with a custom breakpoint), matching the React and Vue adapters:
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<dfk-multi-field-input
|
|
97
|
+
[fieldDescriptions]="fields"
|
|
98
|
+
[layout]="{ type: 'grid', columns: 3, gap: 16 }"
|
|
99
|
+
></dfk-multi-field-input>
|
|
100
|
+
|
|
101
|
+
<dfk-multi-field-input
|
|
102
|
+
[fieldDescriptions]="fields"
|
|
103
|
+
[layout]="{
|
|
104
|
+
type: 'responsive',
|
|
105
|
+
mobile: 'column',
|
|
106
|
+
desktop: { type: 'grid', columns: 2, gap: 12 }
|
|
107
|
+
}"
|
|
108
|
+
></dfk-multi-field-input>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Derived fields with `computeValue`
|
|
112
|
+
|
|
113
|
+
Give a field a `computeValue` to derive its value from the rest of the form data whenever any field changes:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
fields: FieldDescription[] = [
|
|
117
|
+
{ name: 'firstName', type: 'text' },
|
|
118
|
+
{ name: 'lastName', type: 'text' },
|
|
119
|
+
{
|
|
120
|
+
name: 'fullName',
|
|
121
|
+
type: 'text',
|
|
122
|
+
computeValue: (data) => `${data.firstName ?? ''} ${data.lastName ?? ''}`.trim(),
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Repeatable field groups
|
|
128
|
+
|
|
129
|
+
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.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
fields: FieldDescription[] = [
|
|
133
|
+
{
|
|
134
|
+
name: 'contacts',
|
|
135
|
+
type: 'group',
|
|
136
|
+
label: 'Contacts',
|
|
137
|
+
fields: [
|
|
138
|
+
{ name: 'email', type: 'text', label: 'Email' },
|
|
139
|
+
{ name: 'phone', type: 'text', label: 'Phone' },
|
|
140
|
+
],
|
|
141
|
+
defaultItem: { email: '', phone: '' },
|
|
142
|
+
minItems: 1,
|
|
143
|
+
maxItems: 5,
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<dfk-multi-field-input [fieldDescriptions]="fields"></dfk-multi-field-input>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Legacy setup (Angular 14 and earlier with NgModule)
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
156
|
+
import { NgModule } from '@angular/core';
|
|
157
|
+
import { DynamicFieldKitModule } from '@dynamic-field-kit/angular';
|
|
158
|
+
|
|
159
|
+
@NgModule({
|
|
160
|
+
imports: [BrowserModule, DynamicFieldKitModule],
|
|
161
|
+
})
|
|
162
|
+
export class AppModule {}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Type augmentation
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import '@dynamic-field-kit/core';
|
|
169
|
+
|
|
170
|
+
declare module '@dynamic-field-kit/core' {
|
|
171
|
+
interface FieldTypeMap {
|
|
172
|
+
text: string;
|
|
173
|
+
number: number;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Notes
|
|
179
|
+
|
|
180
|
+
- Register Angular component classes in `fieldRegistry`.
|
|
181
|
+
- Do not register React or Vue renderers in the Angular adapter.
|
|
182
|
+
- `MultiFieldInput` supports `column`, `row`, `grid`, and `responsive` layouts, and derives fields using `computeValue`.
|
|
183
|
+
- Fields with `fields` render as repeatable groups instead of going through `fieldRegistry`.
|
|
184
|
+
- The shared schema and field types still come from `@dynamic-field-kit/core`.
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ChangeDetectorRef, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export interface FieldInputProps {
|
|
4
|
+
value?: unknown;
|
|
5
|
+
label?: string;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
options?: unknown[];
|
|
10
|
+
className?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
errorMessage?: string;
|
|
13
|
+
acceptFile?: string;
|
|
14
|
+
maxLength?: number;
|
|
15
|
+
minNumber?: number;
|
|
16
|
+
maxNumber?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare abstract class BaseInputComponent implements OnChanges {
|
|
19
|
+
protected cdr: ChangeDetectorRef;
|
|
20
|
+
value?: unknown;
|
|
21
|
+
label?: string;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
options?: unknown[];
|
|
26
|
+
className?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
errorMessage?: string;
|
|
29
|
+
acceptFile?: string;
|
|
30
|
+
maxLength?: number;
|
|
31
|
+
minNumber?: number;
|
|
32
|
+
maxNumber?: number;
|
|
33
|
+
valueChange: EventEmitter<unknown>;
|
|
34
|
+
constructor(cdr: ChangeDetectorRef);
|
|
35
|
+
ngOnChanges(_changes: SimpleChanges): void;
|
|
36
|
+
protected detectChanges(): void;
|
|
37
|
+
protected hasChanges(changes: SimpleChanges, prop: string): boolean;
|
|
38
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BaseInputComponent, never>;
|
|
39
|
+
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; }; "options": { "alias": "options"; "required": false; }; "className": { "alias": "className"; "required": false; }; "description": { "alias": "description"; "required": false; }; "errorMessage": { "alias": "errorMessage"; "required": false; }; "acceptFile": { "alias": "acceptFile"; "required": false; }; "maxLength": { "alias": "maxLength"; "required": false; }; "minNumber": { "alias": "minNumber"; "required": false; }; "maxNumber": { "alias": "maxNumber"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AfterViewInit, EventEmitter, OnChanges, OnDestroy, SimpleChanges, ViewContainerRef } from '@angular/core';
|
|
2
|
+
import { FieldTypeKey } from '@dynamic-field-kit/core';
|
|
3
|
+
import { BaseInputComponent } from './BaseInput';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export declare class DynamicInput extends BaseInputComponent implements OnChanges, AfterViewInit, OnDestroy {
|
|
6
|
+
type: FieldTypeKey;
|
|
7
|
+
valueChange: EventEmitter<unknown>;
|
|
8
|
+
onChange: EventEmitter<unknown>;
|
|
9
|
+
host: ViewContainerRef;
|
|
10
|
+
private compRef?;
|
|
11
|
+
private inputInstance?;
|
|
12
|
+
private subscriptions;
|
|
13
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
14
|
+
ngAfterViewInit(): void;
|
|
15
|
+
ngOnDestroy(): void;
|
|
16
|
+
private syncPropsToInstance;
|
|
17
|
+
private cleanup;
|
|
18
|
+
private cleanupSubscriptions;
|
|
19
|
+
private cleanupRenderedComponent;
|
|
20
|
+
private render;
|
|
21
|
+
private isComponentType;
|
|
22
|
+
private renderComponent;
|
|
23
|
+
private renderFallback;
|
|
24
|
+
private getFallbackProps;
|
|
25
|
+
private applyProps;
|
|
26
|
+
private bindOutputs;
|
|
27
|
+
private emitValue;
|
|
28
|
+
private renderError;
|
|
29
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DynamicInput, never>;
|
|
30
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicInput, "dfk-dynamic-input", never, { "type": { "alias": "type"; "required": false; }; }, { "valueChange": "valueChange"; "onChange": "onChange"; }, never, never, true, never>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ChangeDetectorRef, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { FieldDescription } from '@dynamic-field-kit/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class FieldInput implements OnChanges {
|
|
5
|
+
private cdr;
|
|
6
|
+
fieldDescription?: FieldDescription;
|
|
7
|
+
value?: unknown;
|
|
8
|
+
onValueChangeField: EventEmitter<{
|
|
9
|
+
value: unknown;
|
|
10
|
+
key: string;
|
|
11
|
+
}>;
|
|
12
|
+
shouldRender: boolean;
|
|
13
|
+
constructor(cdr: ChangeDetectorRef);
|
|
14
|
+
ngOnChanges(_changes: SimpleChanges): void;
|
|
15
|
+
getFieldValue(): unknown;
|
|
16
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FieldInput, never>;
|
|
17
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FieldInput, "dfk-field-input", never, { "fieldDescription": { "alias": "fieldDescription"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "onValueChangeField": "onValueChangeField"; }, never, never, true, never>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ChangeDetectorRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { FieldDescription, Properties } from '@dynamic-field-kit/core';
|
|
3
|
+
import { BaseLayoutConfig, LayoutConfig } from '../types/layout';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export declare class MultiFieldInput implements OnInit, OnChanges {
|
|
6
|
+
private cdr;
|
|
7
|
+
fieldDescriptions: FieldDescription[];
|
|
8
|
+
properties?: Properties;
|
|
9
|
+
onChange: EventEmitter<Properties>;
|
|
10
|
+
layout: LayoutConfig;
|
|
11
|
+
data: Properties;
|
|
12
|
+
visibleFields: FieldDescription[];
|
|
13
|
+
private isMobile;
|
|
14
|
+
constructor(cdr: ChangeDetectorRef);
|
|
15
|
+
onWindowResize(): void;
|
|
16
|
+
get resolvedLayout(): BaseLayoutConfig;
|
|
17
|
+
get resolvedLayoutType(): string;
|
|
18
|
+
get gap(): number;
|
|
19
|
+
get columns(): number;
|
|
20
|
+
trackByFn(index: number, field: FieldDescription): string | number;
|
|
21
|
+
trackByIndex(index: number): number;
|
|
22
|
+
ngOnInit(): void;
|
|
23
|
+
ngOnChanges(_changes: SimpleChanges): void;
|
|
24
|
+
private updateIsMobile;
|
|
25
|
+
private init;
|
|
26
|
+
private updateVisibleFields;
|
|
27
|
+
onFieldChange(event: {
|
|
28
|
+
value: unknown;
|
|
29
|
+
key: string;
|
|
30
|
+
}): void;
|
|
31
|
+
getItems(field: FieldDescription): Properties[];
|
|
32
|
+
canAddItem(field: FieldDescription): boolean;
|
|
33
|
+
canRemoveItem(field: FieldDescription): boolean;
|
|
34
|
+
onGroupItemAdd(field: FieldDescription): void;
|
|
35
|
+
onGroupItemRemove(field: FieldDescription, index: number): void;
|
|
36
|
+
onGroupItemChange(field: FieldDescription, index: number, next: Properties): void;
|
|
37
|
+
private commitData;
|
|
38
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MultiFieldInput, never>;
|
|
39
|
+
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>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output, } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class BaseInputComponent {
|
|
4
|
+
cdr;
|
|
5
|
+
value;
|
|
6
|
+
label;
|
|
7
|
+
placeholder;
|
|
8
|
+
required;
|
|
9
|
+
disabled;
|
|
10
|
+
options;
|
|
11
|
+
className;
|
|
12
|
+
description;
|
|
13
|
+
errorMessage;
|
|
14
|
+
acceptFile;
|
|
15
|
+
maxLength;
|
|
16
|
+
minNumber;
|
|
17
|
+
maxNumber;
|
|
18
|
+
valueChange = new EventEmitter();
|
|
19
|
+
constructor(cdr) {
|
|
20
|
+
this.cdr = cdr;
|
|
21
|
+
}
|
|
22
|
+
ngOnChanges(_changes) {
|
|
23
|
+
this.detectChanges();
|
|
24
|
+
}
|
|
25
|
+
detectChanges() {
|
|
26
|
+
this.cdr.markForCheck();
|
|
27
|
+
}
|
|
28
|
+
hasChanges(changes, prop) {
|
|
29
|
+
return changes[prop] !== undefined;
|
|
30
|
+
}
|
|
31
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BaseInputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
32
|
+
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", options: "options", className: "className", description: "description", errorMessage: "errorMessage", acceptFile: "acceptFile", maxLength: "maxLength", minNumber: "minNumber", maxNumber: "maxNumber" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true });
|
|
33
|
+
}
|
|
34
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: BaseInputComponent, decorators: [{
|
|
35
|
+
type: Component,
|
|
36
|
+
args: [{
|
|
37
|
+
template: '',
|
|
38
|
+
}]
|
|
39
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { value: [{
|
|
40
|
+
type: Input
|
|
41
|
+
}], label: [{
|
|
42
|
+
type: Input
|
|
43
|
+
}], placeholder: [{
|
|
44
|
+
type: Input
|
|
45
|
+
}], required: [{
|
|
46
|
+
type: Input
|
|
47
|
+
}], disabled: [{
|
|
48
|
+
type: Input
|
|
49
|
+
}], options: [{
|
|
50
|
+
type: Input
|
|
51
|
+
}], className: [{
|
|
52
|
+
type: Input
|
|
53
|
+
}], description: [{
|
|
54
|
+
type: Input
|
|
55
|
+
}], errorMessage: [{
|
|
56
|
+
type: Input
|
|
57
|
+
}], acceptFile: [{
|
|
58
|
+
type: Input
|
|
59
|
+
}], maxLength: [{
|
|
60
|
+
type: Input
|
|
61
|
+
}], minNumber: [{
|
|
62
|
+
type: Input
|
|
63
|
+
}], maxNumber: [{
|
|
64
|
+
type: Input
|
|
65
|
+
}], valueChange: [{
|
|
66
|
+
type: Output
|
|
67
|
+
}] } });
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzZUlucHV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvQmFzZUlucHV0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFFTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEdBRVAsTUFBTSxlQUFlLENBQUM7O0FBcUJ2QixNQUFNLE9BQWdCLGtCQUFrQjtJQWlCaEI7SUFoQmIsS0FBSyxDQUFXO0lBQ2hCLEtBQUssQ0FBVTtJQUNmLFdBQVcsQ0FBVTtJQUNyQixRQUFRLENBQVc7SUFDbkIsUUFBUSxDQUFXO0lBQ25CLE9BQU8sQ0FBYTtJQUNwQixTQUFTLENBQVU7SUFDbkIsV0FBVyxDQUFVO0lBQ3JCLFlBQVksQ0FBVTtJQUN0QixVQUFVLENBQVU7SUFDcEIsU0FBUyxDQUFVO0lBQ25CLFNBQVMsQ0FBVTtJQUNuQixTQUFTLENBQVU7SUFFbEIsV0FBVyxHQUFHLElBQUksWUFBWSxFQUFXLENBQUM7SUFFcEQsWUFBc0IsR0FBc0I7UUFBdEIsUUFBRyxHQUFILEdBQUcsQ0FBbUI7SUFBRyxDQUFDO0lBRWhELFdBQVcsQ0FBQyxRQUF1QjtRQUNqQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVTLGFBQWE7UUFDckIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRVMsVUFBVSxDQUFDLE9BQXNCLEVBQUUsSUFBWTtRQUN2RCxPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxTQUFTLENBQUM7SUFDckMsQ0FBQzt3R0E3Qm1CLGtCQUFrQjs0RkFBbEIsa0JBQWtCLGtjQUY1QixFQUFFOzs0RkFFUSxrQkFBa0I7a0JBSHZDLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLEVBQUU7aUJBQ2I7c0ZBRVUsS0FBSztzQkFBYixLQUFLO2dCQUNHLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxXQUFXO3NCQUFuQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxXQUFXO3NCQUFuQixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFFSSxXQUFXO3NCQUFwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZpZWxkSW5wdXRQcm9wcyB7XG4gIHZhbHVlPzogdW5rbm93bjtcbiAgbGFiZWw/OiBzdHJpbmc7XG4gIHBsYWNlaG9sZGVyPzogc3RyaW5nO1xuICByZXF1aXJlZD86IGJvb2xlYW47XG4gIGRpc2FibGVkPzogYm9vbGVhbjtcbiAgb3B0aW9ucz86IHVua25vd25bXTtcbiAgY2xhc3NOYW1lPzogc3RyaW5nO1xuICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgZXJyb3JNZXNzYWdlPzogc3RyaW5nO1xuICBhY2NlcHRGaWxlPzogc3RyaW5nO1xuICBtYXhMZW5ndGg/OiBudW1iZXI7XG4gIG1pbk51bWJlcj86IG51bWJlcjtcbiAgbWF4TnVtYmVyPzogbnVtYmVyO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgdGVtcGxhdGU6ICcnLFxufSlcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlSW5wdXRDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xuICBASW5wdXQoKSB2YWx1ZT86IHVua25vd247XG4gIEBJbnB1dCgpIGxhYmVsPzogc3RyaW5nO1xuICBASW5wdXQoKSBwbGFjZWhvbGRlcj86IHN0cmluZztcbiAgQElucHV0KCkgcmVxdWlyZWQ/OiBib29sZWFuO1xuICBASW5wdXQoKSBkaXNhYmxlZD86IGJvb2xlYW47XG4gIEBJbnB1dCgpIG9wdGlvbnM/OiB1bmtub3duW107XG4gIEBJbnB1dCgpIGNsYXNzTmFtZT86IHN0cmluZztcbiAgQElucHV0KCkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIEBJbnB1dCgpIGVycm9yTWVzc2FnZT86IHN0cmluZztcbiAgQElucHV0KCkgYWNjZXB0RmlsZT86IHN0cmluZztcbiAgQElucHV0KCkgbWF4TGVuZ3RoPzogbnVtYmVyO1xuICBASW5wdXQoKSBtaW5OdW1iZXI/OiBudW1iZXI7XG4gIEBJbnB1dCgpIG1heE51bWJlcj86IG51bWJlcjtcblxuICBAT3V0cHV0KCkgdmFsdWVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPHVua25vd24+KCk7XG5cbiAgY29uc3RydWN0b3IocHJvdGVjdGVkIGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYpIHt9XG5cbiAgbmdPbkNoYW5nZXMoX2NoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICB0aGlzLmRldGVjdENoYW5nZXMoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBkZXRlY3RDaGFuZ2VzKCk6IHZvaWQge1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGhhc0NoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcywgcHJvcDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGNoYW5nZXNbcHJvcF0gIT09IHVuZGVmaW5lZDtcbiAgfVxufVxuIl19
|