ngx-dynamic-entity 0.0.1 → 1.0.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.
Files changed (84) hide show
  1. package/README.md +139 -0
  2. package/esm2022/lib/field-types/array-field.component.mjs +160 -0
  3. package/esm2022/lib/field-types/boolean-field.component.mjs +100 -0
  4. package/esm2022/lib/field-types/checkbox-field.component.mjs +49 -41
  5. package/esm2022/lib/field-types/currency-field.component.mjs +101 -0
  6. package/esm2022/lib/field-types/date-field.component.mjs +47 -39
  7. package/esm2022/lib/field-types/dropdown-field.component.mjs +145 -54
  8. package/esm2022/lib/field-types/email-field.component.mjs +101 -0
  9. package/esm2022/lib/field-types/entity-ref-field.component.mjs +134 -70
  10. package/esm2022/lib/field-types/file-field.component.mjs +156 -0
  11. package/esm2022/lib/field-types/group-field.component.mjs +89 -0
  12. package/esm2022/lib/field-types/image-field.component.mjs +168 -0
  13. package/esm2022/lib/field-types/month-year-field.component.mjs +151 -0
  14. package/esm2022/lib/field-types/multi-select-field.component.mjs +110 -56
  15. package/esm2022/lib/field-types/number-field.component.mjs +84 -41
  16. package/esm2022/lib/field-types/password-field.component.mjs +109 -0
  17. package/esm2022/lib/field-types/radio-field.component.mjs +152 -0
  18. package/esm2022/lib/field-types/text-field.component.mjs +82 -42
  19. package/esm2022/lib/field-types/textarea-field.component.mjs +52 -41
  20. package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +44 -26
  21. package/esm2022/lib/form/dynamic-form.component.mjs +501 -67
  22. package/esm2022/lib/form/dynamic-record-form.component.mjs +469 -0
  23. package/esm2022/lib/providers/provide-field-types.mjs +72 -0
  24. package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +3 -5
  25. package/esm2022/lib/services/cascade-data.service.mjs +129 -0
  26. package/esm2022/lib/services/config-source.service.mjs +67 -0
  27. package/esm2022/lib/services/entity-ref-cache.mjs +20 -0
  28. package/esm2022/lib/services/entity-ref-registry.service.mjs +3 -3
  29. package/esm2022/lib/services/entity-ref-selection.service.mjs +27 -0
  30. package/esm2022/lib/services/entity-reference.service.mjs +168 -0
  31. package/esm2022/lib/services/field-registry.service.mjs +35 -30
  32. package/esm2022/lib/services/file-upload.service.mjs +89 -0
  33. package/esm2022/lib/services/lookup-registry.service.mjs +246 -0
  34. package/esm2022/lib/services/rbac.service.mjs +5 -11
  35. package/esm2022/lib/services/rules-evaluation.service.mjs +27 -0
  36. package/esm2022/lib/services/validator-registry.service.mjs +24 -7
  37. package/esm2022/lib/tokens/injection-tokens.mjs +88 -7
  38. package/esm2022/public-api.mjs +14 -5
  39. package/fesm2022/ngx-dynamic-entity.mjs +3985 -876
  40. package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
  41. package/lib/field-types/array-field.component.d.ts +22 -0
  42. package/lib/field-types/boolean-field.component.d.ts +18 -0
  43. package/lib/field-types/checkbox-field.component.d.ts +3 -2
  44. package/lib/field-types/currency-field.component.d.ts +17 -0
  45. package/lib/field-types/date-field.component.d.ts +3 -2
  46. package/lib/field-types/dropdown-field.component.d.ts +24 -4
  47. package/lib/field-types/email-field.component.d.ts +15 -0
  48. package/lib/field-types/entity-ref-field.component.d.ts +24 -11
  49. package/lib/field-types/file-field.component.d.ts +25 -0
  50. package/lib/field-types/group-field.component.d.ts +17 -0
  51. package/lib/field-types/image-field.component.d.ts +30 -0
  52. package/lib/field-types/month-year-field.component.d.ts +28 -0
  53. package/lib/field-types/multi-select-field.component.d.ts +18 -4
  54. package/lib/field-types/number-field.component.d.ts +5 -2
  55. package/lib/field-types/password-field.component.d.ts +17 -0
  56. package/lib/field-types/radio-field.component.d.ts +33 -0
  57. package/lib/field-types/text-field.component.d.ts +5 -3
  58. package/lib/field-types/textarea-field.component.d.ts +4 -2
  59. package/lib/form/dynamic-field/dynamic-field.component.d.ts +20 -7
  60. package/lib/form/dynamic-form.component.d.ts +111 -19
  61. package/lib/form/dynamic-record-form.component.d.ts +169 -0
  62. package/lib/providers/provide-field-types.d.ts +24 -0
  63. package/lib/providers/provide-ngx-dynamic-entity.d.ts +12 -7
  64. package/lib/services/cascade-data.service.d.ts +45 -0
  65. package/lib/services/config-source.service.d.ts +14 -0
  66. package/lib/services/entity-ref-cache.d.ts +27 -0
  67. package/lib/services/entity-ref-registry.service.d.ts +4 -3
  68. package/lib/services/entity-ref-selection.service.d.ts +24 -0
  69. package/lib/services/entity-reference.service.d.ts +49 -0
  70. package/lib/services/field-registry.service.d.ts +17 -7
  71. package/lib/services/file-upload.service.d.ts +27 -0
  72. package/lib/services/lookup-registry.service.d.ts +94 -0
  73. package/lib/services/rbac.service.d.ts +4 -9
  74. package/lib/services/rules-evaluation.service.d.ts +17 -0
  75. package/lib/services/validator-registry.service.d.ts +5 -4
  76. package/lib/tokens/injection-tokens.d.ts +90 -7
  77. package/package.json +14 -3
  78. package/public-api.d.ts +11 -4
  79. package/esm2022/lib/services/config.service.mjs +0 -58
  80. package/esm2022/lib/services/version.service.mjs +0 -40
  81. package/esm2022/lib/table/dynamic-table.component.mjs +0 -160
  82. package/lib/services/config.service.d.ts +0 -25
  83. package/lib/services/version.service.d.ts +0 -26
  84. package/lib/table/dynamic-table.component.d.ts +0 -56
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # ngx-dynamic-entity
2
+
3
+ Angular dynamic form renderer and tabbed record editor, powered by `@dynamic-entity/core`.
4
+
5
+ ## Features
6
+ - **DynamicFormComponent** — rich tabbed forms from `EntityFormConfig`, built on signals and reactive forms.
7
+ - **DynamicRecordFormComponent** — record editor with summary drawer (`showOnMinimize`), profile header, and session-baseline tracking.
8
+ - **Rules engine** — condition evaluation, info/warning/error banners, field and tab hiding.
9
+ - **Entity references with cascades** — consumer-registered loaders, parent→child filtering, `autoPatch`.
10
+ - **19 field type keys** across 18 components — including date, month-year, entity-ref, file, and image.
11
+
12
+ ## Installation
13
+ ```bash
14
+ npm install ngx-dynamic-entity @dynamic-entity/core
15
+ ```
16
+
17
+ ## Setup
18
+
19
+ Two providers: one for services and registries, one for field components.
20
+
21
+ ```ts
22
+ import {
23
+ provideNgxDynamicEntity,
24
+ provideBuiltInFieldTypes,
25
+ } from 'ngx-dynamic-entity';
26
+
27
+ export const appConfig: ApplicationConfig = {
28
+ providers: [
29
+ provideNgxDynamicEntity({
30
+ maskedRoles: ['IT_SUPPORT'],
31
+ entityRefs: { countries: ctx => api.listCountries(ctx) },
32
+ }),
33
+ provideBuiltInFieldTypes(),
34
+ ],
35
+ };
36
+ ```
37
+
38
+ ### Field components are opt-in (tree-shaking)
39
+
40
+ `FieldRegistryService` imports no components. Only what you register is bundled — so an app
41
+ that renders three field types does not ship nineteen.
42
+
43
+ ```ts
44
+ // Everything (simplest):
45
+ provideBuiltInFieldTypes()
46
+
47
+ // Or only what this app renders:
48
+ provideFieldTypes({
49
+ text: TextFieldComponent,
50
+ number: NumberFieldComponent,
51
+ dropdown: DropdownFieldComponent,
52
+ })
53
+ ```
54
+
55
+ `provideFieldTypes` is a multi-provider: several calls compose, and a later set wins on a key
56
+ collision. `provideNgxDynamicEntity({ fieldTypes })` still overrides everything — use it to
57
+ swap a built-in for your own component. An unregistered type renders nothing and logs a
58
+ console warning in dev builds.
59
+
60
+ ## Rendering
61
+
62
+ ```html
63
+ <ngx-dynamic-form
64
+ [config]="formConfig"
65
+ [rules]="formRules"
66
+ [initialData]="initialRecord"
67
+ [originalData]="sessionBaseline"
68
+ (formSubmit)="onSave($event)"
69
+ />
70
+ ```
71
+
72
+ ## Entity references and cascades
73
+
74
+ Register a loader per entity key. It receives `{ parentValue, filters, lang }` and may return
75
+ an array, a Promise, or an Observable of `ReferenceOption[]`:
76
+
77
+ ```ts
78
+ provideNgxDynamicEntity({
79
+ entityRefs: {
80
+ countries: () => http.get<ReferenceOption[]>('/api/countries'),
81
+ cities: ctx => http.get<ReferenceOption[]>('/api/cities', { params: { country: ctx?.parentValue } }),
82
+ },
83
+ });
84
+ ```
85
+
86
+ A field cascades when its `entityReference.parentField` names a sibling. The child reloads on
87
+ every parent change, drops a now-invalid selection, and shows nothing until the parent has a
88
+ value. Filtering happens server-side (via `parentValue`) or client-side:
89
+
90
+ - `lookupFilter` — keep options whose record matches the parent value at that dot-path.
91
+ - `lookupPath` — take options from a nested array on the selected parent's record.
92
+
93
+ Raw records are labelled through `entityReference.displayFields`; the full record rides along on
94
+ `ReferenceOption.record`, which is what `autoPatch` copies from.
95
+
96
+ ## autoPatch and patchOnTrue
97
+
98
+ ```jsonc
99
+ // Selecting a company fills in its address on the "address" tab
100
+ { "id": "company", "type": "entity-ref",
101
+ "autoPatch": { "targetTab": "address", "mappings": [{ "source": "city", "target": "city" }] } }
102
+
103
+ // Ticking "same as home" copies one field into another
104
+ { "id": "billingSame", "type": "boolean", "patchOnTrue": [{ "from": "home", "to": "billing" }] }
105
+ ```
106
+
107
+ `patchOnTrue` fires on the false→true transition only, so a later manual edit is not clobbered.
108
+
109
+ ## criticalField
110
+
111
+ A field marked `criticalField` renders read-only behind a lock toggle. Once unlocked and
112
+ changed, the form shows a deferred notice naming the field — compared against the session
113
+ baseline (`originalData`, or the values captured at first build). The same baseline feeds
114
+ `VALUE_CHANGED` rules.
115
+
116
+ ## File and image fields
117
+
118
+ Both store a `FileRef`. Register an upload handler to persist on select:
119
+
120
+ ```ts
121
+ { provide: UPLOAD_HANDLER, useValue: (file: File) => http.post<{url: string}>('/upload', file) }
122
+ ```
123
+
124
+ With a handler the value is `{ url, name, size, mimeType }`; without one it is
125
+ `{ file, name, size, mimeType }` for you to upload at submit time. Image previews use object
126
+ URLs for unpersisted files and revoke them automatically.
127
+
128
+ ## Injection tokens
129
+
130
+ | Token | Purpose |
131
+ |---|---|
132
+ | `MASKED_ROLES` | Roles that see `XXXXXXXXX` for masked fields |
133
+ | `FIELD_TYPE_REGISTRY` | Consumer overrides: field type → component (highest priority) |
134
+ | `FIELD_TYPE_SETS` | Multi: field-type sets contributed by `provideFieldTypes()` |
135
+ | `ENTITY_REF_REGISTRY` | Entity key → `EntityReferenceLoader` |
136
+ | `VALIDATOR_REGISTRY` | Validator name → `ValidatorFn` |
137
+ | `HOOK_REGISTRY` | Hook key → handler (e.g. `entity:beforeSave`) |
138
+ | `COMMON_MODULES_REGISTRY` | Consumer-provided shared tab modules |
139
+ | `UPLOAD_HANDLER` | `(file) => UploadResult \| Promise \| Observable` |
@@ -0,0 +1,160 @@
1
+ import { Component, Input, inject, forwardRef } from '@angular/core';
2
+ import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
3
+ import { resolveLabel } from '@dynamic-entity/core';
4
+ import { DynamicFieldComponent } from '../form/dynamic-field/dynamic-field.component';
5
+ import { ValidatorRegistryService } from '../services/validator-registry.service';
6
+ import * as i0 from "@angular/core";
7
+ /** ADR-008: ArrayFieldComponent — renders repeating rows for FormArray with + Add Item and Remove */
8
+ export class ArrayFieldComponent {
9
+ field;
10
+ control;
11
+ config;
12
+ language = 'en';
13
+ readonly = false;
14
+ masked = false;
15
+ userRoles = [];
16
+ fb = inject(FormBuilder);
17
+ validatorRegistry = inject(ValidatorRegistryService);
18
+ get label() {
19
+ return resolveLabel(this.field?.label, this.language);
20
+ }
21
+ get formArray() {
22
+ return this.control;
23
+ }
24
+ getItemChildControl(itemGroup, childId) {
25
+ return itemGroup.get(childId);
26
+ }
27
+ addItem() {
28
+ const controls = {};
29
+ for (const child of this.field.children ?? []) {
30
+ const validators = this.validatorRegistry.resolveFromConfig(child.validators);
31
+ controls[child.id] = [child.defaultValue ?? null, validators];
32
+ }
33
+ const group = this.fb.group(controls);
34
+ this.formArray.push(group);
35
+ }
36
+ removeItem(index) {
37
+ this.formArray.removeAt(index);
38
+ }
39
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
40
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ArrayFieldComponent, isStandalone: true, selector: "ngx-array-field", inputs: { field: "field", control: "control", config: "config", language: "language", readonly: "readonly", masked: "masked", userRoles: "userRoles" }, ngImport: i0, template: `
41
+ <div class="ngx-field ngx-field--array"
42
+ [attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
43
+ <div class="ngx-field__array-header">
44
+ <label class="ngx-field__label">{{ label }}</label>
45
+ @if (!readonly && !masked) {
46
+ <button type="button" class="ngx-field__array-add-btn"
47
+ [attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
48
+ + Add Item
49
+ </button>
50
+ }
51
+ </div>
52
+
53
+ @if (masked) {
54
+ <span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
55
+ } @else {
56
+ <div class="ngx-field__array-list">
57
+ @for (itemGroup of formArray.controls; track idx; let idx = $index) {
58
+ <div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
59
+ <div class="ngx-field__array-item-header">
60
+ <span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
61
+ @if (!readonly) {
62
+ <button type="button" class="ngx-field__array-remove-btn"
63
+ [attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
64
+ Remove
65
+ </button>
66
+ }
67
+ </div>
68
+ <div class="ngx-field__array-item-fields">
69
+ @for (child of field.children ?? []; track child.id) {
70
+ @if (child.visibility !== false) {
71
+ <ngx-dynamic-field
72
+ [field]="child"
73
+ [control]="getItemChildControl(itemGroup, child.id)"
74
+ [config]="config"
75
+ [language]="language"
76
+ [readonly]="readonly || !!child.readonly"
77
+ [userRoles]="userRoles"
78
+ />
79
+ }
80
+ }
81
+ </div>
82
+ </div>
83
+ }
84
+ @if (formArray.controls.length === 0) {
85
+ <div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
86
+ }
87
+ </div>
88
+ }
89
+ </div>
90
+ `, isInline: true, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "component", type: i0.forwardRef(() => DynamicFieldComponent), selector: "ngx-dynamic-field", inputs: ["field", "control", "config", "currentTabId", "language", "readonly", "userRoles"] }] });
91
+ }
92
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayFieldComponent, decorators: [{
93
+ type: Component,
94
+ args: [{ selector: 'ngx-array-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => DynamicFieldComponent)], template: `
95
+ <div class="ngx-field ngx-field--array"
96
+ [attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
97
+ <div class="ngx-field__array-header">
98
+ <label class="ngx-field__label">{{ label }}</label>
99
+ @if (!readonly && !masked) {
100
+ <button type="button" class="ngx-field__array-add-btn"
101
+ [attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
102
+ + Add Item
103
+ </button>
104
+ }
105
+ </div>
106
+
107
+ @if (masked) {
108
+ <span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
109
+ } @else {
110
+ <div class="ngx-field__array-list">
111
+ @for (itemGroup of formArray.controls; track idx; let idx = $index) {
112
+ <div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
113
+ <div class="ngx-field__array-item-header">
114
+ <span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
115
+ @if (!readonly) {
116
+ <button type="button" class="ngx-field__array-remove-btn"
117
+ [attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
118
+ Remove
119
+ </button>
120
+ }
121
+ </div>
122
+ <div class="ngx-field__array-item-fields">
123
+ @for (child of field.children ?? []; track child.id) {
124
+ @if (child.visibility !== false) {
125
+ <ngx-dynamic-field
126
+ [field]="child"
127
+ [control]="getItemChildControl(itemGroup, child.id)"
128
+ [config]="config"
129
+ [language]="language"
130
+ [readonly]="readonly || !!child.readonly"
131
+ [userRoles]="userRoles"
132
+ />
133
+ }
134
+ }
135
+ </div>
136
+ </div>
137
+ }
138
+ @if (formArray.controls.length === 0) {
139
+ <div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
140
+ }
141
+ </div>
142
+ }
143
+ </div>
144
+ `, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\n"] }]
145
+ }], propDecorators: { field: [{
146
+ type: Input
147
+ }], control: [{
148
+ type: Input
149
+ }], config: [{
150
+ type: Input
151
+ }], language: [{
152
+ type: Input
153
+ }], readonly: [{
154
+ type: Input
155
+ }], masked: [{
156
+ type: Input
157
+ }], userRoles: [{
158
+ type: Input
159
+ }] } });
160
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9hcnJheS1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyRSxPQUFPLEVBQThCLFdBQVcsRUFBYSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUN0RixPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQzs7QUFFbEYscUdBQXFHO0FBNEhyRyxNQUFNLE9BQU8sbUJBQW1CO0lBQ3JCLEtBQUssQ0FBcUI7SUFDMUIsT0FBTyxDQUFtQjtJQUMxQixNQUFNLENBQW9CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBQ3hCLFNBQVMsR0FBYSxFQUFFLENBQUM7SUFFakIsRUFBRSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QixpQkFBaUIsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUV0RSxJQUFJLEtBQUs7UUFDUCxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLE9BQW9CLENBQUM7SUFDbkMsQ0FBQztJQUVELG1CQUFtQixDQUFDLFNBQTBCLEVBQUUsT0FBZTtRQUM3RCxPQUFRLFNBQXVCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBb0IsQ0FBQztJQUNsRSxDQUFDO0lBRUQsT0FBTztRQUNMLE1BQU0sUUFBUSxHQUF3QixFQUFFLENBQUM7UUFDekMsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUM5QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzlFLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxJQUFJLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFhO1FBQ3RCLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7d0dBcENVLG1CQUFtQjs0RkFBbkIsbUJBQW1CLG1PQXZIcEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0RULDZrQ0FuRFMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQXdIMUQsbUJBQW1CO2tCQTNIL0IsU0FBUzsrQkFDRSxpQkFBaUIsY0FDZixJQUFJLFdBQ1AsQ0FBQyxtQkFBbUIsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLENBQUMsQ0FBQyxZQUM3RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrRFQ7OEJBc0VRLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIGluamVjdCwgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1BcnJheSwgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZywgRW50aXR5Rm9ybUNvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBEeW5hbWljRmllbGRDb21wb25lbnQgfSBmcm9tICcuLi9mb3JtL2R5bmFtaWMtZmllbGQvZHluYW1pYy1maWVsZC5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy92YWxpZGF0b3ItcmVnaXN0cnkuc2VydmljZSc7XHJcblxyXG4vKiogQURSLTAwODogQXJyYXlGaWVsZENvbXBvbmVudCDigJQgcmVuZGVycyByZXBlYXRpbmcgcm93cyBmb3IgRm9ybUFycmF5IHdpdGggKyBBZGQgSXRlbSBhbmQgUmVtb3ZlICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LWFycmF5LWZpZWxkJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBmb3J3YXJkUmVmKCgpID0+IER5bmFtaWNGaWVsZENvbXBvbmVudCldLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tYXJyYXlcIlxyXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cclxuICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaGVhZGVyXCI+XHJcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiPnt7IGxhYmVsIH19PC9sYWJlbD5cclxuICAgICAgICBAaWYgKCFyZWFkb25seSAmJiAhbWFza2VkKSB7XHJcbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktYWRkLWJ0blwiXHJcbiAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWFkZCdcIiAoY2xpY2spPVwiYWRkSXRlbSgpXCI+XHJcbiAgICAgICAgICAgICsgQWRkIEl0ZW1cclxuICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgIH1cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICBAaWYgKG1hc2tlZCkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1saXN0XCI+XHJcbiAgICAgICAgICBAZm9yIChpdGVtR3JvdXAgb2YgZm9ybUFycmF5LmNvbnRyb2xzOyB0cmFjayBpZHg7IGxldCBpZHggPSAkaW5kZXgpIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJvdydcIj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1pdGVtLWhlYWRlclwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGVcIj5JdGVtICN7eyBpZHggKyAxIH19PC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgQGlmICghcmVhZG9ubHkpIHtcclxuICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG5cIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJlbW92ZS0nICsgaWR4XCIgKGNsaWNrKT1cInJlbW92ZUl0ZW0oaWR4KVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIFJlbW92ZVxyXG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1pdGVtLWZpZWxkc1wiPlxyXG4gICAgICAgICAgICAgICAgQGZvciAoY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gPz8gW107IHRyYWNrIGNoaWxkLmlkKSB7XHJcbiAgICAgICAgICAgICAgICAgIEBpZiAoY2hpbGQudmlzaWJpbGl0eSAhPT0gZmFsc2UpIHtcclxuICAgICAgICAgICAgICAgICAgICA8bmd4LWR5bmFtaWMtZmllbGRcclxuICAgICAgICAgICAgICAgICAgICAgIFtmaWVsZF09XCJjaGlsZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbY29udHJvbF09XCJnZXRJdGVtQ2hpbGRDb250cm9sKGl0ZW1Hcm91cCwgY2hpbGQuaWQpXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtjb25maWddPVwiY29uZmlnXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtsYW5ndWFnZV09XCJsYW5ndWFnZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbcmVhZG9ubHldPVwicmVhZG9ubHkgfHwgISFjaGlsZC5yZWFkb25seVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbdXNlclJvbGVzXT1cInVzZXJSb2xlc1wiXHJcbiAgICAgICAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIEBpZiAoZm9ybUFycmF5LmNvbnRyb2xzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1lbXB0eVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWVtcHR5J1wiPk5vIGl0ZW1zIGFkZGVkIHlldC48L2Rpdj5cclxuICAgICAgICAgIH1cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZXM6IFtcclxuICAgIGBcclxuICAgICAgLm5neC1maWVsZC0tYXJyYXkge1xyXG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNlMmU4ZjA7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4O1xyXG4gICAgICAgIHBhZGRpbmc6IDE2cHg7XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTZweDtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjZjhmYWZjO1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWhlYWRlciB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWFkZC1idG4ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICMyNTYzZWI7XHJcbiAgICAgICAgY29sb3I6ICNmZmY7XHJcbiAgICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICAgIHBhZGRpbmc6IDZweCAxMnB4O1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDRweDtcclxuICAgICAgICBmb250LXdlaWdodDogNTAwO1xyXG4gICAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgfVxyXG4gICAgICAubmd4LWZpZWxkX19hcnJheS1hZGQtYnRuOmhvdmVyIHtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjMWQ0ZWQ4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWxpc3Qge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgICBnYXA6IDEycHg7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1maWVsZF9fYXJyYXktaXRlbSB7XHJcbiAgICAgICAgYmFja2dyb3VuZDogI2ZmZjtcclxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjY2JkNWUxO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDZweDtcclxuICAgICAgICBwYWRkaW5nOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0taGVhZGVyIHtcclxuICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDhweDtcclxuICAgICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2YxZjVmOTtcclxuICAgICAgICBwYWRkaW5nLWJvdHRvbTogNnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGUge1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgICAgZm9udC1zaXplOiAxM3B4O1xyXG4gICAgICAgIGNvbG9yOiAjNDc1NTY5O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG4ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICNlZjQ0NDQ7XHJcbiAgICAgICAgY29sb3I6ICNmZmY7XHJcbiAgICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICAgIHBhZGRpbmc6IDRweCA4cHg7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xyXG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcclxuICAgICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1maWVsZF9fYXJyYXktZW1wdHkge1xyXG4gICAgICAgIGNvbG9yOiAjOTRhM2I4O1xyXG4gICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcclxuICAgICAgICBmb250LXNpemU6IDEzcHg7XHJcbiAgICAgIH1cclxuICAgIGAsXHJcbiAgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIEFycmF5RmllbGRDb21wb25lbnQge1xyXG4gIEBJbnB1dCgpIGZpZWxkITogTmVzdGVkRmllbGRDb25maWc7XHJcbiAgQElucHV0KCkgY29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcclxuICBASW5wdXQoKSBjb25maWchOiBFbnRpdHlGb3JtQ29uZmlnO1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xyXG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgdXNlclJvbGVzOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGZiID0gaW5qZWN0KEZvcm1CdWlsZGVyKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHZhbGlkYXRvclJlZ2lzdHJ5ID0gaW5qZWN0KFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSk7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG5cclxuICBnZXQgZm9ybUFycmF5KCk6IEZvcm1BcnJheSB7XHJcbiAgICByZXR1cm4gdGhpcy5jb250cm9sIGFzIEZvcm1BcnJheTtcclxuICB9XHJcblxyXG4gIGdldEl0ZW1DaGlsZENvbnRyb2woaXRlbUdyb3VwOiBBYnN0cmFjdENvbnRyb2wsIGNoaWxkSWQ6IHN0cmluZyk6IEFic3RyYWN0Q29udHJvbCB7XHJcbiAgICByZXR1cm4gKGl0ZW1Hcm91cCBhcyBGb3JtR3JvdXApLmdldChjaGlsZElkKSBhcyBBYnN0cmFjdENvbnRyb2w7XHJcbiAgfVxyXG5cclxuICBhZGRJdGVtKCk6IHZvaWQge1xyXG4gICAgY29uc3QgY29udHJvbHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcclxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgdGhpcy5maWVsZC5jaGlsZHJlbiA/PyBbXSkge1xyXG4gICAgICBjb25zdCB2YWxpZGF0b3JzID0gdGhpcy52YWxpZGF0b3JSZWdpc3RyeS5yZXNvbHZlRnJvbUNvbmZpZyhjaGlsZC52YWxpZGF0b3JzKTtcclxuICAgICAgY29udHJvbHNbY2hpbGQuaWRdID0gW2NoaWxkLmRlZmF1bHRWYWx1ZSA/PyBudWxsLCB2YWxpZGF0b3JzXTtcclxuICAgIH1cclxuICAgIGNvbnN0IGdyb3VwID0gdGhpcy5mYi5ncm91cChjb250cm9scyk7XHJcbiAgICB0aGlzLmZvcm1BcnJheS5wdXNoKGdyb3VwKTtcclxuICB9XHJcblxyXG4gIHJlbW92ZUl0ZW0oaW5kZXg6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5mb3JtQXJyYXkucmVtb3ZlQXQoaW5kZXgpO1xyXG4gIH1cclxufVxyXG4iXX0=
@@ -0,0 +1,100 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { ReactiveFormsModule } from '@angular/forms';
3
+ import { resolveLabel } from '@dynamic-entity/core';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/forms";
6
+ /**
7
+ * Boolean field: a slide-toggle style switch (true/false).
8
+ * Distinct from `checkbox` (which is a standalone bool) in that it renders as a
9
+ * toggle switch with Yes/No labels for clearer binary state communication.
10
+ */
11
+ export class BooleanFieldComponent {
12
+ field;
13
+ control;
14
+ language = 'en';
15
+ readonly = false;
16
+ masked = false;
17
+ get label() {
18
+ return resolveLabel(this.field?.label, this.language);
19
+ }
20
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BooleanFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
21
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: BooleanFieldComponent, isStandalone: true, selector: "ngx-boolean-field", inputs: { field: "field", control: "control", language: "language", readonly: "readonly", masked: "masked" }, ngImport: i0, template: `
22
+ <div class="ngx-field ngx-field--boolean"
23
+ [attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
24
+ @if (masked) {
25
+ <label class="ngx-field__label">{{ label }}</label>
26
+ <span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
27
+ } @else if (readonly) {
28
+ <label class="ngx-field__label">{{ label }}</label>
29
+ <span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ control.value ? 'Yes' : 'No' }}</span>
30
+ } @else {
31
+ <div class="ngx-field__toggle-wrap">
32
+ <label class="ngx-field__toggle-label">{{ label }}</label>
33
+ <label class="ngx-field__toggle-switch" [class.ngx-field__toggle-switch--checked]="control.value">
34
+ <input
35
+ class="ngx-field__toggle-input"
36
+ type="checkbox"
37
+ role="switch"
38
+ [formControl]="$any(control)"
39
+ [attr.disabled]="field.disabled ? true : null"
40
+ [attr.aria-checked]="control.value"
41
+ />
42
+ <span class="ngx-field__toggle-track">
43
+ <span class="ngx-field__toggle-thumb"></span>
44
+ </span>
45
+ <span class="ngx-field__toggle-text">{{ control.value ? 'Yes' : 'No' }}</span>
46
+ </label>
47
+ </div>
48
+ }
49
+ </div>
50
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
51
+ }
52
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BooleanFieldComponent, decorators: [{
53
+ type: Component,
54
+ args: [{
55
+ selector: 'ngx-boolean-field',
56
+ standalone: true,
57
+ imports: [ReactiveFormsModule],
58
+ template: `
59
+ <div class="ngx-field ngx-field--boolean"
60
+ [attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
61
+ @if (masked) {
62
+ <label class="ngx-field__label">{{ label }}</label>
63
+ <span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
64
+ } @else if (readonly) {
65
+ <label class="ngx-field__label">{{ label }}</label>
66
+ <span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ control.value ? 'Yes' : 'No' }}</span>
67
+ } @else {
68
+ <div class="ngx-field__toggle-wrap">
69
+ <label class="ngx-field__toggle-label">{{ label }}</label>
70
+ <label class="ngx-field__toggle-switch" [class.ngx-field__toggle-switch--checked]="control.value">
71
+ <input
72
+ class="ngx-field__toggle-input"
73
+ type="checkbox"
74
+ role="switch"
75
+ [formControl]="$any(control)"
76
+ [attr.disabled]="field.disabled ? true : null"
77
+ [attr.aria-checked]="control.value"
78
+ />
79
+ <span class="ngx-field__toggle-track">
80
+ <span class="ngx-field__toggle-thumb"></span>
81
+ </span>
82
+ <span class="ngx-field__toggle-text">{{ control.value ? 'Yes' : 'No' }}</span>
83
+ </label>
84
+ </div>
85
+ }
86
+ </div>
87
+ `,
88
+ }]
89
+ }], propDecorators: { field: [{
90
+ type: Input
91
+ }], control: [{
92
+ type: Input
93
+ }], language: [{
94
+ type: Input
95
+ }], readonly: [{
96
+ type: Input
97
+ }], masked: [{
98
+ type: Input
99
+ }] } });
100
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vbGVhbi1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2ZpZWxkLXR5cGVzL2Jvb2xlYW4tZmllbGQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sRUFBbUIsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV0RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7OztBQUVwRDs7OztHQUlHO0FBb0NILE1BQU0sT0FBTyxxQkFBcUI7SUFDdkIsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQW1CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBRWpDLElBQUksS0FBSztRQUNQLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RCxDQUFDO3dHQVRVLHFCQUFxQjs0RkFBckIscUJBQXFCLDJMQS9CdEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNkJULDJEQTlCUyxtQkFBbUI7OzRGQWdDbEIscUJBQXFCO2tCQW5DakMsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsbUJBQW1CO29CQUM3QixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsT0FBTyxFQUFFLENBQUMsbUJBQW1CLENBQUM7b0JBQzlCLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2QlQ7aUJBQ0Y7OEJBRVUsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB0eXBlIHsgTmVzdGVkRmllbGRDb25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XHJcbmltcG9ydCB7IHJlc29sdmVMYWJlbCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuXHJcbi8qKlxyXG4gKiBCb29sZWFuIGZpZWxkOiBhIHNsaWRlLXRvZ2dsZSBzdHlsZSBzd2l0Y2ggKHRydWUvZmFsc2UpLlxyXG4gKiBEaXN0aW5jdCBmcm9tIGBjaGVja2JveGAgKHdoaWNoIGlzIGEgc3RhbmRhbG9uZSBib29sKSBpbiB0aGF0IGl0IHJlbmRlcnMgYXMgYVxyXG4gKiB0b2dnbGUgc3dpdGNoIHdpdGggWWVzL05vIGxhYmVscyBmb3IgY2xlYXJlciBiaW5hcnkgc3RhdGUgY29tbXVuaWNhdGlvbi5cclxuICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LWJvb2xlYW4tZmllbGQnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1JlYWN0aXZlRm9ybXNNb2R1bGVdLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tYm9vbGVhblwiXHJcbiAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIiBbYXR0ci5kYXRhLWZpZWxkLXR5cGVdPVwiZmllbGQudHlwZVwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxyXG4gICAgICBAaWYgKG1hc2tlZCkge1xyXG4gICAgICAgIDxsYWJlbCBjbGFzcz1cIm5neC1maWVsZF9fbGFiZWxcIj57eyBsYWJlbCB9fTwvbGFiZWw+XHJcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlIG5neC1maWVsZF9fdmFsdWUtLW1hc2tlZFwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLW1hc2tlZCdcIj5YWFhYWFhYWFg8L3NwYW4+XHJcbiAgICAgIH0gQGVsc2UgaWYgKHJlYWRvbmx5KSB7XHJcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiPnt7IGxhYmVsIH19PC9sYWJlbD5cclxuICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdmFsdWVcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy12YWx1ZSdcIj57eyBjb250cm9sLnZhbHVlID8gJ1llcycgOiAnTm8nIH19PC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX190b2dnbGUtd3JhcFwiPlxyXG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX190b2dnbGUtbGFiZWxcIj57eyBsYWJlbCB9fTwvbGFiZWw+XHJcbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX3RvZ2dsZS1zd2l0Y2hcIiBbY2xhc3Mubmd4LWZpZWxkX190b2dnbGUtc3dpdGNoLS1jaGVja2VkXT1cImNvbnRyb2wudmFsdWVcIj5cclxuICAgICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgICAgY2xhc3M9XCJuZ3gtZmllbGRfX3RvZ2dsZS1pbnB1dFwiXHJcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcclxuICAgICAgICAgICAgICByb2xlPVwic3dpdGNoXCJcclxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwiJGFueShjb250cm9sKVwiXHJcbiAgICAgICAgICAgICAgW2F0dHIuZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgPyB0cnVlIDogbnVsbFwiXHJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1jaGVja2VkXT1cImNvbnRyb2wudmFsdWVcIlxyXG4gICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdG9nZ2xlLXRyYWNrXCI+XHJcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3RvZ2dsZS10aHVtYlwiPjwvc3Bhbj5cclxuICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdG9nZ2xlLXRleHRcIj57eyBjb250cm9sLnZhbHVlID8gJ1llcycgOiAnTm8nIH19PC9zcGFuPlxyXG4gICAgICAgICAgPC9sYWJlbD5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxufSlcclxuZXhwb3J0IGNsYXNzIEJvb2xlYW5GaWVsZENvbXBvbmVudCB7XHJcbiAgQElucHV0KCkgZmllbGQhOiBOZXN0ZWRGaWVsZENvbmZpZztcclxuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xyXG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG59XHJcbiJdfQ==
@@ -1,5 +1,6 @@
1
1
  import { Component, Input } from '@angular/core';
2
2
  import { ReactiveFormsModule } from '@angular/forms';
3
+ import { resolveLabel } from '@dynamic-entity/core';
3
4
  import * as i0 from "@angular/core";
4
5
  import * as i1 from "@angular/forms";
5
6
  export class CheckboxFieldComponent {
@@ -8,27 +9,32 @@ export class CheckboxFieldComponent {
8
9
  language = 'en';
9
10
  readonly = false;
10
11
  masked = false;
12
+ get label() {
13
+ return resolveLabel(this.field?.label, this.language);
14
+ }
11
15
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: CheckboxFieldComponent, isStandalone: true, selector: "ngx-checkbox-field", inputs: { field: "field", control: "control", language: "language", readonly: "readonly", masked: "masked" }, ngImport: i0, template: `
13
- <div class="ngx-field ngx-field--checkbox" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
14
- @if (masked) {
15
- <label class="ngx-field__label">{{ field.label[language] || field.label['en'] }}</label>
16
- <span class="ngx-field__value ngx-field__value--masked">XXXXXXXXX</span>
17
- } @else if (readonly) {
18
- <label class="ngx-field__label">{{ field.label[language] || field.label['en'] }}</label>
19
- <span class="ngx-field__value">{{ control.value ? 'Yes' : 'No' }}</span>
20
- } @else {
21
- <label class="ngx-field__label">
22
- <input
23
- class="ngx-field__input"
24
- type="checkbox"
25
- [formControl]="$any(control)"
26
- [attr.disabled]="field.disabled ? true : null"
27
- />
28
- {{ field.label[language] || field.label['en'] }}
29
- </label>
30
- }
31
- </div>
16
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: CheckboxFieldComponent, isStandalone: true, selector: "ngx-checkbox-field", inputs: { field: "field", control: "control", language: "language", readonly: "readonly", masked: "masked" }, ngImport: i0, template: `
17
+ <div class="ngx-field ngx-field--checkbox"
18
+ [attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
19
+ @if (masked) {
20
+ <label class="ngx-field__label">{{ label }}</label>
21
+ <span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
22
+ } @else if (readonly) {
23
+ <label class="ngx-field__label">{{ label }}</label>
24
+ <span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ control.value ? 'Yes' : 'No' }}</span>
25
+ } @else {
26
+ <label class="ngx-field__label" [attr.for]="field.id">
27
+ <input
28
+ [id]="field.id"
29
+ class="ngx-field__input" [attr.data-testid]="'field-' + field.id + '-input'"
30
+ type="checkbox"
31
+ [formControl]="$any(control)"
32
+ [attr.disabled]="field.disabled ? true : null"
33
+ />
34
+ {{ label }}
35
+ </label>
36
+ }
37
+ </div>
32
38
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
33
39
  }
34
40
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CheckboxFieldComponent, decorators: [{
@@ -37,26 +43,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
37
43
  selector: 'ngx-checkbox-field',
38
44
  standalone: true,
39
45
  imports: [ReactiveFormsModule],
40
- template: `
41
- <div class="ngx-field ngx-field--checkbox" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
42
- @if (masked) {
43
- <label class="ngx-field__label">{{ field.label[language] || field.label['en'] }}</label>
44
- <span class="ngx-field__value ngx-field__value--masked">XXXXXXXXX</span>
45
- } @else if (readonly) {
46
- <label class="ngx-field__label">{{ field.label[language] || field.label['en'] }}</label>
47
- <span class="ngx-field__value">{{ control.value ? 'Yes' : 'No' }}</span>
48
- } @else {
49
- <label class="ngx-field__label">
50
- <input
51
- class="ngx-field__input"
52
- type="checkbox"
53
- [formControl]="$any(control)"
54
- [attr.disabled]="field.disabled ? true : null"
55
- />
56
- {{ field.label[language] || field.label['en'] }}
57
- </label>
58
- }
59
- </div>
46
+ template: `
47
+ <div class="ngx-field ngx-field--checkbox"
48
+ [attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
49
+ @if (masked) {
50
+ <label class="ngx-field__label">{{ label }}</label>
51
+ <span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
52
+ } @else if (readonly) {
53
+ <label class="ngx-field__label">{{ label }}</label>
54
+ <span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ control.value ? 'Yes' : 'No' }}</span>
55
+ } @else {
56
+ <label class="ngx-field__label" [attr.for]="field.id">
57
+ <input
58
+ [id]="field.id"
59
+ class="ngx-field__input" [attr.data-testid]="'field-' + field.id + '-input'"
60
+ type="checkbox"
61
+ [formControl]="$any(control)"
62
+ [attr.disabled]="field.disabled ? true : null"
63
+ />
64
+ {{ label }}
65
+ </label>
66
+ }
67
+ </div>
60
68
  `,
61
69
  }]
62
70
  }], propDecorators: { field: [{
@@ -70,4 +78,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
70
78
  }], masked: [{
71
79
  type: Input
72
80
  }] } });
73
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2tib3gtZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9jaGVja2JveC1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDakQsT0FBTyxFQUFtQixtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUE2QnRFLE1BQU0sT0FBTyxzQkFBc0I7SUFDeEIsS0FBSyxDQUFlO0lBQ3BCLE9BQU8sQ0FBbUI7SUFDMUIsUUFBUSxHQUFXLElBQUksQ0FBQztJQUN4QixRQUFRLEdBQVksS0FBSyxDQUFDO0lBQzFCLE1BQU0sR0FBWSxLQUFLLENBQUM7d0dBTHRCLHNCQUFzQjs0RkFBdEIsc0JBQXNCLDRMQXRCdkI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JULDJEQXJCUyxtQkFBbUI7OzRGQXVCbEIsc0JBQXNCO2tCQTFCbEMsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsb0JBQW9CO29CQUM5QixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsT0FBTyxFQUFFLENBQUMsbUJBQW1CLENBQUM7b0JBQzlCLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQlQ7aUJBQ0Y7OEJBRVUsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHR5cGUgeyBGaWVsZENvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWNoZWNrYm94LWZpZWxkJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1JlYWN0aXZlRm9ybXNNb2R1bGVdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGQgbmd4LWZpZWxkLS1jaGVja2JveFwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxuICAgICAgQGlmIChtYXNrZWQpIHtcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiPnt7IGZpZWxkLmxhYmVsW2xhbmd1YWdlXSB8fCBmaWVsZC5sYWJlbFsnZW4nXSB9fTwvbGFiZWw+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIj5YWFhYWFhYWFg8L3NwYW4+XG4gICAgICB9IEBlbHNlIGlmIChyZWFkb25seSkge1xuICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX2xhYmVsXCI+e3sgZmllbGQubGFiZWxbbGFuZ3VhZ2VdIHx8IGZpZWxkLmxhYmVsWydlbiddIH19PC9sYWJlbD5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlXCI+e3sgY29udHJvbC52YWx1ZSA/ICdZZXMnIDogJ05vJyB9fTwvc3Bhbj5cbiAgICAgIH0gQGVsc2Uge1xuICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX2xhYmVsXCI+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBjbGFzcz1cIm5neC1maWVsZF9faW5wdXRcIlxuICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCIkYW55KGNvbnRyb2wpXCJcbiAgICAgICAgICAgIFthdHRyLmRpc2FibGVkXT1cImZpZWxkLmRpc2FibGVkID8gdHJ1ZSA6IG51bGxcIlxuICAgICAgICAgIC8+XG4gICAgICAgICAge3sgZmllbGQubGFiZWxbbGFuZ3VhZ2VdIHx8IGZpZWxkLmxhYmVsWydlbiddIH19XG4gICAgICAgIDwvbGFiZWw+XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIGAsXG59KVxuZXhwb3J0IGNsYXNzIENoZWNrYm94RmllbGRDb21wb25lbnQge1xuICBASW5wdXQoKSBmaWVsZCE6IEZpZWxkQ29uZmlnO1xuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XG59XG4iXX0=
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2tib3gtZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9jaGVja2JveC1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDakQsT0FBTyxFQUFtQixtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXRFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7O0FBOEJwRCxNQUFNLE9BQU8sc0JBQXNCO0lBQ3hCLEtBQUssQ0FBcUI7SUFDMUIsT0FBTyxDQUFtQjtJQUMxQixRQUFRLEdBQVcsSUFBSSxDQUFDO0lBQ3hCLFFBQVEsR0FBWSxLQUFLLENBQUM7SUFDMUIsTUFBTSxHQUFZLEtBQUssQ0FBQztJQUVqQyxJQUFJLEtBQUs7UUFDUCxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEQsQ0FBQzt3R0FUVSxzQkFBc0I7NEZBQXRCLHNCQUFzQiw0TEF4QnZCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JULDJEQXZCUyxtQkFBbUI7OzRGQXlCbEIsc0JBQXNCO2tCQTVCbEMsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsb0JBQW9CO29CQUM5QixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsT0FBTyxFQUFFLENBQUMsbUJBQW1CLENBQUM7b0JBQzlCLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCVDtpQkFDRjs4QkFFVSxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZ3gtY2hlY2tib3gtZmllbGQnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1JlYWN0aXZlRm9ybXNNb2R1bGVdLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tY2hlY2tib3hcIlxyXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cclxuICAgICAgQGlmIChtYXNrZWQpIHtcclxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX2xhYmVsXCI+e3sgbGFiZWwgfX08L2xhYmVsPlxyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIGlmIChyZWFkb25seSkge1xyXG4gICAgICAgIDxsYWJlbCBjbGFzcz1cIm5neC1maWVsZF9fbGFiZWxcIj57eyBsYWJlbCB9fTwvbGFiZWw+XHJcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctdmFsdWUnXCI+e3sgY29udHJvbC52YWx1ZSA/ICdZZXMnIDogJ05vJyB9fTwvc3Bhbj5cclxuICAgICAgfSBAZWxzZSB7XHJcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiIFthdHRyLmZvcl09XCJmaWVsZC5pZFwiPlxyXG4gICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgIFtpZF09XCJmaWVsZC5pZFwiXHJcbiAgICAgICAgICAgIGNsYXNzPVwibmd4LWZpZWxkX19pbnB1dFwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWlucHV0J1wiXHJcbiAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXHJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCIkYW55KGNvbnRyb2wpXCJcclxuICAgICAgICAgICAgW2F0dHIuZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgPyB0cnVlIDogbnVsbFwiXHJcbiAgICAgICAgICAvPlxyXG4gICAgICAgICAge3sgbGFiZWwgfX1cclxuICAgICAgICA8L2xhYmVsPlxyXG4gICAgICB9XHJcbiAgICA8L2Rpdj5cclxuICBgLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQ2hlY2tib3hGaWVsZENvbXBvbmVudCB7XHJcbiAgQElucHV0KCkgZmllbGQhOiBOZXN0ZWRGaWVsZENvbmZpZztcclxuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xyXG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG59XHJcbiJdfQ==