xt-components 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1053 @@
1
+ import * as i0 from '@angular/core';
2
+ import { computed, signal, InjectionToken, inject, Injectable, input, model, output, viewChild, Component } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { FormControl, FormGroup, ReactiveFormsModule, FormBuilder, FormArray } from '@angular/forms';
5
+ import { NgComponentOutlet, CommonModule } from '@angular/common';
6
+
7
+ class XtBaseContext {
8
+ /**
9
+ *
10
+ * @param displayMode
11
+ * @param readOnly
12
+ * @param parentGroup
13
+ * @param controlName
14
+ */
15
+ constructor(displayMode, subName, parentGroup, parentContext) {
16
+ this.displayMode = 'FULL_VIEW';
17
+ this.displayValue = computed(() => {
18
+ if (this.nonFormValue !== undefined) {
19
+ return this.nonFormValue();
20
+ }
21
+ else {
22
+ throw new Error("Cannot display a value that does not exist. Are you sure you're not using Reactive Form with this context? " + this.toString());
23
+ }
24
+ });
25
+ this.displayMode = displayMode;
26
+ this.parentFormGroup = parentGroup;
27
+ this.parentContext = parentContext;
28
+ this.subName = subName;
29
+ }
30
+ setDisplayValue(newValue, type, updateParent = true) {
31
+ if (newValue !== undefined) {
32
+ const oldValue = this.nonFormValue ? this.nonFormValue() : null;
33
+ if (this.nonFormValue == null) {
34
+ if ((this.childContexts != null) && (this.childContexts.size > 0))
35
+ throw new Error('An XtContext with no values cannot have children ', { cause: this });
36
+ this.nonFormValue = signal(newValue);
37
+ }
38
+ else {
39
+ this.nonFormValue.set(newValue);
40
+ }
41
+ // Change the children values if needed
42
+ if (this.childContexts != null) {
43
+ if (newValue == null) {
44
+ for (const [subName, child] of this.childContexts) {
45
+ child.setDisplayValue(null, undefined, false);
46
+ }
47
+ }
48
+ else if (oldValue != null) {
49
+ for (const [subName, child] of this.childContexts) {
50
+ if (newValue[subName] != oldValue[subName]) {
51
+ // The value has changed, let's update
52
+ child.setDisplayValue(newValue[subName], undefined, false);
53
+ }
54
+ }
55
+ }
56
+ }
57
+ if ((updateParent) && (this.subName != null))
58
+ this.parentContext?.updateSubDisplayValue(this.subName, newValue);
59
+ }
60
+ if (type !== undefined)
61
+ this.valueType = type;
62
+ return this;
63
+ }
64
+ isInForm() {
65
+ return ((this.subName != null) && (this.formGroup() != null));
66
+ }
67
+ formControlNameOrNull() {
68
+ return this.subName ?? null;
69
+ }
70
+ value() {
71
+ if (this.nonFormValue != null)
72
+ return this.nonFormValue() ?? this.formControlValue();
73
+ else
74
+ return this.formControlValue();
75
+ }
76
+ subValue(subsubName) {
77
+ const value = this.nonFormValue ? this.nonFormValue() : this.formControlValue();
78
+ if ((subsubName != null) && (value != null)) {
79
+ return value[subsubName];
80
+ }
81
+ else {
82
+ return value;
83
+ }
84
+ }
85
+ /**
86
+ * Enable child contexts to update its own value in the parent context whenever it's value changes
87
+ */
88
+ updateSubDisplayValue(subName, subValue) {
89
+ if (this.nonFormValue != null) {
90
+ let newValue = this.nonFormValue();
91
+ if (newValue == null) {
92
+ const newValue = {};
93
+ newValue[subName] = subValue;
94
+ this.nonFormValue.set(newValue);
95
+ }
96
+ else {
97
+ newValue[subName] = subValue; // Discretly update the subValue without triggering parent signal
98
+ }
99
+ }
100
+ else {
101
+ throw new Error("No nonFormValue to update subDisplayValue" + this.toString());
102
+ }
103
+ }
104
+ formControlValue() {
105
+ let ret = undefined;
106
+ if (this.isInForm()) {
107
+ if (this.subName != null) {
108
+ //console.debug ("formControlValue parentGroup value is ", this.parentFormGroup?.value);
109
+ ret = this.parentFormGroup?.value[this.subName];
110
+ }
111
+ else {
112
+ ret = this.parentFormGroup?.value;
113
+ }
114
+ }
115
+ else {
116
+ ret = undefined;
117
+ }
118
+ //console.debug("formControlValue of "+this.subName+ " is ",ret);
119
+ return ret;
120
+ }
121
+ /**
122
+ * Returns the context associated with a specific element in a set.
123
+ * Value must be an array.
124
+ * @param elementIndex
125
+ */
126
+ elementSetContext(elementIndex) {
127
+ const value = this.value();
128
+ if (!Array.isArray(this.value())) {
129
+ throw new Error("The value must be an Array / Set to create a subElement context.");
130
+ }
131
+ const ret = new XtBaseContext(this.displayMode, undefined, undefined, this);
132
+ ret.setDisplayValue(value[elementIndex]);
133
+ if (this.valueType != null) {
134
+ // Convert potential array type into single type
135
+ ret.valueType = this.valueType.endsWith('[]') ? this.valueType.substring(0, this.valueType.length - 2) : this.valueType;
136
+ }
137
+ return ret;
138
+ }
139
+ subContext(subName, subType, typeResolver) {
140
+ if ((subName == null) || (subName.length == 0)) {
141
+ return this;
142
+ }
143
+ else if (this.childContexts?.has(subName)) {
144
+ return this.childContexts?.get(subName);
145
+ }
146
+ else {
147
+ let subValue = null;
148
+ let parentGroup = this.formGroup();
149
+ // Recalculate parentGroup and formControlName and value if needed.
150
+ if (parentGroup == null) {
151
+ let curValue = this.nonFormValue;
152
+ if (curValue != null) {
153
+ if (curValue() != null) {
154
+ subValue = signal(curValue()[subName]);
155
+ }
156
+ }
157
+ if (subValue == null) {
158
+ subValue = signal(null);
159
+ }
160
+ }
161
+ const ret = new XtBaseContext(this.displayMode, subName, parentGroup, this);
162
+ if (subValue != null)
163
+ ret.nonFormValue = subValue;
164
+ if (subType != null) {
165
+ ret.valueType = subType;
166
+ }
167
+ else if ((this.valueType != null) && (typeResolver != null)) {
168
+ ret.valueType = typeResolver.findType(this, subName, this.value()) ?? undefined;
169
+ }
170
+ if (this.childContexts == null)
171
+ this.childContexts = new Map();
172
+ this.childContexts.set(subName, ret);
173
+ return ret;
174
+ }
175
+ }
176
+ formGroup() {
177
+ return this.localFormGroup ?? this.parentFormGroup;
178
+ }
179
+ toString() {
180
+ let ret = 'XtContext named ';
181
+ ret += this.subName ?? 'None';
182
+ ret += ' with type ';
183
+ ret += this.valueType ?? 'None';
184
+ ret += ' with value ';
185
+ ret += this.nonFormValue ? this.nonFormValue() : this.formControlValue();
186
+ return ret;
187
+ }
188
+ }
189
+
190
+ class XtResolvedComponent {
191
+ constructor(componantName, componentClass, outputs = false) {
192
+ this.componentName = componantName;
193
+ this.componentClass = componentClass;
194
+ this.outputs = outputs;
195
+ }
196
+ static from(info) {
197
+ const ret = new XtResolvedComponent(info.componentName, info.componentClass);
198
+ if ((info.outputs != null) && (info.outputs.length > 0)) {
199
+ ret.outputs = true;
200
+ }
201
+ return ret;
202
+ }
203
+ }
204
+
205
+ class XtPluginRegistry {
206
+ constructor() {
207
+ this.pluginRegistry = new Map();
208
+ this.componentRegistry = new Map();
209
+ this.componentByTypeCache = new Map();
210
+ this.listComponents = signal(new Array());
211
+ }
212
+ /**
213
+ * The component can manage any standard javascript primitives types. That's usually the default whenever we don't know any particular type
214
+ * string
215
+ * number
216
+ * bigint
217
+ * boolean
218
+ * undefined
219
+ * null
220
+ * symbol is not managed
221
+ * Date, while an object and not a primitive, is managed
222
+ */
223
+ static { this.ANY_PRIMITIVE_TYPE = "ANY_PRIMITIVE_TYPE"; }
224
+ /**
225
+ * The components can manage any composite javascript type. Default when no type has been defined and it's a user defined javascript object (not a data type)
226
+ */
227
+ static { this.ANY_OBJECT_TYPE = "ANY_OBJECT_TYPE"; }
228
+ static { this.ANY_PRIMITIVE_SET = "ANY_PRIMITIVE_SET"; }
229
+ static { this.ANY_OBJECT_SET = "ANY_OBJECT_SET"; }
230
+ registerPlugin(info) {
231
+ this.pluginRegistry.set(info.name, info);
232
+ if (info.components != null) {
233
+ let updated = false;
234
+ for (const comp of info.components) {
235
+ updated = true;
236
+ this.registerComponent(comp);
237
+ }
238
+ if (updated)
239
+ this.componentByTypeCache.clear(); // Force recalculation of type
240
+ }
241
+ }
242
+ registerComponent(info) {
243
+ this.componentRegistry.set(info.componentName, info);
244
+ this.listComponents.update((array) => {
245
+ let found = false;
246
+ for (let i = 0; i < array.length; i++) {
247
+ if (array[i].componentName == info.componentName) {
248
+ found = true;
249
+ array[i] = info;
250
+ }
251
+ }
252
+ if (!found)
253
+ array.push(info);
254
+ return array;
255
+ });
256
+ }
257
+ findComponentsForType(valueType, value) {
258
+ let originalType = valueType;
259
+ //console.debug('Finding type from '+valueType+' with value ',value);
260
+ // We don't know the value type, let's try to guess if it's a primitive or object based on the value
261
+ if (valueType == null) {
262
+ valueType = XtPluginRegistry.ANY_OBJECT_TYPE;
263
+ if ((value == null) || (typeof value != 'object')) {
264
+ valueType = XtPluginRegistry.ANY_PRIMITIVE_TYPE;
265
+ }
266
+ else if (value instanceof Date) {
267
+ valueType = XtPluginRegistry.ANY_PRIMITIVE_TYPE;
268
+ }
269
+ if (Array.isArray(value)) {
270
+ valueType = (valueType === XtPluginRegistry.ANY_PRIMITIVE_TYPE) ? XtPluginRegistry.ANY_PRIMITIVE_SET : XtPluginRegistry.ANY_OBJECT_SET;
271
+ }
272
+ }
273
+ else { // originalType has been defined.
274
+ if (Array.isArray(value)) {
275
+ valueType = valueType.endsWith('[]') ? valueType : valueType + '[]';
276
+ originalType = valueType;
277
+ }
278
+ }
279
+ //console.debug('Type found is '+valueType);
280
+ let ret = this.componentByTypeCache.get(valueType);
281
+ if (ret == null) {
282
+ ret = new Array();
283
+ for (const comp of this.componentRegistry) {
284
+ const info = comp[1];
285
+ if (info.typesHandled.includes(valueType)) {
286
+ ret.push(info);
287
+ }
288
+ }
289
+ if ((ret.length == 0) && (originalType != null)) {
290
+ // Couldn't find a specific component, let's try the generic ones, so we don't pass any type
291
+ ret = this.findComponentsForType(null, value);
292
+ // Cache the component only if we were able to assert its type.
293
+ // If no type has been given and value is null, then we cannot assess the real type
294
+ if (value != null) {
295
+ this.componentByTypeCache.set(originalType, ret);
296
+ }
297
+ }
298
+ else {
299
+ // Cache the component only if we were able to assert its type.
300
+ // If no type has been given and value is null, then we cannot assess the real type
301
+ if ((value != null) || (originalType != null)) {
302
+ this.componentByTypeCache.set(originalType ?? valueType, ret);
303
+ }
304
+ }
305
+ }
306
+ return ret;
307
+ }
308
+ static registry() {
309
+ return XT_REGISTRY;
310
+ }
311
+ findComponentInfo(type) {
312
+ // Search for the component registered with this class
313
+ for (const info of this.componentRegistry.values()) {
314
+ if (info.componentClass == type) {
315
+ return info;
316
+ }
317
+ }
318
+ return null;
319
+ }
320
+ getComponentInfo(type) {
321
+ const ret = this.findComponentInfo(type);
322
+ if (ret == null) {
323
+ throw new Error("No component found with class " + type);
324
+ }
325
+ return ret;
326
+ }
327
+ }
328
+ const XT_REGISTRY = new XtPluginRegistry();
329
+
330
+ const XT_RESOLVER_TOKEN = new InjectionToken('Enable providing a custom component resolver.');
331
+ const XT_TYPE_RESOLVER_TOKEN = new InjectionToken('Enable providing a custom type resolver.');
332
+ const XT_REGISTRY_TOKEN = new InjectionToken("Injects the Plugin Registry right into your angular component", {
333
+ factory: () => {
334
+ return XT_REGISTRY;
335
+ }
336
+ });
337
+
338
+ class XtRegistryResolver {
339
+ constructor(registry, typeResolver) {
340
+ this.registry = registry;
341
+ this.typeResolver = typeResolver;
342
+ }
343
+ resolve(baseContext, subName) {
344
+ const ret = this.registry.findComponentsForType(this.typeResolver.findType(baseContext, subName), baseContext.subValue(subName));
345
+ if (ret != null && ret.length > 0) {
346
+ return XtResolvedComponent.from(ret[0]);
347
+ }
348
+ return null;
349
+ }
350
+ }
351
+
352
+ class XtTypeHierarchyResolver {
353
+ constructor() {
354
+ this.types = new Map();
355
+ }
356
+ addType(typeName, type) {
357
+ this.types.set(typeName, fromDescription(type));
358
+ }
359
+ canUpdate() {
360
+ return true;
361
+ }
362
+ findType(typeInfo, subName, value) {
363
+ if (typeInfo == null)
364
+ return typeInfo;
365
+ if (typeInfo.valueType == null)
366
+ return typeInfo.valueType;
367
+ if (subName == null) {
368
+ return typeInfo.valueType;
369
+ }
370
+ else {
371
+ const selectedType = this.types.get(typeInfo.valueType);
372
+ if ((selectedType != null) && (selectedType.children != null)) {
373
+ const type = selectedType.children[subName].type;
374
+ if (type == null) {
375
+ throw new Error('SubType named ' + subName + ' of ' + typeInfo.valueType + ' doesn\'t have a type name.');
376
+ }
377
+ else {
378
+ return type;
379
+ }
380
+ }
381
+ }
382
+ return undefined;
383
+ }
384
+ listSubNames(context, value) {
385
+ let ret = [];
386
+ if ((context != null) && (context.valueType != null)) {
387
+ const typeInfo = this.types.get(context.valueType);
388
+ if (typeInfo?.children != null) {
389
+ ret = Object.keys(typeInfo.children);
390
+ }
391
+ }
392
+ if (ret.length == 0) {
393
+ // We will use the value to extract properties
394
+ if (value != null) {
395
+ if (Array.isArray(value)) {
396
+ if (value.length > 0) {
397
+ const setOfKeys = new Set();
398
+ for (const element of value) {
399
+ const elementKeys = Object.keys(element);
400
+ for (const key of elementKeys) {
401
+ setOfKeys.add(key);
402
+ }
403
+ }
404
+ ret = Array.from(setOfKeys.values());
405
+ }
406
+ }
407
+ else {
408
+ ret = Object.keys(value);
409
+ }
410
+ }
411
+ }
412
+ return ret;
413
+ }
414
+ }
415
+ class XtBaseTypeHierarchy {
416
+ constructor(type, parent) {
417
+ this.type = type;
418
+ this.parent = parent;
419
+ }
420
+ addChild(key, child) {
421
+ if (this.children == null)
422
+ this.children = {};
423
+ this.children[key] = child;
424
+ }
425
+ }
426
+ function fromDescription(typeHierarchy, name, parent) {
427
+ let ret = null;
428
+ if (typeof typeHierarchy == 'string') {
429
+ ret = new XtBaseTypeHierarchy(typeHierarchy, parent);
430
+ }
431
+ else {
432
+ ret = new XtBaseTypeHierarchy(undefined, parent);
433
+ for (const key of Object.keys(typeHierarchy)) {
434
+ const value = typeHierarchy[key];
435
+ fromDescription(value, key, ret);
436
+ }
437
+ }
438
+ if ((parent != null) && (name != null))
439
+ parent.addChild(name, ret);
440
+ else if ((parent != null) && (name == null)) {
441
+ throw new Error("Cannot add type to parent without a name.");
442
+ }
443
+ return ret;
444
+ }
445
+ function updateFormGroupWithValue(formGroup, value) {
446
+ const toDelete = new Set(Object.keys(formGroup.controls));
447
+ for (const valueKey in value) {
448
+ const primitive = isPrimitive(value[valueKey]);
449
+ if (toDelete.delete(valueKey)) {
450
+ // Already a control
451
+ const oldControl = formGroup.get(valueKey);
452
+ // Is it the right type ?
453
+ if (primitive) {
454
+ // Must be an FormControl2
455
+ if (oldControl.controls === undefined) {
456
+ // It's ok, just set the value
457
+ oldControl.setValue(value[valueKey]);
458
+ }
459
+ else {
460
+ formGroup.setControl(valueKey, new FormControl(value[valueKey]));
461
+ }
462
+ }
463
+ else {
464
+ // Must be a FormGroup
465
+ if (oldControl.controls === undefined) {
466
+ const newFormGroup = new FormGroup({});
467
+ formGroup.setControl(valueKey, newFormGroup);
468
+ updateFormGroupWithValue(newFormGroup, value[valueKey]);
469
+ }
470
+ else {
471
+ // It was already a formgroup, so just update it
472
+ updateFormGroupWithValue(oldControl, value[valueKey]);
473
+ }
474
+ }
475
+ }
476
+ else {
477
+ if (primitive) {
478
+ formGroup.addControl(valueKey, new FormControl(value[valueKey]));
479
+ }
480
+ else {
481
+ const newFormGroup = new FormGroup({});
482
+ formGroup.addControl(valueKey, newFormGroup);
483
+ updateFormGroupWithValue(newFormGroup, value[valueKey]);
484
+ }
485
+ }
486
+ }
487
+ // Delete controls that are no more used
488
+ for (const delName of toDelete) {
489
+ formGroup.removeControl(delName);
490
+ }
491
+ }
492
+ function isPrimitive(valueElement) {
493
+ if (typeof valueElement == 'object') {
494
+ if (valueElement == null)
495
+ return true;
496
+ else {
497
+ return valueElement instanceof Date;
498
+ }
499
+ }
500
+ else
501
+ return true;
502
+ }
503
+
504
+ class XtResolverService {
505
+ constructor() {
506
+ this.pluginRegistry = inject(XT_REGISTRY_TOKEN);
507
+ this.baseResolver = inject(XT_RESOLVER_TOKEN, { optional: true });
508
+ this.baseTypeResolver = inject(XT_TYPE_RESOLVER_TOKEN, { optional: true });
509
+ this.listComponents = computed(() => {
510
+ return this.pluginRegistry.listComponents();
511
+ });
512
+ if (this.baseTypeResolver == null) {
513
+ this.typeResolver = new XtTypeHierarchyResolver();
514
+ }
515
+ else
516
+ this.typeResolver = this.baseTypeResolver;
517
+ if (this.baseResolver == null) {
518
+ this.resolver = new XtRegistryResolver(this.pluginRegistry, this.typeResolver);
519
+ }
520
+ else
521
+ this.resolver = this.baseResolver;
522
+ }
523
+ findBestComponent(baseContext, subName) {
524
+ const ret = this.resolver.resolve(baseContext, subName);
525
+ if (ret != null)
526
+ return ret;
527
+ else
528
+ throw new Error("No components found for this context " + baseContext.toString());
529
+ }
530
+ findTypeOf(baseContext, subName, value) {
531
+ const ret = this.typeResolver.findType(baseContext, subName, value);
532
+ return ret;
533
+ }
534
+ listSubNamesOf(baseContext, value) {
535
+ return this.typeResolver.listSubNames(baseContext, value);
536
+ }
537
+ registerPlugin(info) {
538
+ this.pluginRegistry.registerPlugin(info);
539
+ this.registerTypes(info.types);
540
+ }
541
+ registerTypes(types) {
542
+ if ((types != null) && (this.typeResolver.canUpdate())) {
543
+ for (const newType in types) {
544
+ this.typeResolver.addType(newType, types[newType]);
545
+ }
546
+ }
547
+ }
548
+ getComponentInfo(type) {
549
+ return XtResolvedComponent.from(this.pluginRegistry.getComponentInfo(type));
550
+ }
551
+ findComponentInfo(type) {
552
+ const ret = this.pluginRegistry.findComponentInfo(type);
553
+ if (ret == null)
554
+ return null;
555
+ else
556
+ return XtResolvedComponent.from(ret);
557
+ }
558
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
559
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtResolverService, providedIn: 'root' }); }
560
+ }
561
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtResolverService, decorators: [{
562
+ type: Injectable,
563
+ args: [{
564
+ providedIn: 'root'
565
+ }]
566
+ }], ctorParameters: () => [] });
567
+
568
+ /**
569
+ * Offers a nice and easy to dynamically embed a component.
570
+ * You set the type, the display mode, and either the value or the formgroup & subName to use.
571
+ * XtRender will then instantiate the component, bind it to the value or form, and display it.
572
+ */
573
+ class XtRenderComponent {
574
+ constructor() {
575
+ this.resolverService = inject(XtResolverService);
576
+ this.componentType = input();
577
+ this.displayMode = input.required();
578
+ this.valueType = input();
579
+ // Either we set the value directly
580
+ this.value = model();
581
+ // Or we are inside a Form
582
+ this.formGroup = input();
583
+ this.subName = input();
584
+ this.outputs = output();
585
+ this.hasOutputs = false;
586
+ this.outlet = viewChild.required(NgComponentOutlet);
587
+ this.context = computed(() => {
588
+ let form = this.formGroup();
589
+ const ret = new XtBaseContext(this.displayMode(), this.subName(), form);
590
+ ret.valueType = this.valueType();
591
+ if (!ret.isInForm()) {
592
+ const subName = this.subName();
593
+ const value = this.value();
594
+ if ((subName == null) || (value == null)) {
595
+ ret.setDisplayValue(value);
596
+ }
597
+ else {
598
+ ret.setDisplayValue(value[subName]);
599
+ }
600
+ }
601
+ return ret;
602
+ });
603
+ this.type = computed(() => {
604
+ //console.debug("Calculating type in XtRenderSubComponent");
605
+ let type = this.componentType();
606
+ let compFound = null;
607
+ if (type == null) {
608
+ //console.debug('XtRender, using component set '+ type);
609
+ //compFound = this.resolverService.findComponentInfo (type);
610
+ //} else {
611
+ compFound = this.resolverService.findBestComponent(this.context());
612
+ //console.debug('XtRender, found component ',compFound.componentName);
613
+ type = compFound.componentClass;
614
+ }
615
+ return type ?? null;
616
+ });
617
+ }
618
+ ngAfterViewInit() {
619
+ const instance = this.outlet().componentInstance;
620
+ if ((instance != null) && (instance.hasOutputs) && (instance.outputs != null)) {
621
+ instance.outputs.subscribe((out) => this.outputs.emit(out));
622
+ this.hasOutputs = true;
623
+ }
624
+ }
625
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtRenderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
626
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.4", type: XtRenderComponent, isStandalone: true, selector: "xt-render", inputs: { componentType: { classPropertyName: "componentType", publicName: "componentType", isSignal: true, isRequired: false, transformFunction: null }, displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: true, transformFunction: null }, valueType: { classPropertyName: "valueType", publicName: "valueType", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, subName: { classPropertyName: "subName", publicName: "subName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", outputs: "outputs" }, viewQueries: [{ propertyName: "outlet", first: true, predicate: NgComponentOutlet, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *ngComponentOutlet=\"type(); inputs: {context:context ()}\" />\n", styles: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); }
627
+ }
628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtRenderComponent, decorators: [{
629
+ type: Component,
630
+ args: [{ selector: 'xt-render', standalone: true, imports: [
631
+ NgComponentOutlet,
632
+ ReactiveFormsModule
633
+ ], template: "<ng-container *ngComponentOutlet=\"type(); inputs: {context:context ()}\" />\n" }]
634
+ }], ctorParameters: () => [] });
635
+
636
+ /**
637
+ * Dynamically render a component that will display the given subValue.
638
+ * To be used only inside an XtSimpleComponent or XtCompositeComponent
639
+ */
640
+ class XtRenderSubComponent {
641
+ constructor() {
642
+ this.context = input.required();
643
+ this.componentType = input();
644
+ this.outputs = output();
645
+ this.hasOutputs = false;
646
+ this.outlet = viewChild.required(NgComponentOutlet);
647
+ this.resolverService = inject(XtResolverService);
648
+ this.type = computed(() => {
649
+ //console.debug("Calculating type in XtRenderSubComponent");
650
+ let type = this.componentType();
651
+ let compFound = null;
652
+ if (type == null) {
653
+ //console.debug('XtRender, using component set '+ type);
654
+ //compFound = this.resolverService.findComponentInfo (type);
655
+ //} else {
656
+ compFound = this.resolverService.findBestComponent(this.context());
657
+ //console.debug('XtRender, found component ',compFound.componentName);
658
+ type = compFound.componentClass;
659
+ }
660
+ return type ?? null;
661
+ });
662
+ }
663
+ ngAfterViewInit() {
664
+ const instance = this.outlet().componentInstance;
665
+ if ((instance != null) && (instance.hasOutputs) && (instance.outputs != null)) {
666
+ instance.outputs.subscribe((out) => this.outputs.emit(out));
667
+ this.hasOutputs = true;
668
+ }
669
+ }
670
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtRenderSubComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
671
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.4", type: XtRenderSubComponent, isStandalone: true, selector: "xt-render-sub", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: true, transformFunction: null }, componentType: { classPropertyName: "componentType", publicName: "componentType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { outputs: "outputs" }, viewQueries: [{ propertyName: "outlet", first: true, predicate: NgComponentOutlet, descendants: true, isSignal: true }], ngImport: i0, template: "{{componentType()}}\n<ng-container *ngComponentOutlet=\"type(); inputs: {context:context ()}\" />\n", styles: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); }
672
+ }
673
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtRenderSubComponent, decorators: [{
674
+ type: Component,
675
+ args: [{ selector: 'xt-render-sub', standalone: true, imports: [
676
+ NgComponentOutlet,
677
+ ReactiveFormsModule
678
+ ], template: "{{componentType()}}\n<ng-container *ngComponentOutlet=\"type(); inputs: {context:context ()}\" />\n" }]
679
+ }] });
680
+
681
+ class XtBaseOutput {
682
+ setNewOutput(name, value) {
683
+ let ret = false;
684
+ if (this[name] == null) {
685
+ this[name] = signal(value);
686
+ ret = true;
687
+ }
688
+ else {
689
+ this[name].set(value);
690
+ }
691
+ return ret;
692
+ }
693
+ }
694
+
695
+ /**
696
+ * An XtSimpleComponent just displays the given value or element in a form.
697
+ * If you need to dynamically embed other XtComponents to display sub elements, then please use the XtCompositeComponent
698
+ */
699
+ class XtSimpleComponent {
700
+ constructor() {
701
+ this.context = input.required();
702
+ this.outputs = output();
703
+ /**
704
+ * Does the component provides Output or not ?
705
+ * @protected
706
+ */
707
+ this.hasOutputs = false;
708
+ this.isInForm = computed(() => {
709
+ return this.context()?.isInForm() ?? false;
710
+ });
711
+ this.formControlNameIfAny = computed(() => {
712
+ return this.context()?.subName;
713
+ });
714
+ this.formGroupIfAny = computed(() => {
715
+ return this.context()?.formGroup();
716
+ });
717
+ this.formGroup = computed(() => {
718
+ const ret = this.context()?.formGroup();
719
+ if (ret == null)
720
+ throw new Error('No form groups in this component of type ' + this.componentDescriptor());
721
+ return ret;
722
+ });
723
+ /**
724
+ * Returns the component form name, which is for now the subName
725
+ */
726
+ this.componentNameInForm = computed(() => {
727
+ return this.safelyGetSubName();
728
+ });
729
+ this.safelyGetSubName = computed(() => {
730
+ const ret = this.context()?.subName;
731
+ if (ret == null)
732
+ throw new Error('This component has no name in the form ' + this.componentDescriptor());
733
+ return ret;
734
+ });
735
+ /**
736
+ * Returns the form control name and create a form control behind the scene
737
+ */
738
+ this.formControlName = computed(() => {
739
+ const ret = this.safelyGetSubName();
740
+ this.manageFormControl(ret); // Creates the form control
741
+ return ret;
742
+ });
743
+ this.formControl = computed(() => {
744
+ const subName = this.safelyGetSubName();
745
+ const formControl = this.manageFormControl(subName);
746
+ if (formControl == null)
747
+ throw new Error("Calling formControl for subName " + subName + " when none exist.");
748
+ return formControl;
749
+ });
750
+ this.getValue = computed(() => {
751
+ return this.context().value();
752
+ });
753
+ this.displayValue = computed(() => {
754
+ return this.context().displayValue();
755
+ });
756
+ if (this.hasOutputs) {
757
+ if (this.outputElement == null) {
758
+ this.outputElement = new XtBaseOutput();
759
+ }
760
+ }
761
+ }
762
+ manageFormControl(ctrlName) {
763
+ const formGroup = this.formGroupIfAny();
764
+ if (formGroup == null) {
765
+ // You can call manageFormControl even in not a form, it just get ignored
766
+ //console.debug('FormGroup is undefined when declaring managedcontrol '+ctrlName);
767
+ return undefined;
768
+ }
769
+ else {
770
+ let ctrl = formGroup.get(ctrlName);
771
+ if (ctrl == null) {
772
+ ctrl = new FormControl(undefined);
773
+ formGroup.setControl(ctrlName, ctrl);
774
+ }
775
+ return ctrl;
776
+ }
777
+ }
778
+ componentDescriptor() {
779
+ return "Component with type " + this.constructor.name + " with context " + this.context().toString();
780
+ }
781
+ emitOutput(outputName, newValue) {
782
+ if (!this.hasOutputs) {
783
+ throw new Error("Component without outputs cannot emit output");
784
+ }
785
+ let newOutput = false;
786
+ if (this.outputElement == null) {
787
+ this.outputElement = new XtBaseOutput();
788
+ newOutput = true;
789
+ }
790
+ newOutput = this.outputElement.setNewOutput(outputName, newValue) || newOutput;
791
+ if (newOutput) {
792
+ this.outputs?.emit(this.outputElement);
793
+ }
794
+ }
795
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtSimpleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
796
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.4", type: XtSimpleComponent, isStandalone: true, selector: "ng-component", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { outputs: "outputs" }, ngImport: i0, template: '', isInline: true }); }
797
+ }
798
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtSimpleComponent, decorators: [{
799
+ type: Component,
800
+ args: [{
801
+ standalone: true,
802
+ imports: [],
803
+ template: ''
804
+ }]
805
+ }], ctorParameters: () => [] });
806
+
807
+ class XtCompositeComponent extends XtSimpleComponent {
808
+ constructor() {
809
+ super(...arguments);
810
+ this.resolverService = inject(XtResolverService);
811
+ this.formGroupIfAny = computed(() => {
812
+ const context = this.context();
813
+ if (context == null)
814
+ return undefined;
815
+ let ret = context.localFormGroup;
816
+ if ((ret == null) && (context.parentFormGroup != null) && (context.subName != null)) {
817
+ if (context.parentFormGroup.contains(context.subName)) {
818
+ context.localFormGroup = context.parentFormGroup.get(context.subName);
819
+ }
820
+ else {
821
+ context.localFormGroup = new FormGroup({});
822
+ context.parentFormGroup.addControl(context.subName, context.localFormGroup);
823
+ }
824
+ ret = context.localFormGroup;
825
+ }
826
+ return ret;
827
+ });
828
+ /**
829
+ * We need to create a new form group to manage the sub elements.
830
+ */
831
+ this.formGroup = computed(() => {
832
+ const ret = this.formGroupIfAny();
833
+ if (ret == null)
834
+ throw new Error('No form groups in this component of type ' + this.componentDescriptor());
835
+ return ret;
836
+ });
837
+ }
838
+ /**
839
+ * Helper function to calculate the sub context
840
+ * @param subName
841
+ * @param subType
842
+ */
843
+ subContext(subName, subType) {
844
+ this.formGroupIfAny(); // Ensure the context is properly initialized
845
+ return this.context().subContext(subName, subType, this.resolverService.typeResolver);
846
+ }
847
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtCompositeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
848
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: XtCompositeComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: '', isInline: true, styles: [""] }); }
849
+ }
850
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: XtCompositeComponent, decorators: [{
851
+ type: Component,
852
+ args: [{ standalone: true, imports: [], template: '' }]
853
+ }] });
854
+
855
+ class XtUnitTestHelper {
856
+ }
857
+
858
+ /**
859
+ * Component that can be used to bootstrap tests.
860
+ * Just set the value and component type, and it will be injected in your test.
861
+ */
862
+ class HostTestSimpleComponent {
863
+ constructor() {
864
+ this.type = input.required();
865
+ this.displayMode = input('FULL_VIEW');
866
+ this.value = input(undefined);
867
+ }
868
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestSimpleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
869
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.4", type: HostTestSimpleComponent, isStandalone: true, selector: "test-host", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<h1>Test Simple Component</h1> <xt-render [componentType]="type()" [displayMode]="displayMode()" [value]="value()" ></xt-render> ', isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: XtRenderComponent, selector: "xt-render", inputs: ["componentType", "displayMode", "valueType", "value", "formGroup", "subName"], outputs: ["valueChange", "outputs"] }] }); }
870
+ }
871
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestSimpleComponent, decorators: [{
872
+ type: Component,
873
+ args: [{
874
+ selector: 'test-host',
875
+ standalone: true,
876
+ imports: [CommonModule, XtRenderComponent],
877
+ template: '<h1>Test Simple Component</h1> <xt-render [componentType]="type()" [displayMode]="displayMode()" [value]="value()" ></xt-render> '
878
+ }]
879
+ }] });
880
+ /**
881
+ * Same as HostTestSimpleComponent but it includes everything in a form.
882
+ * Just set the component type, the formGroup and the component name, and your component will be run.
883
+ * You can as well easily read and set the value.
884
+ */
885
+ class HostTestFormComponent {
886
+ constructor() {
887
+ this.builder = inject(FormBuilder);
888
+ this.type = input.required();
889
+ this.controlName = input.required();
890
+ // You can send the description to be used in a FormBuilder to create the formgroup;
891
+ this.formDescription = input({});
892
+ // Or set the FormGroup directly
893
+ this.formGroup = input();
894
+ this.createdFormGroup = null;
895
+ }
896
+ computedFormGroup() {
897
+ if (this.createdFormGroup == null) {
898
+ const formGroup = this.formGroup();
899
+ this.createdFormGroup = formGroup ?? generateFormGroup(this.formDescription());
900
+ }
901
+ return this.createdFormGroup;
902
+ }
903
+ patchValue(newVal) {
904
+ const patch = {};
905
+ patch[this.controlName()] = newVal;
906
+ if (this.createdFormGroup != null)
907
+ this.createdFormGroup.patchValue(patch);
908
+ else
909
+ throw new Error("FormGroup not yet created. Did you set formGroup or formDescription property ?");
910
+ }
911
+ retrieveValue() {
912
+ if (this.createdFormGroup != null)
913
+ return this.createdFormGroup.value[this.controlName()];
914
+ else
915
+ throw new Error("FormGroup not yet created. Did you set formGroup or formDescription property ?");
916
+ }
917
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
918
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.4", type: HostTestFormComponent, isStandalone: true, selector: "test-form-host", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: true, transformFunction: null }, formDescription: { classPropertyName: "formDescription", publicName: "formDescription", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<h1>Test Form Component</h1> <form [formGroup]="computedFormGroup()"> <xt-render [componentType]="type()" displayMode="FULL_EDITABLE" [subName]="controlName()" [formGroup]="computedFormGroup()"></xt-render></form>', isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: XtRenderComponent, selector: "xt-render", inputs: ["componentType", "displayMode", "valueType", "value", "formGroup", "subName"], outputs: ["valueChange", "outputs"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] }); }
919
+ }
920
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestFormComponent, decorators: [{
921
+ type: Component,
922
+ args: [{
923
+ selector: 'test-form-host',
924
+ standalone: true,
925
+ imports: [CommonModule, XtRenderComponent, ReactiveFormsModule],
926
+ template: '<h1>Test Form Component</h1> <form [formGroup]="computedFormGroup()"> <xt-render [componentType]="type()" displayMode="FULL_EDITABLE" [subName]="controlName()" [formGroup]="computedFormGroup()"></xt-render></form>'
927
+ }]
928
+ }] });
929
+ /**
930
+ * Component that can be used to test your component based on the type it handles
931
+ * Just set the type hierarchy to register, the value, and it will instantiate the right component in your plugin
932
+ */
933
+ class HostTestTypedComponent {
934
+ constructor() {
935
+ this.displayMode = input('FULL_VIEW');
936
+ this.value = input();
937
+ this.valueType = input();
938
+ this.context = computed(() => {
939
+ const ret = new XtBaseContext(this.displayMode());
940
+ ret.valueType = this.valueType();
941
+ ret.setDisplayValue(this.value());
942
+ return ret;
943
+ });
944
+ }
945
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestTypedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
946
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.4", type: HostTestTypedComponent, isStandalone: true, selector: "test-typed-host", inputs: { displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, valueType: { classPropertyName: "valueType", publicName: "valueType", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<h1>Test Typed Component</h1> <xt-render-sub [context]="context()" ></xt-render-sub> ', isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: XtRenderSubComponent, selector: "xt-render-sub", inputs: ["context", "componentType"], outputs: ["outputs"] }] }); }
947
+ }
948
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestTypedComponent, decorators: [{
949
+ type: Component,
950
+ args: [{
951
+ selector: 'test-typed-host',
952
+ standalone: true,
953
+ imports: [CommonModule, XtRenderSubComponent],
954
+ template: '<h1>Test Typed Component</h1> <xt-render-sub [context]="context()" ></xt-render-sub> '
955
+ }]
956
+ }] });
957
+ /**
958
+ * Same as HostTestSimpleComponent but it includes everything in a form.
959
+ * Just set the component type, the formGroup and the component name, and your component will be run.
960
+ * You can as well easily read and set the value.
961
+ */
962
+ class HostTestTypedFormComponent {
963
+ constructor() {
964
+ this.builder = inject(FormBuilder);
965
+ this.resolver = inject(XtResolverService);
966
+ this.valueType = input();
967
+ this.controlName = input();
968
+ // You can send the description to be used in a FormBuilder to create the formgroup;
969
+ this.formDescription = input({});
970
+ // Or set the FormGroup directly
971
+ this.formGroup = input();
972
+ this.parentFormGroup = this.builder.group({});
973
+ this.createdFormGroup = null;
974
+ this.computedFormGroup = computed(() => {
975
+ if (this.createdFormGroup == null) {
976
+ const formGroup = this.formGroup();
977
+ this.createdFormGroup = formGroup ?? generateFormGroup(this.formDescription());
978
+ this.parentFormGroup.addControl(this.controlName() ?? HostTestTypedFormComponent.CONTROL_NAME, this.createdFormGroup);
979
+ }
980
+ return this.createdFormGroup;
981
+ });
982
+ this.subContext = computed(() => {
983
+ this.computedFormGroup(); // Make sure the subformgroups are created
984
+ const ctrlName = this.controlName();
985
+ let ret = null;
986
+ if (ctrlName == null) {
987
+ ret = new XtBaseContext('FULL_EDITABLE', HostTestTypedFormComponent.CONTROL_NAME, this.parentFormGroup);
988
+ }
989
+ else {
990
+ ret = new XtBaseContext('FULL_EDITABLE', ctrlName, this.createdFormGroup);
991
+ }
992
+ ret.valueType = this.valueType();
993
+ return ret;
994
+ });
995
+ }
996
+ static { this.CONTROL_NAME = 'ForTest'; }
997
+ patchValue(controlName, newVal) {
998
+ const patch = {};
999
+ patch[controlName] = newVal;
1000
+ this.computedFormGroup().patchValue(patch);
1001
+ }
1002
+ retrieveValue(controlName) {
1003
+ return this.computedFormGroup().value[controlName];
1004
+ }
1005
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestTypedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1006
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.4", type: HostTestTypedFormComponent, isStandalone: true, selector: "test-typed-form-host", inputs: { valueType: { classPropertyName: "valueType", publicName: "valueType", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, formDescription: { classPropertyName: "formDescription", publicName: "formDescription", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '<h1>Test Typed Form Component</h1> <form [formGroup]="parentFormGroup"> <xt-render-sub [context]="subContext()"></xt-render-sub></form>', isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: XtRenderSubComponent, selector: "xt-render-sub", inputs: ["context", "componentType"], outputs: ["outputs"] }] }); }
1007
+ }
1008
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HostTestTypedFormComponent, decorators: [{
1009
+ type: Component,
1010
+ args: [{
1011
+ selector: 'test-typed-form-host',
1012
+ standalone: true,
1013
+ imports: [CommonModule, ReactiveFormsModule, XtRenderSubComponent],
1014
+ template: '<h1>Test Typed Form Component</h1> <form [formGroup]="parentFormGroup"> <xt-render-sub [context]="subContext()"></xt-render-sub></form>'
1015
+ }]
1016
+ }] });
1017
+ function generateFormGroup(formDescription) {
1018
+ if (typeof formDescription != 'object') {
1019
+ throw new Error('Form Description should be an object of values');
1020
+ }
1021
+ return generateFormControl(formDescription);
1022
+ }
1023
+ function generateFormControl(formDescription) {
1024
+ if (formDescription == null) {
1025
+ return new FormControl(formDescription);
1026
+ }
1027
+ if (Array.isArray(formDescription)) {
1028
+ const retArray = new FormArray([]);
1029
+ for (const val of formDescription) {
1030
+ retArray.push(generateFormControl(val), { emitEvent: false });
1031
+ }
1032
+ return retArray;
1033
+ }
1034
+ if ((typeof formDescription == 'object') && (!(formDescription instanceof Date))) {
1035
+ const retObject = new FormGroup({});
1036
+ for (const key of Object.keys(formDescription)) {
1037
+ retObject.addControl(key, generateFormControl(formDescription[key]));
1038
+ }
1039
+ return retObject;
1040
+ }
1041
+ return new FormControl(formDescription);
1042
+ }
1043
+
1044
+ /*
1045
+ * Public API Surface of xt-components
1046
+ */
1047
+
1048
+ /**
1049
+ * Generated bundle index. Do not edit.
1050
+ */
1051
+
1052
+ export { HostTestFormComponent, HostTestSimpleComponent, HostTestTypedComponent, HostTestTypedFormComponent, XT_REGISTRY, XT_REGISTRY_TOKEN, XT_RESOLVER_TOKEN, XT_TYPE_RESOLVER_TOKEN, XtBaseContext, XtBaseTypeHierarchy, XtCompositeComponent, XtPluginRegistry, XtRenderComponent, XtRenderSubComponent, XtResolvedComponent, XtResolverService, XtSimpleComponent, XtTypeHierarchyResolver, XtUnitTestHelper, fromDescription, updateFormGroupWithValue };
1053
+ //# sourceMappingURL=xt-components.mjs.map