@acorex/platform 21.0.0-next.2 → 21.0.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/auth/index.d.ts +97 -238
  2. package/common/index.d.ts +778 -213
  3. package/core/index.d.ts +562 -433
  4. package/fesm2022/acorex-platform-auth.mjs +160 -200
  5. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  6. package/fesm2022/acorex-platform-common.mjs +1012 -125
  7. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  8. package/fesm2022/acorex-platform-core.mjs +685 -400
  9. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  10. package/fesm2022/acorex-platform-domain.mjs +54 -11
  11. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  12. package/fesm2022/acorex-platform-layout-builder.mjs +412 -270
  13. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  14. package/fesm2022/acorex-platform-layout-components.mjs +2112 -3153
  15. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  16. package/fesm2022/acorex-platform-layout-designer.mjs +7 -7
  17. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  18. package/fesm2022/acorex-platform-layout-entity.mjs +756 -648
  19. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  20. package/fesm2022/acorex-platform-layout-views.mjs +4 -4
  21. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  22. package/fesm2022/acorex-platform-layout-widget-core.mjs +248 -174
  23. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  24. package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-D0y-9nE5.mjs → acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs} +2 -2
  25. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +1 -0
  26. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-m8rHZP8L.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs} +2 -2
  27. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +1 -0
  28. package/fesm2022/acorex-platform-layout-widgets.mjs +3058 -1038
  29. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  30. package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-mARj77Mr.mjs → acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs} +26 -5
  31. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +1 -0
  32. package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-Cym8pq0v.mjs → acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs} +4 -5
  33. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs.map +1 -0
  34. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +101 -0
  35. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +1 -0
  36. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-B_P0a5KW.mjs → acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs} +3 -3
  37. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +1 -0
  38. package/fesm2022/acorex-platform-themes-default.mjs +166 -30
  39. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  40. package/fesm2022/acorex-platform-themes-shared.mjs +27 -27
  41. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  42. package/layout/builder/index.d.ts +4 -1
  43. package/layout/components/index.d.ts +405 -327
  44. package/layout/designer/index.d.ts +3 -3
  45. package/layout/entity/index.d.ts +163 -108
  46. package/layout/widget-core/index.d.ts +39 -49
  47. package/layout/widgets/index.d.ts +368 -54
  48. package/package.json +5 -5
  49. package/themes/default/index.d.ts +15 -2
  50. package/themes/shared/index.d.ts +10 -10
  51. package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-fhhZOWul.mjs +0 -50
  52. package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-fhhZOWul.mjs.map +0 -1
  53. package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-C3Qbs0fz.mjs +0 -42
  54. package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-C3Qbs0fz.mjs.map +0 -1
  55. package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-CngQBUlN.mjs +0 -55
  56. package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-CngQBUlN.mjs.map +0 -1
  57. package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-DSNo9e4W.mjs +0 -50
  58. package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-DSNo9e4W.mjs.map +0 -1
  59. package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-CL0CwEHX.mjs +0 -48
  60. package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-CL0CwEHX.mjs.map +0 -1
  61. package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-B6Fi0xTw.mjs +0 -42
  62. package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-B6Fi0xTw.mjs.map +0 -1
  63. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-D0y-9nE5.mjs.map +0 -1
  64. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-m8rHZP8L.mjs.map +0 -1
  65. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-mARj77Mr.mjs.map +0 -1
  66. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-Cym8pq0v.mjs.map +0 -1
  67. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BTA6h7Xd.mjs +0 -101
  68. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BTA6h7Xd.mjs.map +0 -1
  69. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-B_P0a5KW.mjs.map +0 -1
@@ -1,13 +1,13 @@
1
1
  import * as i4 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, Injectable, input, model, signal, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output, Input } from '@angular/core';
4
+ import { Injectable, inject, input, model, signal, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output, Input } from '@angular/core';
5
5
  import { AXPopupService } from '@acorex/components/popup';
6
+ import { cloneDeep, isNil, set, isEqual } from 'lodash-es';
6
7
  import * as i2 from '@acorex/components/form';
7
8
  import { AXFormComponent, AXFormModule } from '@acorex/components/form';
8
9
  import * as i1 from '@acorex/platform/layout/widget-core';
9
10
  import { AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
10
- import { isEqual, cloneDeep } from 'lodash-es';
11
11
  import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
12
12
  import * as i1$1 from '@acorex/components/button';
13
13
  import { AXButtonModule } from '@acorex/components/button';
@@ -20,6 +20,281 @@ import * as i5 from '@acorex/core/translation';
20
20
  import { AXTranslationModule } from '@acorex/core/translation';
21
21
  import { AXPExpressionEvaluatorService } from '@acorex/platform/core';
22
22
 
23
+ class AXPLayoutConversionService {
24
+ constructor() {
25
+ //#region ---- Caching ----
26
+ this.widgetTreeCache = new Map();
27
+ this.formDefinitionCache = new Map();
28
+ }
29
+ //#endregion
30
+ //#region ---- Public Methods ----
31
+ /**
32
+ * Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
33
+ * Groups become Fieldset Layouts with Form Field widgets as children
34
+ * Fields become Form Field widgets with Editor widgets as children
35
+ */
36
+ convertFormDefinition(formDefinition) {
37
+ // Create cache key based on form definition content
38
+ const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
39
+ // Check cache first
40
+ if (this.widgetTreeCache.has(cacheKey)) {
41
+ return this.widgetTreeCache.get(cacheKey);
42
+ }
43
+ // Generate widget tree
44
+ const widgetTree = {
45
+ type: 'grid-layout',
46
+ name: 'dynamic-form-container',
47
+ mode: formDefinition.mode, // Preserve form-level mode
48
+ options: {
49
+ title: 'Dynamic Form',
50
+ grid: {
51
+ default: {
52
+ columns: 1,
53
+ gap: '1rem',
54
+ },
55
+ },
56
+ },
57
+ children: formDefinition.groups.map((group) => this.createGroupAsFieldsetWidget(group, formDefinition.mode)),
58
+ };
59
+ // Cache the result
60
+ this.widgetTreeCache.set(cacheKey, widgetTree);
61
+ return widgetTree;
62
+ }
63
+ /**
64
+ * Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
65
+ * Parses Fieldset Layouts back to Groups
66
+ * Parses Form Field widgets back to Fields
67
+ */
68
+ convertWidgetTreeToFormDefinition(widgetTree) {
69
+ // Create cache key based on widget tree content
70
+ const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
71
+ // Check cache first
72
+ if (this.formDefinitionCache.has(cacheKey)) {
73
+ return this.formDefinitionCache.get(cacheKey);
74
+ }
75
+ // Parse widget tree
76
+ const groups = [];
77
+ if (widgetTree.children) {
78
+ widgetTree.children.forEach((child) => {
79
+ if (child.type === 'fieldset-layout') {
80
+ const group = this.extractGroupFromFieldset(child);
81
+ groups.push(group);
82
+ }
83
+ });
84
+ }
85
+ const formDefinition = { groups };
86
+ // Cache the result
87
+ this.formDefinitionCache.set(cacheKey, formDefinition);
88
+ return formDefinition;
89
+ }
90
+ /**
91
+ * Validate that a widget tree represents a valid dynamic form structure
92
+ */
93
+ validateFormWidgetTree(widgetTree) {
94
+ if (!widgetTree || widgetTree.type !== 'grid-layout') {
95
+ return false;
96
+ }
97
+ if (!widgetTree.children || widgetTree.children.length === 0) {
98
+ return true; // Empty form is valid
99
+ }
100
+ // Check that all children are fieldset-layout widgets
101
+ return widgetTree.children.every((child) => child.type === 'fieldset-layout' &&
102
+ child.children &&
103
+ child.children.every((formField) => formField.type === 'form-field' && formField.children && formField.children.length > 0));
104
+ }
105
+ /**
106
+ * Clear all caches
107
+ */
108
+ clearCaches() {
109
+ this.widgetTreeCache.clear();
110
+ this.formDefinitionCache.clear();
111
+ }
112
+ /**
113
+ * Get cache statistics
114
+ */
115
+ getCacheStats() {
116
+ return {
117
+ widgetTreeCacheSize: this.widgetTreeCache.size,
118
+ formDefinitionCacheSize: this.formDefinitionCache.size,
119
+ };
120
+ }
121
+ //#endregion
122
+ //#region ---- Private Methods ----
123
+ /**
124
+ * Convert a single group to Fieldset widget structure
125
+ */
126
+ createGroupAsFieldsetWidget(group, formMode) {
127
+ // Determine columns count from layout or default to 1
128
+ const columnsCount = 1;
129
+ // Use group mode if set, otherwise inherit from form mode
130
+ const groupMode = group.mode || formMode;
131
+ return {
132
+ type: 'fieldset-layout',
133
+ name: group.name,
134
+ mode: groupMode,
135
+ options: {
136
+ title: group.title,
137
+ description: group.description,
138
+ cols: columnsCount,
139
+ look: group.look || 'container', // Default to 'container' if not specified
140
+ },
141
+ children: this.createFieldWidgets(group.parameters, columnsCount, groupMode),
142
+ };
143
+ }
144
+ /**
145
+ * Convert fields to Form Field widgets
146
+ */
147
+ createFieldWidgets(fields, columnsCount, groupMode) {
148
+ return fields.map((field) => this.createFormFieldWidget(field, groupMode));
149
+ }
150
+ /**
151
+ * Convert a single field to Form Field widget with editor as child
152
+ */
153
+ createFormFieldWidget(field, groupMode) {
154
+ // Use field mode if set, otherwise inherit from group mode
155
+ const fieldMode = field.mode || groupMode;
156
+ // Ensure the editor widget also has the mode set
157
+ const editorWidget = { ...field.widget };
158
+ if (!editorWidget.mode) {
159
+ editorWidget.mode = fieldMode;
160
+ }
161
+ return {
162
+ type: 'form-field',
163
+ name: field.path,
164
+ mode: fieldMode,
165
+ options: {
166
+ label: field.title,
167
+ badge: field.badge,
168
+ description: field.description,
169
+ showLabel: true,
170
+ },
171
+ children: [editorWidget], // The editor widget becomes a child of form-field
172
+ };
173
+ }
174
+ /**
175
+ * Extract group information from Fieldset Layout widget
176
+ */
177
+ extractGroupFromFieldset(fieldsetNode) {
178
+ const columnsCount = fieldsetNode.options?.['cols'] || 1;
179
+ // Extract fields directly from fieldset children
180
+ const fields = [];
181
+ if (fieldsetNode.children) {
182
+ fieldsetNode.children.forEach((formField) => {
183
+ if (formField.type === 'form-field' && formField.children && formField.children.length > 0) {
184
+ const field = this.extractFieldFromFormWidget(formField);
185
+ if (field) {
186
+ fields.push(field);
187
+ }
188
+ }
189
+ });
190
+ }
191
+ return {
192
+ name: fieldsetNode.name || `group-${Date.now()}`,
193
+ title: fieldsetNode.options?.['title'],
194
+ description: fieldsetNode.options?.['description'],
195
+ parameters: fields,
196
+ mode: fieldsetNode.mode,
197
+ look: fieldsetNode.options?.['look'],
198
+ };
199
+ }
200
+ /**
201
+ * Extract field information from Form Field widget
202
+ */
203
+ extractFieldFromFormWidget(formFieldNode) {
204
+ if (!formFieldNode.children || formFieldNode.children.length === 0) {
205
+ return null;
206
+ }
207
+ const editorWidget = formFieldNode.children[0];
208
+ return {
209
+ path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
210
+ title: formFieldNode.options?.['label'],
211
+ badge: formFieldNode.options?.['badge'],
212
+ description: formFieldNode.options?.['description'],
213
+ widget: editorWidget,
214
+ mode: formFieldNode.mode,
215
+ };
216
+ }
217
+ /**
218
+ * Create cache key for form definition
219
+ */
220
+ createFormDefinitionCacheKey(formDefinition) {
221
+ // Create a hash-like key instead of full JSON string
222
+ const keyParts = [];
223
+ keyParts.push(`groups:${formDefinition.groups.length}`);
224
+ formDefinition.groups.forEach((group, groupIndex) => {
225
+ keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
226
+ group.parameters.forEach((param, paramIndex) => {
227
+ keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
228
+ });
229
+ });
230
+ if (formDefinition.mode) {
231
+ keyParts.push(`mode:${formDefinition.mode}`);
232
+ }
233
+ // Join with delimiter and create a shorter hash
234
+ const keyString = keyParts.join('|');
235
+ // If still too long, create a simple hash
236
+ if (keyString.length > 100) {
237
+ return this.createSimpleHash(keyString);
238
+ }
239
+ return keyString;
240
+ }
241
+ /**
242
+ * Create cache key for widget tree
243
+ */
244
+ createWidgetTreeCacheKey(widgetTree) {
245
+ // Create a hash-like key instead of full JSON string
246
+ const keyParts = [];
247
+ keyParts.push(`type:${widgetTree.type}`);
248
+ if (widgetTree.name) {
249
+ keyParts.push(`name:${widgetTree.name}`);
250
+ }
251
+ if (widgetTree.children) {
252
+ keyParts.push(`children:${widgetTree.children.length}`);
253
+ widgetTree.children.forEach((child, index) => {
254
+ keyParts.push(`c${index}:${child.type}`);
255
+ if (child.children) {
256
+ keyParts.push(`cc${index}:${child.children.length}`);
257
+ child.children.forEach((grandChild, gIndex) => {
258
+ keyParts.push(`gc${index}.${gIndex}:${grandChild.type}`);
259
+ if (grandChild.children) {
260
+ keyParts.push(`gcc${index}.${gIndex}:${grandChild.children.length}`);
261
+ }
262
+ });
263
+ }
264
+ });
265
+ }
266
+ // Join with delimiter and create a shorter hash
267
+ const keyString = keyParts.join('|');
268
+ // If still too long, create a simple hash
269
+ if (keyString.length > 100) {
270
+ return this.createSimpleHash(keyString);
271
+ }
272
+ return keyString;
273
+ }
274
+ /**
275
+ * Create a simple hash from a string
276
+ */
277
+ createSimpleHash(str) {
278
+ let hash = 0;
279
+ if (str.length === 0)
280
+ return hash.toString();
281
+ for (let i = 0; i < str.length; i++) {
282
+ const char = str.charCodeAt(i);
283
+ hash = (hash << 5) - hash + char;
284
+ hash = hash & hash; // Convert to 32-bit integer
285
+ }
286
+ return Math.abs(hash).toString(36); // Convert to base36 for shorter string
287
+ }
288
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
289
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
290
+ }
291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
292
+ type: Injectable,
293
+ args: [{
294
+ providedIn: 'root',
295
+ }]
296
+ }] });
297
+
23
298
  //#region ---- Inheritance Utilities ----
24
299
  /**
25
300
  * Resolves inherited properties from context and local values
@@ -74,6 +349,54 @@ function generateValueWidgetPath(widgetName, formFieldName, formFieldLabel) {
74
349
  }
75
350
  return generateRandomId();
76
351
  }
352
+ /**
353
+ * Collects default values from widget node tree and merges them into context
354
+ * Only sets values for paths that don't already exist in the context
355
+ * @param node - The widget node to process
356
+ * @param context - The context object to modify in place (cloned at top level only)
357
+ * @param isTopLevel - Internal flag to track if this is the top-level call
358
+ */
359
+ function collectDefaultValues(node, context = {}, isTopLevel = true) {
360
+ // Clone context only at the top level, then modify in place for recursive calls
361
+ const result = isTopLevel ? cloneDeep(context) : context;
362
+ // Check if this node has a defaultValue and a path
363
+ // Note: We check for both node.defaultValue and also look in node.options.defaultValue as fallback
364
+ const defaultValue = node.defaultValue !== undefined
365
+ ? node.defaultValue
366
+ : node.options?.defaultValue;
367
+ if (defaultValue !== undefined && !isNil(defaultValue) && node.path) {
368
+ // Check if path exists in context using lodash get equivalent check
369
+ const currentValue = getNestedValue(result, node.path);
370
+ if (currentValue === undefined) {
371
+ // Clone the defaultValue to avoid reference issues (especially for Date objects)
372
+ const clonedValue = defaultValue instanceof Date
373
+ ? new Date(defaultValue.getTime())
374
+ : cloneDeep(defaultValue);
375
+ set(result, node.path, clonedValue);
376
+ }
377
+ }
378
+ // Recursively process children - pass result object to accumulate values in place
379
+ if (node.children && Array.isArray(node.children)) {
380
+ for (const child of node.children) {
381
+ collectDefaultValues(child, result, false);
382
+ }
383
+ }
384
+ return result;
385
+ }
386
+ /**
387
+ * Gets a nested value from an object using dot notation path
388
+ */
389
+ function getNestedValue(obj, path) {
390
+ const keys = path.split('.');
391
+ let current = obj;
392
+ for (const key of keys) {
393
+ if (current === undefined || current === null || typeof current !== 'object') {
394
+ return undefined;
395
+ }
396
+ current = current[key];
397
+ }
398
+ return current;
399
+ }
77
400
  //#endregion
78
401
  //#region ---- Service Implementation ----
79
402
  class AXPLayoutBuilderService {
@@ -480,6 +803,26 @@ class ChildContainerMixin extends LayoutContainerMixin {
480
803
  this.containerState.children.push(field.build());
481
804
  return this;
482
805
  }
806
+ dynamicForm(definition) {
807
+ // Get conversion service using inject() - works in any context in Angular 14+
808
+ let conversionService;
809
+ try {
810
+ conversionService = inject(AXPLayoutConversionService);
811
+ }
812
+ catch {
813
+ // Fallback: create service instance if inject() fails (shouldn't happen in normal usage)
814
+ conversionService = new AXPLayoutConversionService();
815
+ }
816
+ // Convert form definition to widget node
817
+ const widgetNode = conversionService.convertFormDefinition(definition);
818
+ // Add the widget node's children to this container
819
+ // The converted widget node has a root grid-layout, we want its children (fieldsets)
820
+ if (widgetNode.children && widgetNode.children.length > 0) {
821
+ this.ensureChildren();
822
+ this.containerState.children.push(...widgetNode.children);
823
+ }
824
+ return this;
825
+ }
483
826
  }
484
827
  /**
485
828
  * Widget container mixin - Interface Segregation Principle
@@ -540,8 +883,56 @@ class WidgetContainerMixin extends ChildContainerMixin {
540
883
  this.containerState.children.push(container.build());
541
884
  return this;
542
885
  }
543
- customWidget(type, options) {
544
- this.addWidget(type, options);
886
+ customWidget(type, optionsOrDelegate, delegate) {
887
+ const child = new WidgetBuilder();
888
+ child.type(type);
889
+ // Determine if second parameter is delegate or options
890
+ const isDelegate = typeof optionsOrDelegate === 'function';
891
+ const options = isDelegate ? undefined : optionsOrDelegate;
892
+ const actualDelegate = isDelegate ? optionsOrDelegate : delegate;
893
+ // Apply inheritance context BEFORE setting options or calling delegate
894
+ child.withInheritanceContext(this.inheritanceContext);
895
+ // If options are provided (non-delegate overload), handle them
896
+ if (!isDelegate && options !== undefined) {
897
+ const widgetOptions = options;
898
+ const path = widgetOptions.path;
899
+ const name = widgetOptions.name;
900
+ // Set name and path in widget state, not options
901
+ if (name) {
902
+ child.name(name);
903
+ }
904
+ if (path) {
905
+ child.path(path);
906
+ }
907
+ // Remove name and path from options
908
+ const { name: _, path: __, ...cleanOptions } = widgetOptions;
909
+ child.options(cleanOptions);
910
+ }
911
+ // If delegate is provided, call it to allow setting path, options, and other control methods
912
+ if (actualDelegate) {
913
+ actualDelegate(child);
914
+ }
915
+ // Build the widget to check if path is set (for value widgets)
916
+ const builtWidget = child.build();
917
+ // Check if value widget requires path
918
+ const valueWidgetTypes = [
919
+ 'text-editor',
920
+ 'large-text-editor',
921
+ 'rich-text-editor',
922
+ 'password-editor',
923
+ 'number-editor',
924
+ 'select-editor',
925
+ 'lookup-editor',
926
+ 'selection-list-editor',
927
+ 'date-time-editor',
928
+ 'toggle-editor',
929
+ 'color-editor',
930
+ ];
931
+ if (valueWidgetTypes.includes(type) && !builtWidget.path) {
932
+ throw new Error(`Value widget '${type}' requires a 'path' property`);
933
+ }
934
+ this.ensureChildren();
935
+ this.containerState.children.push(builtWidget);
545
936
  return this;
546
937
  }
547
938
  }
@@ -1107,11 +1498,14 @@ class DialogContainerBuilder {
1107
1498
  const dialogNode = this.build();
1108
1499
  // Import the dialog renderer component dynamically
1109
1500
  const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
1501
+ // Collect default values from widget tree and merge into initial context
1502
+ const initialContext = this.dialogState.dialogOptions?.context || {};
1503
+ const contextWithDefaults = collectDefaultValues(dialogNode, initialContext);
1110
1504
  // Create dialog configuration
1111
1505
  const dialogConfig = {
1112
1506
  title: this.dialogState.dialogOptions?.title || '',
1113
1507
  message: this.dialogState.dialogOptions?.message,
1114
- context: this.dialogState.dialogOptions?.context || {},
1508
+ context: contextWithDefaults,
1115
1509
  definition: dialogNode,
1116
1510
  actions: this.dialogState.actions,
1117
1511
  };
@@ -1167,8 +1561,18 @@ class WidgetBuilder {
1167
1561
  return this;
1168
1562
  }
1169
1563
  options(options) {
1170
- // Merge options instead of replacing to preserve inherited properties
1171
- this.widgetState.options = { ...this.widgetState.options, ...options };
1564
+ // Extract defaultValue from options - it's an exceptional parameter that updates context, not a widget option
1565
+ if (options && options.defaultValue !== undefined) {
1566
+ this.widgetState.defaultValue = options.defaultValue;
1567
+ // Remove defaultValue from options since it's stored on the node, not in options
1568
+ const { defaultValue: _, ...cleanOptions } = options;
1569
+ // Merge clean options instead of replacing to preserve inherited properties
1570
+ this.widgetState.options = { ...this.widgetState.options, ...cleanOptions };
1571
+ }
1572
+ else {
1573
+ // Merge options instead of replacing to preserve inherited properties
1574
+ this.widgetState.options = { ...this.widgetState.options, ...options };
1575
+ }
1172
1576
  return this;
1173
1577
  }
1174
1578
  layout(value) {
@@ -1442,268 +1846,6 @@ class StepWizardBuilder extends LayoutContainerMixin {
1442
1846
  }
1443
1847
  }
1444
1848
 
1445
- class AXPLayoutConversionService {
1446
- constructor() {
1447
- //#region ---- Caching ----
1448
- this.widgetTreeCache = new Map();
1449
- this.formDefinitionCache = new Map();
1450
- }
1451
- //#endregion
1452
- //#region ---- Public Methods ----
1453
- /**
1454
- * Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
1455
- * Groups become Fieldset Layouts with Form Field widgets as children
1456
- * Fields become Form Field widgets with Editor widgets as children
1457
- */
1458
- convertFormDefinition(formDefinition) {
1459
- // Create cache key based on form definition content
1460
- const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
1461
- // Check cache first
1462
- if (this.widgetTreeCache.has(cacheKey)) {
1463
- return this.widgetTreeCache.get(cacheKey);
1464
- }
1465
- // Generate widget tree
1466
- const widgetTree = {
1467
- type: 'grid-layout',
1468
- name: 'dynamic-form-container',
1469
- options: {
1470
- title: 'Dynamic Form',
1471
- grid: {
1472
- default: {
1473
- columns: 1,
1474
- gap: '1rem',
1475
- },
1476
- },
1477
- },
1478
- children: formDefinition.groups.map((group) => this.createGroupAsFieldsetWidget(group)),
1479
- };
1480
- // Cache the result
1481
- this.widgetTreeCache.set(cacheKey, widgetTree);
1482
- return widgetTree;
1483
- }
1484
- /**
1485
- * Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
1486
- * Parses Fieldset Layouts back to Groups
1487
- * Parses Form Field widgets back to Fields
1488
- */
1489
- convertWidgetTreeToFormDefinition(widgetTree) {
1490
- // Create cache key based on widget tree content
1491
- const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
1492
- // Check cache first
1493
- if (this.formDefinitionCache.has(cacheKey)) {
1494
- return this.formDefinitionCache.get(cacheKey);
1495
- }
1496
- // Parse widget tree
1497
- const groups = [];
1498
- if (widgetTree.children) {
1499
- widgetTree.children.forEach((child) => {
1500
- if (child.type === 'fieldset-layout') {
1501
- const group = this.extractGroupFromFieldset(child);
1502
- groups.push(group);
1503
- }
1504
- });
1505
- }
1506
- const formDefinition = { groups };
1507
- // Cache the result
1508
- this.formDefinitionCache.set(cacheKey, formDefinition);
1509
- return formDefinition;
1510
- }
1511
- /**
1512
- * Validate that a widget tree represents a valid dynamic form structure
1513
- */
1514
- validateFormWidgetTree(widgetTree) {
1515
- if (!widgetTree || widgetTree.type !== 'grid-layout') {
1516
- return false;
1517
- }
1518
- if (!widgetTree.children || widgetTree.children.length === 0) {
1519
- return true; // Empty form is valid
1520
- }
1521
- // Check that all children are fieldset-layout widgets
1522
- return widgetTree.children.every((child) => child.type === 'fieldset-layout' &&
1523
- child.children &&
1524
- child.children.every((formField) => formField.type === 'form-field' && formField.children && formField.children.length > 0));
1525
- }
1526
- /**
1527
- * Clear all caches
1528
- */
1529
- clearCaches() {
1530
- this.widgetTreeCache.clear();
1531
- this.formDefinitionCache.clear();
1532
- }
1533
- /**
1534
- * Get cache statistics
1535
- */
1536
- getCacheStats() {
1537
- return {
1538
- widgetTreeCacheSize: this.widgetTreeCache.size,
1539
- formDefinitionCacheSize: this.formDefinitionCache.size,
1540
- };
1541
- }
1542
- //#endregion
1543
- //#region ---- Private Methods ----
1544
- /**
1545
- * Convert a single group to Fieldset widget structure
1546
- */
1547
- createGroupAsFieldsetWidget(group) {
1548
- // Determine columns count from layout or default to 1
1549
- const columnsCount = 1;
1550
- return {
1551
- type: 'fieldset-layout',
1552
- name: group.name,
1553
- mode: group.mode,
1554
- options: {
1555
- title: group.title,
1556
- description: group.description,
1557
- cols: columnsCount,
1558
- look: group.look || 'container', // Default to 'container' if not specified
1559
- },
1560
- children: this.createFieldWidgets(group.parameters, columnsCount),
1561
- };
1562
- }
1563
- /**
1564
- * Convert fields to Form Field widgets
1565
- */
1566
- createFieldWidgets(fields, columnsCount) {
1567
- return fields.map((field) => this.createFormFieldWidget(field));
1568
- }
1569
- /**
1570
- * Convert a single field to Form Field widget with editor as child
1571
- */
1572
- createFormFieldWidget(field) {
1573
- return {
1574
- type: 'form-field',
1575
- name: field.path,
1576
- options: {
1577
- label: field.title,
1578
- description: field.description,
1579
- showLabel: true,
1580
- },
1581
- children: [field.widget], // The editor widget becomes a child of form-field
1582
- };
1583
- }
1584
- /**
1585
- * Extract group information from Fieldset Layout widget
1586
- */
1587
- extractGroupFromFieldset(fieldsetNode) {
1588
- const columnsCount = fieldsetNode.options?.['cols'] || 1;
1589
- // Extract fields directly from fieldset children
1590
- const fields = [];
1591
- if (fieldsetNode.children) {
1592
- fieldsetNode.children.forEach((formField) => {
1593
- if (formField.type === 'form-field' && formField.children && formField.children.length > 0) {
1594
- const field = this.extractFieldFromFormWidget(formField);
1595
- if (field) {
1596
- fields.push(field);
1597
- }
1598
- }
1599
- });
1600
- }
1601
- return {
1602
- name: fieldsetNode.name || `group-${Date.now()}`,
1603
- title: fieldsetNode.options?.['title'],
1604
- description: fieldsetNode.options?.['description'],
1605
- parameters: fields,
1606
- mode: fieldsetNode.mode,
1607
- look: fieldsetNode.options?.['look'],
1608
- };
1609
- }
1610
- /**
1611
- * Extract field information from Form Field widget
1612
- */
1613
- extractFieldFromFormWidget(formFieldNode) {
1614
- if (!formFieldNode.children || formFieldNode.children.length === 0) {
1615
- return null;
1616
- }
1617
- const editorWidget = formFieldNode.children[0];
1618
- return {
1619
- path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
1620
- title: formFieldNode.options?.['label'],
1621
- description: formFieldNode.options?.['description'],
1622
- widget: editorWidget,
1623
- mode: formFieldNode.mode,
1624
- };
1625
- }
1626
- /**
1627
- * Create cache key for form definition
1628
- */
1629
- createFormDefinitionCacheKey(formDefinition) {
1630
- // Create a hash-like key instead of full JSON string
1631
- const keyParts = [];
1632
- keyParts.push(`groups:${formDefinition.groups.length}`);
1633
- formDefinition.groups.forEach((group, groupIndex) => {
1634
- keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
1635
- group.parameters.forEach((param, paramIndex) => {
1636
- keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
1637
- });
1638
- });
1639
- if (formDefinition.mode) {
1640
- keyParts.push(`mode:${formDefinition.mode}`);
1641
- }
1642
- // Join with delimiter and create a shorter hash
1643
- const keyString = keyParts.join('|');
1644
- // If still too long, create a simple hash
1645
- if (keyString.length > 100) {
1646
- return this.createSimpleHash(keyString);
1647
- }
1648
- return keyString;
1649
- }
1650
- /**
1651
- * Create cache key for widget tree
1652
- */
1653
- createWidgetTreeCacheKey(widgetTree) {
1654
- // Create a hash-like key instead of full JSON string
1655
- const keyParts = [];
1656
- keyParts.push(`type:${widgetTree.type}`);
1657
- if (widgetTree.name) {
1658
- keyParts.push(`name:${widgetTree.name}`);
1659
- }
1660
- if (widgetTree.children) {
1661
- keyParts.push(`children:${widgetTree.children.length}`);
1662
- widgetTree.children.forEach((child, index) => {
1663
- keyParts.push(`c${index}:${child.type}`);
1664
- if (child.children) {
1665
- keyParts.push(`cc${index}:${child.children.length}`);
1666
- child.children.forEach((grandChild, gIndex) => {
1667
- keyParts.push(`gc${index}.${gIndex}:${grandChild.type}`);
1668
- if (grandChild.children) {
1669
- keyParts.push(`gcc${index}.${gIndex}:${grandChild.children.length}`);
1670
- }
1671
- });
1672
- }
1673
- });
1674
- }
1675
- // Join with delimiter and create a shorter hash
1676
- const keyString = keyParts.join('|');
1677
- // If still too long, create a simple hash
1678
- if (keyString.length > 100) {
1679
- return this.createSimpleHash(keyString);
1680
- }
1681
- return keyString;
1682
- }
1683
- /**
1684
- * Create a simple hash from a string
1685
- */
1686
- createSimpleHash(str) {
1687
- let hash = 0;
1688
- if (str.length === 0)
1689
- return hash.toString();
1690
- for (let i = 0; i < str.length; i++) {
1691
- const char = str.charCodeAt(i);
1692
- hash = (hash << 5) - hash + char;
1693
- hash = hash & hash; // Convert to 32-bit integer
1694
- }
1695
- return Math.abs(hash).toString(36); // Convert to base36 for shorter string
1696
- }
1697
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1698
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
1699
- }
1700
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
1701
- type: Injectable,
1702
- args: [{
1703
- providedIn: 'root',
1704
- }]
1705
- }] });
1706
-
1707
1849
  class AXPLayoutRendererComponent {
1708
1850
  constructor() {
1709
1851
  this.conversionService = inject(AXPLayoutConversionService);
@@ -1945,7 +2087,7 @@ class AXPLayoutRendererComponent {
1945
2087
  }
1946
2088
  </axp-widgets-container>
1947
2089
  </ax-form>
1948
- `, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i2.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2090
+ `, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i2.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1949
2091
  }
1950
2092
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
1951
2093
  type: Component,