@dotjem/angular-dynamic-components 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +17 -0
- package/.github/workflows/ci-publish.yml +113 -0
- package/.prettierrc +12 -0
- package/.vscode/extensions.json +4 -0
- package/.vscode/launch.json +20 -0
- package/.vscode/mcp.json +9 -0
- package/.vscode/tasks.json +42 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/angular-dynamic-components-0.0.0.tgz +0 -0
- package/angular.json +102 -0
- package/dotjem-angular-dynamic-components-0.0.1.tgz +0 -0
- package/package.json +34 -0
- package/projects/demo/public/favicon.ico +0 -0
- package/projects/demo/src/app/app.config.ts +30 -0
- package/projects/demo/src/app/app.html +41 -0
- package/projects/demo/src/app/app.routes.ts +3 -0
- package/projects/demo/src/app/app.scss +0 -0
- package/projects/demo/src/app/app.spec.ts +27 -0
- package/projects/demo/src/app/app.ts +117 -0
- package/projects/demo/src/app/components/search-text-field.component.ts +49 -0
- package/projects/demo/src/app/components/section-heading.component.ts +25 -0
- package/projects/demo/src/app/components/select-field.component.ts +56 -0
- package/projects/demo/src/app/components/text-field.component.ts +53 -0
- package/projects/demo/src/index.html +13 -0
- package/projects/demo/src/main.ts +5 -0
- package/projects/demo/src/styles.scss +1 -0
- package/projects/demo/tsconfig.app.json +11 -0
- package/projects/demo/tsconfig.spec.json +10 -0
- package/projects/dotjem/angular-dynamic-components/README.md +5 -0
- package/projects/dotjem/angular-dynamic-components/ng-package.json +7 -0
- package/projects/dotjem/angular-dynamic-components/package.json +27 -0
- package/projects/dotjem/angular-dynamic-components/src/lib/component-registry.spec.ts +127 -0
- package/projects/dotjem/angular-dynamic-components/src/lib/component-registry.ts +137 -0
- package/projects/dotjem/angular-dynamic-components/src/lib/dynamic-component-host.component.spec.ts +151 -0
- package/projects/dotjem/angular-dynamic-components/src/lib/dynamic-component-host.component.ts +135 -0
- package/projects/dotjem/angular-dynamic-components/src/public-api.ts +6 -0
- package/projects/dotjem/angular-dynamic-components/tsconfig.lib.json +13 -0
- package/projects/dotjem/angular-dynamic-components/tsconfig.lib.prod.json +11 -0
- package/projects/dotjem/angular-dynamic-components/tsconfig.spec.json +10 -0
- package/tsconfig.json +42 -0
package/.editorconfig
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Editor configuration, see https://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
charset = utf-8
|
|
6
|
+
indent_style = space
|
|
7
|
+
indent_size = 2
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[*.ts]
|
|
12
|
+
quote_type = single
|
|
13
|
+
ij_typescript_use_double_quotes = false
|
|
14
|
+
|
|
15
|
+
[*.md]
|
|
16
|
+
max_line_length = off
|
|
17
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
name: CI and Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
verify:
|
|
14
|
+
name: Build, Test and Report
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Setup Node.js
|
|
21
|
+
uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: 22
|
|
24
|
+
cache: npm
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: npm ci
|
|
28
|
+
|
|
29
|
+
- name: Run tests
|
|
30
|
+
run: npm test
|
|
31
|
+
|
|
32
|
+
- name: Build library
|
|
33
|
+
run: npm run build
|
|
34
|
+
|
|
35
|
+
- name: Upload build artifact
|
|
36
|
+
uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dotjem-angular-dynamic-components-dist
|
|
39
|
+
path: dist/dotjem/angular-dynamic-components
|
|
40
|
+
if-no-files-found: error
|
|
41
|
+
|
|
42
|
+
publish:
|
|
43
|
+
name: Publish to npm
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
needs: verify
|
|
46
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
47
|
+
env:
|
|
48
|
+
LIB_PACKAGE_DIR: projects/dotjem/angular-dynamic-components
|
|
49
|
+
LIB_DIST_DIR: dist/dotjem/angular-dynamic-components
|
|
50
|
+
steps:
|
|
51
|
+
- name: Checkout
|
|
52
|
+
uses: actions/checkout@v4
|
|
53
|
+
|
|
54
|
+
- name: Setup Node.js for npm publish
|
|
55
|
+
uses: actions/setup-node@v4
|
|
56
|
+
with:
|
|
57
|
+
node-version: 22
|
|
58
|
+
cache: npm
|
|
59
|
+
registry-url: https://registry.npmjs.org
|
|
60
|
+
|
|
61
|
+
- name: Install dependencies
|
|
62
|
+
run: npm ci
|
|
63
|
+
|
|
64
|
+
- name: Calculate Version Parameters
|
|
65
|
+
id: version
|
|
66
|
+
run: |
|
|
67
|
+
set -euo pipefail
|
|
68
|
+
build="${GITHUB_RUN_NUMBER}"
|
|
69
|
+
template="$(node -p "require('./${LIB_PACKAGE_DIR}/package.json').version")"
|
|
70
|
+
shortsha="$(git rev-parse --short "${GITHUB_SHA}")"
|
|
71
|
+
base="$(node - "$template" "$build" <<'NODE'
|
|
72
|
+
const template = process.argv[2];
|
|
73
|
+
const build = process.argv[3];
|
|
74
|
+
const parts = template.split('.');
|
|
75
|
+
const index = parts.indexOf('build');
|
|
76
|
+
|
|
77
|
+
if (index >= 0) {
|
|
78
|
+
parts[index] = build;
|
|
79
|
+
process.stdout.write(parts.join('.'));
|
|
80
|
+
} else {
|
|
81
|
+
process.stdout.write(`${template}-${build}`);
|
|
82
|
+
}
|
|
83
|
+
NODE
|
|
84
|
+
)"
|
|
85
|
+
publish_version="${base}+sha.${shortsha}"
|
|
86
|
+
|
|
87
|
+
echo "template=$template" >> "$GITHUB_OUTPUT"
|
|
88
|
+
echo "shortsha=$shortsha" >> "$GITHUB_OUTPUT"
|
|
89
|
+
echo "publish_version=$publish_version" >> "$GITHUB_OUTPUT"
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
echo "### Version Parameters"
|
|
93
|
+
echo "- template: \`$template\`"
|
|
94
|
+
echo "- run number: \`$build\`"
|
|
95
|
+
echo "- short sha: \`$shortsha\`"
|
|
96
|
+
echo "- publish version: \`$publish_version\`"
|
|
97
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
98
|
+
|
|
99
|
+
- name: Set package version
|
|
100
|
+
run: |
|
|
101
|
+
npm pkg set version="${{ steps.version.outputs.publish_version }}" --prefix "${LIB_PACKAGE_DIR}"
|
|
102
|
+
|
|
103
|
+
- name: Build library
|
|
104
|
+
run: npm run build
|
|
105
|
+
|
|
106
|
+
- name: Set dist package version
|
|
107
|
+
run: |
|
|
108
|
+
npm pkg set version="${{ steps.version.outputs.publish_version }}" --prefix "${LIB_DIST_DIR}"
|
|
109
|
+
|
|
110
|
+
- name: Publish package
|
|
111
|
+
run: npm publish "./${LIB_DIST_DIR}" --access public
|
|
112
|
+
env:
|
|
113
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH }}
|
package/.prettierrc
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"configurations": [
|
|
5
|
+
{
|
|
6
|
+
"name": "ng serve",
|
|
7
|
+
"type": "chrome",
|
|
8
|
+
"request": "launch",
|
|
9
|
+
"preLaunchTask": "npm: start",
|
|
10
|
+
"url": "http://localhost:4200/"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "ng test",
|
|
14
|
+
"type": "chrome",
|
|
15
|
+
"request": "launch",
|
|
16
|
+
"preLaunchTask": "npm: test",
|
|
17
|
+
"url": "http://localhost:9876/debug.html"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
package/.vscode/mcp.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"tasks": [
|
|
5
|
+
{
|
|
6
|
+
"type": "npm",
|
|
7
|
+
"script": "start",
|
|
8
|
+
"isBackground": true,
|
|
9
|
+
"problemMatcher": {
|
|
10
|
+
"owner": "typescript",
|
|
11
|
+
"pattern": "$tsc",
|
|
12
|
+
"background": {
|
|
13
|
+
"activeOnStart": true,
|
|
14
|
+
"beginsPattern": {
|
|
15
|
+
"regexp": "Changes detected"
|
|
16
|
+
},
|
|
17
|
+
"endsPattern": {
|
|
18
|
+
"regexp": "bundle generation (complete|failed)"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "npm",
|
|
25
|
+
"script": "test",
|
|
26
|
+
"isBackground": true,
|
|
27
|
+
"problemMatcher": {
|
|
28
|
+
"owner": "typescript",
|
|
29
|
+
"pattern": "$tsc",
|
|
30
|
+
"background": {
|
|
31
|
+
"activeOnStart": true,
|
|
32
|
+
"beginsPattern": {
|
|
33
|
+
"regexp": "Changes detected"
|
|
34
|
+
},
|
|
35
|
+
"endsPattern": {
|
|
36
|
+
"regexp": "bundle generation (complete|failed)"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dotJEM
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# @dotjem/angular-dynamic-components
|
|
2
|
+
|
|
3
|
+
> Dynamic component hosting for Angular 21+ — render registered components configured as plain JSON.
|
|
4
|
+
|
|
5
|
+
Use `dx-dynamic-component-host` directly and let your application own iteration, data mapping, and configuration shape.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @dotjem/angular-dynamic-components
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> **Peer dependencies:** `@angular/core ^21`, `@angular/common ^21`, `@angular/forms ^21`
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
### 1. Register your components
|
|
22
|
+
|
|
23
|
+
In your `app.config.ts` (or any `providers` array) call `provideDynamicComponents()`:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { provideDynamicComponents } from '@dotjem/angular-dynamic-components';
|
|
27
|
+
import { TextFieldComponent } from './fields/text-field.component';
|
|
28
|
+
import { SelectFieldComponent } from './fields/select-field.component';
|
|
29
|
+
|
|
30
|
+
export const appConfig: ApplicationConfig = {
|
|
31
|
+
providers: [
|
|
32
|
+
provideDynamicComponents(
|
|
33
|
+
{
|
|
34
|
+
'text-field': TextFieldComponent,
|
|
35
|
+
'select-field': SelectFieldComponent,
|
|
36
|
+
},
|
|
37
|
+
'editor'
|
|
38
|
+
),
|
|
39
|
+
provideDynamicComponents(
|
|
40
|
+
{
|
|
41
|
+
'text-field': SearchTextFieldComponent,
|
|
42
|
+
},
|
|
43
|
+
'search'
|
|
44
|
+
),
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Describe your UI as configuration entries
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
type DynamicConfiguration = {
|
|
53
|
+
type: string;
|
|
54
|
+
field?: string;
|
|
55
|
+
config: Record<string, unknown>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const editorConfigurations: DynamicConfiguration[] = [
|
|
59
|
+
{ type: 'section-heading', config: { title: 'Personal Information' } },
|
|
60
|
+
{
|
|
61
|
+
type: 'text-field',
|
|
62
|
+
field: 'firstName',
|
|
63
|
+
config: { name: 'firstName', label: 'First name', placeholder: 'Jane' },
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
let editorData: Record<string, unknown> = {
|
|
68
|
+
firstName: { value: 'Jane' },
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. Render with `<dx-dynamic-component-host>`
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
@for (entry of editorConfigurations; track $index) {
|
|
76
|
+
<dx-dynamic-component-host
|
|
77
|
+
[component]="entry.type"
|
|
78
|
+
registry="editor"
|
|
79
|
+
[data]="entry.field ? editorData[entry.field] : undefined"
|
|
80
|
+
[config]="entry.config"
|
|
81
|
+
(dataChange)="onFieldChange(entry.field, $event)"
|
|
82
|
+
/>
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## API
|
|
89
|
+
|
|
90
|
+
### `ComponentRegistry`
|
|
91
|
+
|
|
92
|
+
Injectable service. Use it when you need to register components imperatively:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { ComponentRegistry } from '@dotjem/angular-dynamic-components';
|
|
96
|
+
|
|
97
|
+
export class SomeModule {
|
|
98
|
+
constructor(registry: ComponentRegistry) {
|
|
99
|
+
registry.register('my-widget', MyWidgetComponent);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Method | Description |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `register(type, component, registry?)` | Register a component in a named registry (`default` if omitted). |
|
|
107
|
+
| `resolve(type, registry?)` | Returns the component class or `null` in the selected registry. |
|
|
108
|
+
| `has(type, registry?)` | Returns `true` if the type is registered in the selected registry. |
|
|
109
|
+
| `types(registry?)` | Returns registered type keys for the selected registry. |
|
|
110
|
+
| `registryNames()` | Returns all known registry names. |
|
|
111
|
+
|
|
112
|
+
### `provideDynamicComponents(map, registry?)`
|
|
113
|
+
|
|
114
|
+
Creates an Angular multi-provider that pre-populates a named registry at bootstrap time.
|
|
115
|
+
|
|
116
|
+
### `<dx-dynamic-component-host [component]="...">`
|
|
117
|
+
|
|
118
|
+
Renders the single component described by a registered component key.
|
|
119
|
+
Accepts host-level `[data]` and `[config]` inputs.
|
|
120
|
+
Re-emits the rendered component's `dataChange` so `[(data)]`-style flows work naturally.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Demo application
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Build the library first
|
|
128
|
+
npm run build
|
|
129
|
+
|
|
130
|
+
# Serve the demo app
|
|
131
|
+
npm start
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Run library unit tests
|
|
140
|
+
npm test
|
|
141
|
+
|
|
142
|
+
# Build the library
|
|
143
|
+
npm run build
|
|
144
|
+
|
|
145
|
+
# Build the demo application
|
|
146
|
+
npm run build:demo
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT
|
|
Binary file
|
package/angular.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"cli": {
|
|
5
|
+
"packageManager": "npm"
|
|
6
|
+
},
|
|
7
|
+
"newProjectRoot": "projects",
|
|
8
|
+
"projects": {
|
|
9
|
+
"@dotjem/angular-dynamic-components": {
|
|
10
|
+
"projectType": "library",
|
|
11
|
+
"root": "projects/dotjem/angular-dynamic-components",
|
|
12
|
+
"sourceRoot": "projects/dotjem/angular-dynamic-components/src",
|
|
13
|
+
"prefix": "dotjem",
|
|
14
|
+
"architect": {
|
|
15
|
+
"build": {
|
|
16
|
+
"builder": "@angular/build:ng-packagr",
|
|
17
|
+
"configurations": {
|
|
18
|
+
"production": {
|
|
19
|
+
"tsConfig": "projects/dotjem/angular-dynamic-components/tsconfig.lib.prod.json"
|
|
20
|
+
},
|
|
21
|
+
"development": {
|
|
22
|
+
"tsConfig": "projects/dotjem/angular-dynamic-components/tsconfig.lib.json"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"defaultConfiguration": "production"
|
|
26
|
+
},
|
|
27
|
+
"test": {
|
|
28
|
+
"builder": "@angular/build:unit-test",
|
|
29
|
+
"options": {
|
|
30
|
+
"tsConfig": "projects/dotjem/angular-dynamic-components/tsconfig.spec.json"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"demo": {
|
|
36
|
+
"projectType": "application",
|
|
37
|
+
"schematics": {
|
|
38
|
+
"@schematics/angular:component": {
|
|
39
|
+
"style": "scss"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"root": "projects/demo",
|
|
43
|
+
"sourceRoot": "projects/demo/src",
|
|
44
|
+
"prefix": "app",
|
|
45
|
+
"architect": {
|
|
46
|
+
"build": {
|
|
47
|
+
"builder": "@angular/build:application",
|
|
48
|
+
"options": {
|
|
49
|
+
"browser": "projects/demo/src/main.ts",
|
|
50
|
+
"tsConfig": "projects/demo/tsconfig.app.json",
|
|
51
|
+
"inlineStyleLanguage": "scss",
|
|
52
|
+
"assets": [
|
|
53
|
+
{
|
|
54
|
+
"glob": "**/*",
|
|
55
|
+
"input": "projects/demo/public"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"styles": ["projects/demo/src/styles.scss"]
|
|
59
|
+
},
|
|
60
|
+
"configurations": {
|
|
61
|
+
"production": {
|
|
62
|
+
"budgets": [
|
|
63
|
+
{
|
|
64
|
+
"type": "initial",
|
|
65
|
+
"maximumWarning": "500kB",
|
|
66
|
+
"maximumError": "1MB"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "anyComponentStyle",
|
|
70
|
+
"maximumWarning": "4kB",
|
|
71
|
+
"maximumError": "8kB"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"outputHashing": "all"
|
|
75
|
+
},
|
|
76
|
+
"development": {
|
|
77
|
+
"optimization": false,
|
|
78
|
+
"extractLicenses": false,
|
|
79
|
+
"sourceMap": true
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"defaultConfiguration": "production"
|
|
83
|
+
},
|
|
84
|
+
"serve": {
|
|
85
|
+
"builder": "@angular/build:dev-server",
|
|
86
|
+
"configurations": {
|
|
87
|
+
"production": {
|
|
88
|
+
"buildTarget": "demo:build:production"
|
|
89
|
+
},
|
|
90
|
+
"development": {
|
|
91
|
+
"buildTarget": "demo:build:development"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"defaultConfiguration": "development"
|
|
95
|
+
},
|
|
96
|
+
"test": {
|
|
97
|
+
"builder": "@angular/build:unit-test"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dotjem/angular-dynamic-components",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"ng": "ng",
|
|
6
|
+
"start": "ng serve demo",
|
|
7
|
+
"build": "ng build @dotjem/angular-dynamic-components",
|
|
8
|
+
"build:demo": "ng build demo",
|
|
9
|
+
"watch": "ng build @dotjem/angular-dynamic-components --watch --configuration development",
|
|
10
|
+
"test": "ng test @dotjem/angular-dynamic-components",
|
|
11
|
+
"test:demo": "ng test demo"
|
|
12
|
+
},
|
|
13
|
+
"packageManager": "npm@10.8.2",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@angular/common": "^21.2.0",
|
|
16
|
+
"@angular/compiler": "^21.2.0",
|
|
17
|
+
"@angular/core": "^21.2.0",
|
|
18
|
+
"@angular/forms": "^21.2.0",
|
|
19
|
+
"@angular/platform-browser": "^21.2.0",
|
|
20
|
+
"@angular/router": "^21.2.0",
|
|
21
|
+
"rxjs": "~7.8.0",
|
|
22
|
+
"tslib": "^2.3.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@angular/build": "^21.2.11",
|
|
26
|
+
"@angular/cli": "^21.2.11",
|
|
27
|
+
"@angular/compiler-cli": "^21.2.0",
|
|
28
|
+
"jsdom": "^28.0.0",
|
|
29
|
+
"ng-packagr": "^21.2.0",
|
|
30
|
+
"prettier": "^3.8.1",
|
|
31
|
+
"typescript": "~5.9.2",
|
|
32
|
+
"vitest": "^4.0.8"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
|
2
|
+
import { provideRouter } from '@angular/router';
|
|
3
|
+
import { provideDynamicComponents } from '@dotjem/angular-dynamic-components';
|
|
4
|
+
|
|
5
|
+
import { routes } from './app.routes';
|
|
6
|
+
import { TextFieldComponent } from './components/text-field.component';
|
|
7
|
+
import { SelectFieldComponent } from './components/select-field.component';
|
|
8
|
+
import { SectionHeadingComponent } from './components/section-heading.component';
|
|
9
|
+
import { SearchTextFieldComponent } from './components/search-text-field.component';
|
|
10
|
+
|
|
11
|
+
export const appConfig: ApplicationConfig = {
|
|
12
|
+
providers: [
|
|
13
|
+
provideBrowserGlobalErrorListeners(),
|
|
14
|
+
provideRouter(routes),
|
|
15
|
+
provideDynamicComponents(
|
|
16
|
+
{
|
|
17
|
+
'text-field': TextFieldComponent,
|
|
18
|
+
'select-field': SelectFieldComponent,
|
|
19
|
+
'section-heading': SectionHeadingComponent,
|
|
20
|
+
},
|
|
21
|
+
'editor'
|
|
22
|
+
),
|
|
23
|
+
provideDynamicComponents(
|
|
24
|
+
{
|
|
25
|
+
'text-field': SearchTextFieldComponent,
|
|
26
|
+
},
|
|
27
|
+
'search'
|
|
28
|
+
),
|
|
29
|
+
],
|
|
30
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<div class="page">
|
|
2
|
+
<header>
|
|
3
|
+
<h1>@dotjem/angular-dynamic-components</h1>
|
|
4
|
+
<p>Consumer-driven rendering with component/config entries and record-based model data.</p>
|
|
5
|
+
</header>
|
|
6
|
+
|
|
7
|
+
<main>
|
|
8
|
+
<section class="panel">
|
|
9
|
+
<h2>Editor form registry</h2>
|
|
10
|
+
@for (entry of editorConfigurations; track $index) {
|
|
11
|
+
<dx-dynamic-component-host
|
|
12
|
+
[component]="entry.type"
|
|
13
|
+
registry="editor"
|
|
14
|
+
[data]="entry.field ? editorData[entry.field] : undefined"
|
|
15
|
+
[config]="entry.config"
|
|
16
|
+
(dataChange)="handleEditorDataChange(entry.field, $event)"
|
|
17
|
+
/>
|
|
18
|
+
}
|
|
19
|
+
</section>
|
|
20
|
+
|
|
21
|
+
<section class="panel">
|
|
22
|
+
<h2>Search form registry</h2>
|
|
23
|
+
@for (entry of searchConfigurations; track $index) {
|
|
24
|
+
<dx-dynamic-component-host
|
|
25
|
+
[component]="entry.type"
|
|
26
|
+
registry="search"
|
|
27
|
+
[data]="entry.field ? searchData[entry.field] : undefined"
|
|
28
|
+
[config]="entry.config"
|
|
29
|
+
(dataChange)="handleSearchDataChange(entry.field, $event)"
|
|
30
|
+
/>
|
|
31
|
+
}
|
|
32
|
+
</section>
|
|
33
|
+
</main>
|
|
34
|
+
|
|
35
|
+
<footer>
|
|
36
|
+
<p>Configuration JSON:</p>
|
|
37
|
+
<pre>{{ configurationJson }}</pre>
|
|
38
|
+
<p>Data JSON:</p>
|
|
39
|
+
<pre>{{ dataJson }}</pre>
|
|
40
|
+
</footer>
|
|
41
|
+
</div>
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { App } from './app';
|
|
3
|
+
import { appConfig } from './app.config';
|
|
4
|
+
|
|
5
|
+
describe('App', () => {
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
await TestBed.configureTestingModule({
|
|
8
|
+
imports: [App],
|
|
9
|
+
providers: [...appConfig.providers],
|
|
10
|
+
}).compileComponents();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should create the app', () => {
|
|
14
|
+
const fixture = TestBed.createComponent(App);
|
|
15
|
+
const app = fixture.componentInstance;
|
|
16
|
+
expect(app).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should render the library name in the heading', async () => {
|
|
20
|
+
const fixture = TestBed.createComponent(App);
|
|
21
|
+
await fixture.whenStable();
|
|
22
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
23
|
+
expect(compiled.querySelector('h1')?.textContent).toContain(
|
|
24
|
+
'@dotjem/angular-dynamic-components'
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
});
|