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

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 (117) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +295 -45
  2. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  3. package/fesm2022/{acorex-platform-common-common-settings.provider-zhqNP3xb.mjs → acorex-platform-common-common-settings.provider-G9XcXXOG.mjs} +60 -4
  4. package/fesm2022/acorex-platform-common-common-settings.provider-G9XcXXOG.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +960 -319
  6. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-core.mjs +1352 -832
  8. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-domain.mjs +554 -826
  10. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-builder.mjs +530 -154
  12. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs +121 -0
  14. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-layout-components.mjs +5969 -2347
  16. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-layout-designer.mjs +169 -154
  18. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  19. package/fesm2022/acorex-platform-layout-entity.mjs +15380 -9274
  20. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-views.mjs +393 -110
  22. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-widget-core.mjs +511 -450
  24. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  25. package/fesm2022/{acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs → acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs} +10 -10
  26. package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs.map +1 -0
  27. package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs → acorex-platform-layout-widgets-file-list-popup.component-9uCkMxcc.mjs} +39 -16
  28. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-9uCkMxcc.mjs.map +1 -0
  29. package/fesm2022/{acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs → acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs} +6 -7
  30. package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs.map +1 -0
  31. package/fesm2022/{acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs → acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs} +12 -12
  32. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs.map +1 -0
  33. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BGQqY5Mw.mjs +111 -0
  34. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BGQqY5Mw.mjs.map +1 -0
  35. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DmzNTYiS.mjs} +6 -6
  36. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DmzNTYiS.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-BNG_588B.mjs} +5 -5
  38. package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-BNG_588B.mjs.map +1 -0
  39. package/fesm2022/{acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs} +6 -6
  40. package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-layout-widgets.mjs +7865 -4026
  42. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  43. package/fesm2022/acorex-platform-native.mjs +8 -7
  44. package/fesm2022/acorex-platform-native.mjs.map +1 -1
  45. package/fesm2022/acorex-platform-runtime.mjs +220 -169
  46. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  47. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs +160 -0
  48. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs.map +1 -0
  49. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs +120 -0
  50. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs.map +1 -0
  51. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs → acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs} +18 -25
  52. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs.map +1 -0
  53. package/fesm2022/{acorex-platform-themes-default-error-401.component-cfREo88K.mjs → acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs} +4 -4
  54. package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +1 -0
  55. package/fesm2022/{acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs → acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs} +4 -4
  56. package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +1 -0
  57. package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs +19 -0
  58. package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs.map +1 -0
  59. package/fesm2022/acorex-platform-themes-default.mjs +1717 -66
  60. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  61. package/fesm2022/{acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs → acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs} +6 -6
  62. package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs.map +1 -0
  63. package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs → acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs} +6 -6
  64. package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs.map +1 -0
  65. package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +1 -1
  66. package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs → acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs} +11 -11
  67. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs.map +1 -0
  68. package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs} +9 -9
  69. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs.map +1 -0
  70. package/fesm2022/acorex-platform-themes-shared.mjs +563 -561
  71. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  72. package/fesm2022/acorex-platform-workflow.mjs +1735 -1750
  73. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  74. package/fesm2022/acorex-platform.mjs.map +1 -1
  75. package/package.json +31 -31
  76. package/{auth/index.d.ts → types/acorex-platform-auth.d.ts} +247 -10
  77. package/{common/index.d.ts → types/acorex-platform-common.d.ts} +492 -31
  78. package/{core/index.d.ts → types/acorex-platform-core.d.ts} +606 -392
  79. package/{domain/index.d.ts → types/acorex-platform-domain.d.ts} +719 -413
  80. package/{layout/builder/index.d.ts → types/acorex-platform-layout-builder.d.ts} +128 -56
  81. package/types/acorex-platform-layout-components.d.ts +2927 -0
  82. package/{layout/designer/index.d.ts → types/acorex-platform-layout-designer.d.ts} +9 -3
  83. package/{layout/entity/index.d.ts → types/acorex-platform-layout-entity.d.ts} +1133 -237
  84. package/{layout/views/index.d.ts → types/acorex-platform-layout-views.d.ts} +90 -31
  85. package/{layout/widget-core/index.d.ts → types/acorex-platform-layout-widget-core.d.ts} +206 -102
  86. package/{layout/widgets/index.d.ts → types/acorex-platform-layout-widgets.d.ts} +942 -137
  87. package/{native/index.d.ts → types/acorex-platform-native.d.ts} +0 -7
  88. package/{runtime/index.d.ts → types/acorex-platform-runtime.d.ts} +237 -74
  89. package/{themes/default/index.d.ts → types/acorex-platform-themes-default.d.ts} +113 -5
  90. package/{themes/shared/index.d.ts → types/acorex-platform-themes-shared.d.ts} +1 -1
  91. package/types/acorex-platform-workflow.d.ts +1806 -0
  92. package/fesm2022/acorex-platform-common-common-settings.provider-zhqNP3xb.mjs.map +0 -1
  93. package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs.map +0 -1
  94. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +0 -1
  95. package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs.map +0 -1
  96. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs.map +0 -1
  97. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +0 -1
  98. package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs.map +0 -1
  99. package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs.map +0 -1
  100. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs +0 -157
  101. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +0 -1
  102. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs +0 -1542
  103. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs.map +0 -1
  104. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +0 -101
  105. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +0 -1
  106. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +0 -1
  107. package/fesm2022/acorex-platform-themes-default-error-401.component-cfREo88K.mjs.map +0 -1
  108. package/fesm2022/acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs.map +0 -1
  109. package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs +0 -19
  110. package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs.map +0 -1
  111. package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs.map +0 -1
  112. package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs.map +0 -1
  113. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs.map +0 -1
  114. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs.map +0 -1
  115. package/layout/components/index.d.ts +0 -1669
  116. package/workflow/index.d.ts +0 -2443
  117. /package/{index.d.ts → types/acorex-platform.d.ts} +0 -0
@@ -1,13 +1,14 @@
1
- import * as i4 from '@angular/common';
1
+ import * as i5 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { Injectable, inject, 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 } from '@angular/core';
5
+ import { provideCommandSetups } from '@acorex/platform/runtime';
5
6
  import { AXPopupService } from '@acorex/components/popup';
7
+ import * as i1 from '@acorex/platform/layout/widget-core';
8
+ import { AXPWidgetSerializationHelper, AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule, AXPWidgetRegistryService } from '@acorex/platform/layout/widget-core';
6
9
  import { cloneDeep, isNil, set, isEqual } from 'lodash-es';
7
10
  import * as i2 from '@acorex/components/form';
8
11
  import { AXFormComponent, AXFormModule } from '@acorex/components/form';
9
- import * as i1 from '@acorex/platform/layout/widget-core';
10
- import { AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
11
12
  import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
12
13
  import * as i1$1 from '@acorex/components/button';
13
14
  import { AXButtonModule } from '@acorex/components/button';
@@ -16,9 +17,11 @@ import { AXDecoratorModule } from '@acorex/components/decorators';
16
17
  import * as i3 from '@acorex/components/loading';
17
18
  import { AXLoadingModule } from '@acorex/components/loading';
18
19
  import { AXBasePageComponent } from '@acorex/components/page';
19
- import * as i5 from '@acorex/core/translation';
20
- import { AXTranslationModule } from '@acorex/core/translation';
21
- import { AXPExpressionEvaluatorService } from '@acorex/platform/core';
20
+ import * as i6 from '@acorex/core/translation';
21
+ import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
22
+ import * as i4 from '@acorex/platform/core';
23
+ import { AXPExpressionEvaluatorService, AXPComponentSlotModule, AXPContextStore, AXPMultiLanguageStringResolverService } from '@acorex/platform/core';
24
+ import { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
22
25
 
23
26
  class AXPLayoutConversionService {
24
27
  constructor() {
@@ -222,9 +225,16 @@ class AXPLayoutConversionService {
222
225
  const keyParts = [];
223
226
  keyParts.push(`groups:${formDefinition.groups.length}`);
224
227
  formDefinition.groups.forEach((group, groupIndex) => {
225
- keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
228
+ // Include group.mode so view vs edit (or mixed) layouts do not share a cached widget tree.
229
+ const groupModePart = group.mode ?? '_';
230
+ keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}:${groupModePart}`);
231
+ keyParts.push(`gL${groupIndex}:${JSON.stringify(group.title ?? null)}:${JSON.stringify(group.description ?? null)}`);
226
232
  group.parameters.forEach((param, paramIndex) => {
227
- keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
233
+ // Field mode must be part of the key; otherwise metadata forms that only differ by
234
+ // view/edit (same paths and widget types) incorrectly reuse the first cached tree.
235
+ const fieldModePart = param.mode ?? '_';
236
+ keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}:${fieldModePart}`);
237
+ keyParts.push(`pL${groupIndex}.${paramIndex}:${JSON.stringify(param.title ?? null)}:${JSON.stringify(param.description ?? null)}:${JSON.stringify(param.badge ?? null)}`);
228
238
  });
229
239
  });
230
240
  if (formDefinition.mode) {
@@ -285,10 +295,10 @@ class AXPLayoutConversionService {
285
295
  }
286
296
  return Math.abs(hash).toString(36); // Convert to base36 for shorter string
287
297
  }
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' }); }
298
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
299
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
290
300
  }
291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
301
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
292
302
  type: Injectable,
293
303
  args: [{
294
304
  providedIn: 'root',
@@ -361,17 +371,13 @@ function collectDefaultValues(node, context = {}, isTopLevel = true) {
361
371
  const result = isTopLevel ? cloneDeep(context) : context;
362
372
  // Check if this node has a defaultValue and a path
363
373
  // 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;
374
+ const defaultValue = node.defaultValue !== undefined ? node.defaultValue : node.options?.defaultValue;
367
375
  if (defaultValue !== undefined && !isNil(defaultValue) && node.path) {
368
376
  // Check if path exists in context using lodash get equivalent check
369
377
  const currentValue = getNestedValue(result, node.path);
370
378
  if (currentValue === undefined) {
371
379
  // 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);
380
+ const clonedValue = defaultValue instanceof Date ? new Date(defaultValue.getTime()) : cloneDeep(defaultValue);
375
381
  set(result, node.path, clonedValue);
376
382
  }
377
383
  }
@@ -409,10 +415,10 @@ class AXPLayoutBuilderService {
409
415
  create() {
410
416
  return new LayoutBuilder(this.popupService);
411
417
  }
412
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
413
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutBuilderService, providedIn: 'root' }); }
418
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
419
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutBuilderService, providedIn: 'root' }); }
414
420
  }
415
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutBuilderService, decorators: [{
421
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutBuilderService, decorators: [{
416
422
  type: Injectable,
417
423
  args: [{
418
424
  providedIn: 'root',
@@ -527,6 +533,15 @@ class LayoutBuilder {
527
533
  mode: this.root.mode,
528
534
  };
529
535
  }
536
+ /**
537
+ * Converts the built widget node to JSON string
538
+ * @param options - Serialization options
539
+ * @returns JSON string representation of the widget node
540
+ */
541
+ toJson(options) {
542
+ const node = this.build();
543
+ return AXPWidgetSerializationHelper.toJson(node, options);
544
+ }
530
545
  }
531
546
  //#endregion
532
547
  //#region ---- Container Builder Implementation ----
@@ -585,6 +600,7 @@ class BaseContainerBuilder {
585
600
  'number-editor',
586
601
  'select-editor',
587
602
  'lookup-editor',
603
+ 'entity-definition-provider-editor',
588
604
  'selection-list-editor',
589
605
  'date-time-editor',
590
606
  'toggle-editor',
@@ -687,24 +703,30 @@ class BaseContainerMixin extends BaseContainerBuilder {
687
703
  class LayoutContainerMixin extends BaseContainerMixin {
688
704
  layout(value) {
689
705
  // Map layout intent to grid item sizing so containers like `form-field`
690
- // can span multiple columns inside grid/fieldset layouts.
706
+ // can span multiple columns/rows inside grid/fieldset layouts.
691
707
  if (!this.containerState.options)
692
708
  this.containerState.options = {};
693
709
  if (typeof value === 'number') {
694
- // Direct numeric shorthand → colSpan
695
710
  this.containerState.options.colSpan = value;
696
711
  }
697
712
  else if (value) {
698
- // Try to extract a reasonable colSpan from breakpoint positions
699
713
  const positions = value.positions;
700
714
  if (positions) {
701
- const colSpan = positions?.lg?.colSpan ??
702
- positions?.xl?.colSpan ??
703
- positions?.xxl?.colSpan ??
704
- positions?.md?.colSpan ??
705
- positions?.sm?.colSpan;
706
- if (colSpan != null) {
707
- this.containerState.options.colSpan = colSpan;
715
+ const placement = positions?.lg ?? positions?.xl ?? positions?.xxl ?? positions?.md ?? positions?.sm;
716
+ if (placement) {
717
+ const opts = this.containerState.options;
718
+ if (placement.colSpan != null)
719
+ opts.colSpan = placement.colSpan;
720
+ if (placement.colStart != null)
721
+ opts.colStart = placement.colStart;
722
+ if (placement.colEnd != null)
723
+ opts.colEnd = placement.colEnd;
724
+ if (placement.rowSpan != null)
725
+ opts.rowSpan = placement.rowSpan;
726
+ if (placement.rowStart != null)
727
+ opts.rowStart = placement.rowStart;
728
+ if (placement.rowEnd != null)
729
+ opts.rowEnd = placement.rowEnd;
708
730
  }
709
731
  }
710
732
  }
@@ -923,6 +945,7 @@ class WidgetContainerMixin extends ChildContainerMixin {
923
945
  'number-editor',
924
946
  'select-editor',
925
947
  'lookup-editor',
948
+ 'entity-definition-provider-editor',
926
949
  'selection-list-editor',
927
950
  'date-time-editor',
928
951
  'toggle-editor',
@@ -978,6 +1001,34 @@ class FlexContainerBuilder extends WidgetContainerMixin {
978
1001
  * Grid Container Builder - Liskov Substitution Principle
979
1002
  * Extends WidgetContainerMixin to inherit all common functionality
980
1003
  */
1004
+ /**
1005
+ * Extracts flat grid-item options from AXPGridLayoutOptions for grid-item-layout widget.
1006
+ * Uses first available breakpoint (lg, xl, md, sm).
1007
+ */
1008
+ function toGridItemOptions(layoutOptions) {
1009
+ if (!layoutOptions?.positions)
1010
+ return { colSpan: 12 };
1011
+ const positions = layoutOptions.positions;
1012
+ const placement = positions['lg'] ?? positions['xl'] ?? positions['xxl'] ?? positions['md'] ?? positions['sm'];
1013
+ if (!placement)
1014
+ return { colSpan: 12 };
1015
+ const opts = {};
1016
+ if (placement['colSpan'] != null)
1017
+ opts['colSpan'] = placement['colSpan'];
1018
+ if (placement['colStart'] != null)
1019
+ opts['colStart'] = placement['colStart'];
1020
+ if (placement['colEnd'] != null)
1021
+ opts['colEnd'] = placement['colEnd'];
1022
+ if (placement['rowSpan'] != null)
1023
+ opts['rowSpan'] = placement['rowSpan'];
1024
+ if (placement['rowStart'] != null)
1025
+ opts['rowStart'] = placement['rowStart'];
1026
+ if (placement['rowEnd'] != null)
1027
+ opts['rowEnd'] = placement['rowEnd'];
1028
+ if (Object.keys(opts).length === 0)
1029
+ opts['colSpan'] = 12;
1030
+ return opts;
1031
+ }
981
1032
  class GridContainerBuilder extends WidgetContainerMixin {
982
1033
  constructor() {
983
1034
  super('grid-layout');
@@ -986,6 +1037,21 @@ class GridContainerBuilder extends WidgetContainerMixin {
986
1037
  this.containerState.options = { ...this.containerState.options, ...options };
987
1038
  return this;
988
1039
  }
1040
+ item(layoutOptions, delegate) {
1041
+ const fieldset = new FieldsetContainerBuilder();
1042
+ fieldset.withInheritanceContext(this.inheritanceContext);
1043
+ delegate(fieldset);
1044
+ const fieldsetNode = fieldset.build();
1045
+ const gridItemOptions = toGridItemOptions(layoutOptions);
1046
+ const gridItemNode = {
1047
+ type: 'grid-item-layout',
1048
+ options: gridItemOptions,
1049
+ children: [fieldsetNode],
1050
+ };
1051
+ this.ensureChildren();
1052
+ this.containerState.children.push(gridItemNode);
1053
+ return this;
1054
+ }
989
1055
  // Individual fluent methods for Grid
990
1056
  setColumns(columns) {
991
1057
  return this.setOptions({ grid: { default: { columns } } });
@@ -1155,10 +1221,34 @@ class FormFieldBuilder extends LayoutContainerMixin {
1155
1221
  child.type(type);
1156
1222
  child.name(finalName);
1157
1223
  child.path(widgetPath);
1158
- // Remove name from options since it's now in state
1159
- const { name: _, ...cleanOptions } = (options || {});
1224
+ // Extract extended properties from options (triggers, meta, valueTransforms, mode, visible, defaultValue)
1225
+ const { name: _, triggers, meta, valueTransforms, mode: extendedMode, visible: extendedVisible, defaultValue: extendedDefaultValue, children: extendedChildren, ...cleanOptions } = (options || {});
1160
1226
  child.withInheritanceContext(this.inheritanceContext);
1161
1227
  child.options(cleanOptions);
1228
+ // Apply extended properties if provided
1229
+ if (extendedMode !== undefined) {
1230
+ child.mode(extendedMode);
1231
+ }
1232
+ if (extendedVisible !== undefined) {
1233
+ child.visible(extendedVisible);
1234
+ }
1235
+ if (extendedDefaultValue !== undefined) {
1236
+ child.defaultValue(extendedDefaultValue);
1237
+ }
1238
+ // Set triggers, meta, and valueTransforms directly on widgetState
1239
+ // These are part of AXPWidgetNode but not handled by WidgetBuilder methods
1240
+ if (triggers !== undefined) {
1241
+ child.widgetState.triggers = triggers;
1242
+ }
1243
+ if (meta !== undefined) {
1244
+ child.widgetState.meta = meta;
1245
+ }
1246
+ if (valueTransforms !== undefined) {
1247
+ child.widgetState.valueTransforms = valueTransforms;
1248
+ }
1249
+ if (extendedChildren !== undefined) {
1250
+ child.widgetState.children = extendedChildren;
1251
+ }
1162
1252
  // IMPORTANT: Store the widget builder, don't build it yet!
1163
1253
  // This allows properties set after this method (like disabled, readonly) to be applied
1164
1254
  this.childWidget = child;
@@ -1452,6 +1542,10 @@ class DialogContainerBuilder {
1452
1542
  }
1453
1543
  return this;
1454
1544
  }
1545
+ onAction(handler) {
1546
+ (this.dialogState.dialogOptions ??= {}).onAction = handler;
1547
+ return this;
1548
+ }
1455
1549
  addCustomAction(action) {
1456
1550
  // Add to actions based on position
1457
1551
  const position = action.position || 'suffix';
@@ -1500,14 +1594,16 @@ class DialogContainerBuilder {
1500
1594
  const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
1501
1595
  // Collect default values from widget tree and merge into initial context
1502
1596
  const initialContext = this.dialogState.dialogOptions?.context || {};
1597
+ //TODO remove using collectDefaultValues and use initialContext directly for now:
1503
1598
  const contextWithDefaults = collectDefaultValues(dialogNode, initialContext);
1504
1599
  // Create dialog configuration
1505
1600
  const dialogConfig = {
1506
1601
  title: this.dialogState.dialogOptions?.title || '',
1507
1602
  message: this.dialogState.dialogOptions?.message,
1508
- context: contextWithDefaults,
1603
+ context: initialContext,
1509
1604
  definition: dialogNode,
1510
1605
  actions: this.dialogState.actions,
1606
+ onAction: this.dialogState.dialogOptions?.onAction,
1511
1607
  };
1512
1608
  // The Promise resolves when user clicks an action button
1513
1609
  return new Promise(async (resolve) => {
@@ -1520,7 +1616,6 @@ class DialogContainerBuilder {
1520
1616
  data: {
1521
1617
  config: dialogConfig,
1522
1618
  callBack: (result) => {
1523
- // Resolve with the dialog reference when user clicks an action
1524
1619
  resolve(result);
1525
1620
  },
1526
1621
  },
@@ -1539,6 +1634,7 @@ class WidgetBuilder {
1539
1634
  this.widgetState = {
1540
1635
  type: 'widget',
1541
1636
  options: {},
1637
+ children: [],
1542
1638
  };
1543
1639
  this.inheritanceContext = {};
1544
1640
  if (name) {
@@ -1602,6 +1698,7 @@ class WidgetBuilder {
1602
1698
  this.widgetState.options = {};
1603
1699
  }
1604
1700
  this.widgetState.options['visible'] = condition;
1701
+ this.widgetState.visible = condition;
1605
1702
  this.inheritanceContext.visible = condition;
1606
1703
  return this;
1607
1704
  }
@@ -1633,6 +1730,10 @@ class WidgetBuilder {
1633
1730
  this.inheritanceContext.direction = direction;
1634
1731
  return this;
1635
1732
  }
1733
+ children(children) {
1734
+ this.widgetState.children = children;
1735
+ return this;
1736
+ }
1636
1737
  // Inheritance context methods
1637
1738
  withInheritanceContext(context) {
1638
1739
  this.inheritanceContext = mergeInheritanceContext(context);
@@ -1656,6 +1757,7 @@ class WidgetBuilder {
1656
1757
  }
1657
1758
  if (resolved.visible !== undefined) {
1658
1759
  this.widgetState.options['visible'] = resolved.visible;
1760
+ this.widgetState.visible = resolved.visible;
1659
1761
  }
1660
1762
  if (context.defaultValue !== undefined) {
1661
1763
  this.widgetState.defaultValue = context.defaultValue;
@@ -1666,14 +1768,29 @@ class WidgetBuilder {
1666
1768
  return { ...this.inheritanceContext };
1667
1769
  }
1668
1770
  build() {
1669
- return {
1771
+ const node = {
1670
1772
  name: this.widgetState.name,
1671
1773
  type: this.widgetState.type,
1672
1774
  options: this.widgetState.options,
1673
1775
  mode: this.widgetState.mode,
1674
1776
  path: this.widgetState.path,
1675
1777
  defaultValue: this.widgetState.defaultValue,
1778
+ children: this.widgetState.children,
1676
1779
  };
1780
+ // Add extended properties if they exist
1781
+ if (this.widgetState.triggers !== undefined) {
1782
+ node.triggers = this.widgetState.triggers;
1783
+ }
1784
+ if (this.widgetState.meta !== undefined) {
1785
+ node.meta = this.widgetState.meta;
1786
+ }
1787
+ if (this.widgetState.valueTransforms !== undefined) {
1788
+ node.valueTransforms = this.widgetState.valueTransforms;
1789
+ }
1790
+ if (this.widgetState.visible !== undefined) {
1791
+ node.visible = this.widgetState.visible;
1792
+ }
1793
+ return node;
1677
1794
  }
1678
1795
  }
1679
1796
  //#region ---- Action Builder Implementation ----
@@ -1687,7 +1804,6 @@ class ActionBuilder {
1687
1804
  }
1688
1805
  this.dialogBuilder['dialogState'].actions.footer.suffix.push({
1689
1806
  title: text || '@general:actions.cancel.title',
1690
- icon: 'fa-times',
1691
1807
  color: 'default',
1692
1808
  command: { name: 'cancel' },
1693
1809
  });
@@ -1699,17 +1815,25 @@ class ActionBuilder {
1699
1815
  }
1700
1816
  this.dialogBuilder['dialogState'].actions.footer.suffix.push({
1701
1817
  title: text || '@general:actions.submit.title',
1702
- icon: 'fa-check',
1703
1818
  color: 'primary',
1704
1819
  command: { name: 'submit', options: { validate: true } },
1705
1820
  });
1706
1821
  return this;
1707
1822
  }
1708
1823
  custom(action) {
1709
- if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
1710
- this.dialogBuilder['dialogState'].actions.footer.suffix = [];
1824
+ const position = action.position ?? 'suffix';
1825
+ if (position === 'prefix') {
1826
+ if (!this.dialogBuilder['dialogState'].actions.footer.prefix) {
1827
+ this.dialogBuilder['dialogState'].actions.footer.prefix = [];
1828
+ }
1829
+ this.dialogBuilder['dialogState'].actions.footer.prefix.push(action);
1830
+ }
1831
+ else {
1832
+ if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
1833
+ this.dialogBuilder['dialogState'].actions.footer.suffix = [];
1834
+ }
1835
+ this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
1711
1836
  }
1712
- this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
1713
1837
  return this;
1714
1838
  }
1715
1839
  }
@@ -1858,22 +1982,22 @@ class AXPLayoutRendererComponent {
1858
1982
  /**
1859
1983
  * Form definition containing groups and fields OR widget tree
1860
1984
  */
1861
- this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : []));
1985
+ this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
1862
1986
  /**
1863
1987
  * Form context/model data
1864
1988
  */
1865
- this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
1989
+ this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
1866
1990
  /**
1867
1991
  * Form appearance and density styling (normal, compact, spacious)
1868
1992
  */
1869
- this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : []));
1993
+ this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : /* istanbul ignore next */ []));
1870
1994
  /**
1871
1995
  * Default form mode. Can be overridden by section/group and field.
1872
1996
  */
1873
- this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : []));
1997
+ this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
1874
1998
  //#endregion
1875
1999
  //#region ---- Widget Tree Conversion ----
1876
- this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : []));
2000
+ this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : /* istanbul ignore next */ []));
1877
2001
  /**
1878
2002
  * Convert layout data to widget tree when inputs change
1879
2003
  */
@@ -1898,7 +2022,7 @@ class AXPLayoutRendererComponent {
1898
2022
  if (!isEqual(prev, tree)) {
1899
2023
  this.widgetTree.set(tree);
1900
2024
  }
1901
- }, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : []));
2025
+ }, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : /* istanbul ignore next */ []));
1902
2026
  //#endregion
1903
2027
  //#region ---- Outputs ----
1904
2028
  /**
@@ -1911,12 +2035,12 @@ class AXPLayoutRendererComponent {
1911
2035
  this.validityChange = output();
1912
2036
  //#endregion
1913
2037
  //#region ---- Properties ----
1914
- this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : []));
1915
- this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
2038
+ this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
2039
+ this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : /* istanbul ignore next */ []));
1916
2040
  /**
1917
2041
  * Internal context signal for reactivity
1918
2042
  */
1919
- this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : []));
2043
+ this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : /* istanbul ignore next */ []));
1920
2044
  /**
1921
2045
  * Initial context for reset functionality
1922
2046
  */
@@ -1929,7 +2053,7 @@ class AXPLayoutRendererComponent {
1929
2053
  this.#contextSyncEffect = effect(() => {
1930
2054
  const ctx = this.context() ?? {};
1931
2055
  this.contextUpdateSubject.next(ctx);
1932
- }, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : []));
2056
+ }, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : /* istanbul ignore next */ []));
1933
2057
  /**
1934
2058
  * Effect to handle widget tree status changes
1935
2059
  */
@@ -1938,7 +2062,7 @@ class AXPLayoutRendererComponent {
1938
2062
  if (widgetTree) {
1939
2063
  this.container()?.builderService.setStatus(AXPPageStatus.Rendered);
1940
2064
  }
1941
- }, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : []));
2065
+ }, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : /* istanbul ignore next */ []));
1942
2066
  }
1943
2067
  //#endregion
1944
2068
  //#region ---- Lifecycle Methods ----
@@ -2078,8 +2202,8 @@ class AXPLayoutRendererComponent {
2078
2202
  isWidgetNode(data) {
2079
2203
  return data && typeof data === 'object' && 'type' in data && typeof data.type === 'string';
2080
2204
  }
2081
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2082
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPLayoutRendererComponent, isStandalone: true, selector: "axp-layout-renderer", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { context: "contextChange", contextInitiated: "contextInitiated", validityChange: "validityChange" }, viewQueries: [{ propertyName: "form", first: true, predicate: AXFormComponent, descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
2205
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2206
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLayoutRendererComponent, isStandalone: true, selector: "axp-layout-renderer", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { context: "contextChange", contextInitiated: "contextInitiated", validityChange: "validityChange" }, viewQueries: [{ propertyName: "form", first: true, predicate: AXFormComponent, descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
2083
2207
  <ax-form>
2084
2208
  <axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
2085
2209
  @if (widgetTree()) {
@@ -2087,11 +2211,11 @@ class AXPLayoutRendererComponent {
2087
2211
  }
2088
2212
  </axp-widgets-container>
2089
2213
  </ax-form>
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 }); }
2214
+ `, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ 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", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2091
2215
  }
2092
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
2216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
2093
2217
  type: Component,
2094
- args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [CommonModule, AXPWidgetCoreModule, AXFormModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2218
+ args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [AXPWidgetCoreModule, AXFormModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2095
2219
  <ax-form>
2096
2220
  <axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
2097
2221
  @if (widgetTree()) {
@@ -2102,16 +2226,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2102
2226
  `, styles: [":host{display:block;width:100%}\n"] }]
2103
2227
  }], propDecorators: { layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }, { type: i0.Output, args: ["contextChange"] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], contextInitiated: [{ type: i0.Output, args: ["contextInitiated"] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], form: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXFormComponent), { isSignal: true }] }], container: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPWidgetContainerComponent), { isSignal: true }] }] } });
2104
2228
 
2229
+ /** Registration key for {@link AXPPreviewWidgetFieldCommand}; lives alone so `LayoutBuilderModule` can reference it without static-importing the command implementation. */
2230
+ const AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY = 'Widget:Preview';
2231
+
2105
2232
  class LayoutBuilderModule {
2106
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: LayoutBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2107
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.12", ngImport: i0, type: LayoutBuilderModule, imports: [CommonModule, AXPLayoutRendererComponent], exports: [AXPLayoutRendererComponent] }); }
2108
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: LayoutBuilderModule, providers: [AXPLayoutBuilderService], imports: [CommonModule, AXPLayoutRendererComponent] }); }
2233
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2234
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, imports: [CommonModule, AXPLayoutRendererComponent], exports: [AXPLayoutRendererComponent] }); }
2235
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, providers: [
2236
+ AXPLayoutBuilderService,
2237
+ provideCommandSetups([
2238
+ {
2239
+ key: AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY,
2240
+ command: () => Promise.resolve().then(function () { return previewWidgetField_command; }).then((c) => c.AXPPreviewWidgetFieldCommand),
2241
+ },
2242
+ ]),
2243
+ ], imports: [CommonModule, AXPLayoutRendererComponent] }); }
2109
2244
  }
2110
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: LayoutBuilderModule, decorators: [{
2245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: LayoutBuilderModule, decorators: [{
2111
2246
  type: NgModule,
2112
2247
  args: [{
2113
2248
  imports: [CommonModule, AXPLayoutRendererComponent],
2114
- providers: [AXPLayoutBuilderService],
2249
+ providers: [
2250
+ AXPLayoutBuilderService,
2251
+ provideCommandSetups([
2252
+ {
2253
+ key: AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY,
2254
+ command: () => Promise.resolve().then(function () { return previewWidgetField_command; }).then((c) => c.AXPPreviewWidgetFieldCommand),
2255
+ },
2256
+ ]),
2257
+ ],
2115
2258
  exports: [AXPLayoutRendererComponent],
2116
2259
  }]
2117
2260
  }] });
@@ -2123,17 +2266,17 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2123
2266
  super(...arguments);
2124
2267
  this.result = new EventEmitter();
2125
2268
  this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
2126
- this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
2269
+ this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
2127
2270
  // This will be set by the popup service automatically - same as dynamic-dialog
2128
2271
  this.callBack = () => { };
2129
- this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : []));
2272
+ this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : /* istanbul ignore next */ []));
2130
2273
  // Aggregated actions for footer rendering
2131
- this.footerPrefix = signal([], ...(ngDevMode ? [{ debugName: "footerPrefix" }] : []));
2132
- this.footerSuffix = signal([], ...(ngDevMode ? [{ debugName: "footerSuffix" }] : []));
2274
+ this.footerPrefix = signal([], ...(ngDevMode ? [{ debugName: "footerPrefix" }] : /* istanbul ignore next */ []));
2275
+ this.footerSuffix = signal([], ...(ngDevMode ? [{ debugName: "footerSuffix" }] : /* istanbul ignore next */ []));
2133
2276
  //#endregion
2134
2277
  //#region ---- View Accessors ----
2135
2278
  // Access the internal layout renderer to reach the widgets container injector
2136
- this.layoutRenderer = viewChild(AXPLayoutRendererComponent, ...(ngDevMode ? [{ debugName: "layoutRenderer" }] : []));
2279
+ this.layoutRenderer = viewChild(AXPLayoutRendererComponent, ...(ngDevMode ? [{ debugName: "layoutRenderer" }] : /* istanbul ignore next */ []));
2137
2280
  this.#eff = effect(() => {
2138
2281
  let count = 0;
2139
2282
  this.aggregateAndEvaluateActions();
@@ -2141,10 +2284,10 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2141
2284
  const renderer = this.layoutRenderer();
2142
2285
  const container = renderer?.getContainer();
2143
2286
  this.widgetCoreService = container?.builderService ?? null;
2144
- count = this.widgetCoreService.registeredWidgetsCount();
2287
+ count = this.widgetCoreService?.registeredWidgetsCount();
2145
2288
  }
2146
2289
  else {
2147
- count = this.widgetCoreService.registeredWidgetsCount();
2290
+ count = this.widgetCoreService?.registeredWidgetsCount();
2148
2291
  // Clear existing timer
2149
2292
  if (this.debounceTimer) {
2150
2293
  clearTimeout(this.debounceTimer);
@@ -2154,12 +2297,11 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2154
2297
  this.aggregateAndEvaluateActions();
2155
2298
  }, 200);
2156
2299
  }
2157
- }, ...(ngDevMode ? [{ debugName: "#eff" }] : []));
2300
+ }, ...(ngDevMode ? [{ debugName: "#eff" }] : /* istanbul ignore next */ []));
2158
2301
  }
2159
2302
  //#endregion
2160
2303
  //#region ---- Lifecycle ----
2161
2304
  ngOnInit() {
2162
- // Initialize context with provided context
2163
2305
  this.context.set(this.config?.context || {});
2164
2306
  }
2165
2307
  #eff;
@@ -2185,14 +2327,14 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2185
2327
  return this.isDialogLoading();
2186
2328
  }
2187
2329
  async executeAction(action) {
2188
- const cmd = action.command;
2330
+ const cmd = this.resolveActionCommandName(action.command);
2189
2331
  if (cmd !== 'cancel') {
2190
2332
  const isValid = await this.layoutRenderer()?.validate();
2191
2333
  if (!isValid?.result) {
2192
2334
  return;
2193
2335
  }
2194
2336
  }
2195
- if (typeof cmd === 'string' && cmd.startsWith('widget:')) {
2337
+ if (cmd?.startsWith('widget:')) {
2196
2338
  const parsed = this.parseWidgetCommand(cmd);
2197
2339
  if (parsed.widgetName && parsed.action) {
2198
2340
  await this.executeWidgetApi(parsed.widgetName, parsed.action);
@@ -2200,16 +2342,39 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2200
2342
  return;
2201
2343
  }
2202
2344
  }
2345
+ const context = this.context();
2346
+ const onAction = this.config?.onAction;
2347
+ if (onAction) {
2348
+ const dialogRef = {
2349
+ close: (res) => this.close(res),
2350
+ context: () => this.context(),
2351
+ action: () => action.command ?? undefined,
2352
+ setLoading: (loading) => this.isDialogLoading.set(loading),
2353
+ };
2354
+ try {
2355
+ this.isDialogLoading.set(true);
2356
+ const result = await Promise.resolve(onAction(dialogRef));
2357
+ this.callBack(result);
2358
+ this.close(result);
2359
+ }
2360
+ catch {
2361
+ // Handler threw: stay open for retry, actions remain clickable
2362
+ }
2363
+ finally {
2364
+ this.isDialogLoading.set(false);
2365
+ }
2366
+ return;
2367
+ }
2203
2368
  // Fallback: treat as regular dialog action (cancel/confirm/custom)
2204
- const result = { context: this.context(), action: cmd };
2369
+ const result = { context, action: cmd };
2205
2370
  this.dialogResult = result;
2206
2371
  if (this.data) {
2207
2372
  this.data.context = result.context;
2208
2373
  this.data.action = result.action;
2209
2374
  }
2210
2375
  this.callBack({
2211
- close: (result) => {
2212
- this.close(result);
2376
+ close: (res) => {
2377
+ this.close(res);
2213
2378
  },
2214
2379
  context: () => this.context(),
2215
2380
  action: () => result.action,
@@ -2217,6 +2382,20 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2217
2382
  this.isDialogLoading.set(loading);
2218
2383
  },
2219
2384
  });
2385
+ // Without `onAction`, only the configured cancel action dismisses the dialog (not submit/custom).
2386
+ if (cmd === 'cancel') {
2387
+ await this.close(result);
2388
+ }
2389
+ }
2390
+ /** Resolves footer/widget action command to a string (e.g. `cancel`, `submit`, `widget:...`). */
2391
+ resolveActionCommandName(command) {
2392
+ if (typeof command === 'string') {
2393
+ return command;
2394
+ }
2395
+ if (command && typeof command === 'object' && 'name' in command) {
2396
+ return command.name;
2397
+ }
2398
+ return undefined;
2220
2399
  }
2221
2400
  parseWidgetCommand(cmd) {
2222
2401
  // Expected 'widget:<widgetName>.<action>'
@@ -2343,8 +2522,9 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2343
2522
  return undefined;
2344
2523
  }
2345
2524
  }
2346
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPDialogRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2347
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", inputs: { config: "config" }, outputs: { result: "result" }, viewQueries: [{ propertyName: "layoutRenderer", first: true, predicate: AXPLayoutRendererComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
2525
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDialogRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2526
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", outputs: { result: "result" }, providers: [AXPContextStore], viewQueries: [{ propertyName: "layoutRenderer", first: true, predicate: AXPLayoutRendererComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
2527
+ <axp-component-slot name="dialog-header" [context]="context()"></axp-component-slot>
2348
2528
  <div class="ax-p-4">
2349
2529
  <axp-layout-renderer
2350
2530
  [layout]="config.definition"
@@ -2355,46 +2535,52 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
2355
2535
  </axp-layout-renderer>
2356
2536
  </div>
2357
2537
 
2358
- <ax-footer>
2359
- <ax-prefix>
2360
- @for (action of footerPrefixActions(); track $index) {
2361
- <ax-button
2362
- [disabled]="action.disabled || isFormLoading()"
2363
- [text]="(action.title | translate | async)!"
2364
- [look]="'outline'"
2365
- [color]="action.color"
2366
- (onClick)="executeAction(action)"
2367
- >
2368
- <ax-prefix>
2369
- <i class="{{ action.icon }}"></i>
2370
- </ax-prefix>
2371
- </ax-button>
2372
- }
2373
- </ax-prefix>
2374
- <ax-suffix>
2375
- @for (action of footerSuffixActions(); track $index) {
2376
- <ax-button
2377
- [disabled]="action.disabled || isSubmitting()"
2378
- [text]="(action.title | translate | async)!"
2379
- [look]="'solid'"
2380
- [color]="action.color"
2381
- (onClick)="executeAction(action)"
2382
- >
2383
- @if (isFormLoading()) {
2384
- <ax-loading></ax-loading>
2385
- }
2386
- @if (action.icon) {
2538
+ <!-- Custom footer slot: if it has content, default footer is hidden -->
2539
+ <axp-component-slot name="dialog-footer" #footerSlot="slot" [context]="context()"></axp-component-slot>
2540
+ @if (footerSlot.isEmpty()) {
2541
+ <ax-footer>
2542
+ <ax-prefix>
2543
+ <axp-component-slot name="dialog-footer-prefix" [context]="context()"></axp-component-slot>
2544
+ @for (action of footerPrefixActions(); track $index) {
2545
+ <ax-button
2546
+ [disabled]="action.disabled || isFormLoading()"
2547
+ [text]="(action.title | translate | async)!"
2548
+ [look]="'outline'"
2549
+ [color]="action.color"
2550
+ (onClick)="executeAction(action)"
2551
+ >
2387
2552
  <ax-prefix>
2388
- <ax-icon icon="{{ action.icon }}"></ax-icon>
2553
+ <i class="{{ action.icon }}"></i>
2389
2554
  </ax-prefix>
2390
- }
2391
- </ax-button>
2392
- }
2393
- </ax-suffix>
2394
- </ax-footer>
2395
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i3.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }] }); }
2555
+ </ax-button>
2556
+ }
2557
+ </ax-prefix>
2558
+ <ax-suffix>
2559
+ @for (action of footerSuffixActions(); track $index) {
2560
+ <ax-button
2561
+ [disabled]="action.disabled || isSubmitting()"
2562
+ [text]="(action.title | translate | async)!"
2563
+ [look]="'solid'"
2564
+ [color]="action.color"
2565
+ (onClick)="executeAction(action)"
2566
+ >
2567
+ @if (isFormLoading()) {
2568
+ <ax-loading></ax-loading>
2569
+ }
2570
+ @if (action.icon) {
2571
+ <ax-prefix>
2572
+ <ax-icon icon="{{ action.icon }}"></ax-icon>
2573
+ </ax-prefix>
2574
+ }
2575
+ </ax-button>
2576
+ }
2577
+ <axp-component-slot name="dialog-footer-suffix" [context]="context()"></axp-component-slot>
2578
+ </ax-suffix>
2579
+ </ax-footer>
2580
+ }
2581
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i3.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "directive", type: i4.AXPComponentSlotDirective, selector: "axp-component-slot", inputs: ["name", "host", "context"], exportAs: ["slot"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2396
2582
  }
2397
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPDialogRendererComponent, decorators: [{
2583
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDialogRendererComponent, decorators: [{
2398
2584
  type: Component,
2399
2585
  args: [{
2400
2586
  selector: 'axp-dialog-renderer',
@@ -2406,8 +2592,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2406
2592
  AXDecoratorModule,
2407
2593
  AXLoadingModule,
2408
2594
  AXTranslationModule,
2595
+ AXPComponentSlotModule,
2409
2596
  ],
2597
+ providers: [AXPContextStore],
2598
+ changeDetection: ChangeDetectionStrategy.OnPush,
2410
2599
  template: `
2600
+ <axp-component-slot name="dialog-header" [context]="context()"></axp-component-slot>
2411
2601
  <div class="ax-p-4">
2412
2602
  <axp-layout-renderer
2413
2603
  [layout]="config.definition"
@@ -2418,48 +2608,52 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
2418
2608
  </axp-layout-renderer>
2419
2609
  </div>
2420
2610
 
2421
- <ax-footer>
2422
- <ax-prefix>
2423
- @for (action of footerPrefixActions(); track $index) {
2424
- <ax-button
2425
- [disabled]="action.disabled || isFormLoading()"
2426
- [text]="(action.title | translate | async)!"
2427
- [look]="'outline'"
2428
- [color]="action.color"
2429
- (onClick)="executeAction(action)"
2430
- >
2431
- <ax-prefix>
2432
- <i class="{{ action.icon }}"></i>
2433
- </ax-prefix>
2434
- </ax-button>
2435
- }
2436
- </ax-prefix>
2437
- <ax-suffix>
2438
- @for (action of footerSuffixActions(); track $index) {
2439
- <ax-button
2440
- [disabled]="action.disabled || isSubmitting()"
2441
- [text]="(action.title | translate | async)!"
2442
- [look]="'solid'"
2443
- [color]="action.color"
2444
- (onClick)="executeAction(action)"
2445
- >
2446
- @if (isFormLoading()) {
2447
- <ax-loading></ax-loading>
2448
- }
2449
- @if (action.icon) {
2611
+ <!-- Custom footer slot: if it has content, default footer is hidden -->
2612
+ <axp-component-slot name="dialog-footer" #footerSlot="slot" [context]="context()"></axp-component-slot>
2613
+ @if (footerSlot.isEmpty()) {
2614
+ <ax-footer>
2615
+ <ax-prefix>
2616
+ <axp-component-slot name="dialog-footer-prefix" [context]="context()"></axp-component-slot>
2617
+ @for (action of footerPrefixActions(); track $index) {
2618
+ <ax-button
2619
+ [disabled]="action.disabled || isFormLoading()"
2620
+ [text]="(action.title | translate | async)!"
2621
+ [look]="'outline'"
2622
+ [color]="action.color"
2623
+ (onClick)="executeAction(action)"
2624
+ >
2450
2625
  <ax-prefix>
2451
- <ax-icon icon="{{ action.icon }}"></ax-icon>
2626
+ <i class="{{ action.icon }}"></i>
2452
2627
  </ax-prefix>
2453
- }
2454
- </ax-button>
2455
- }
2456
- </ax-suffix>
2457
- </ax-footer>
2628
+ </ax-button>
2629
+ }
2630
+ </ax-prefix>
2631
+ <ax-suffix>
2632
+ @for (action of footerSuffixActions(); track $index) {
2633
+ <ax-button
2634
+ [disabled]="action.disabled || isSubmitting()"
2635
+ [text]="(action.title | translate | async)!"
2636
+ [look]="'solid'"
2637
+ [color]="action.color"
2638
+ (onClick)="executeAction(action)"
2639
+ >
2640
+ @if (isFormLoading()) {
2641
+ <ax-loading></ax-loading>
2642
+ }
2643
+ @if (action.icon) {
2644
+ <ax-prefix>
2645
+ <ax-icon icon="{{ action.icon }}"></ax-icon>
2646
+ </ax-prefix>
2647
+ }
2648
+ </ax-button>
2649
+ }
2650
+ <axp-component-slot name="dialog-footer-suffix" [context]="context()"></axp-component-slot>
2651
+ </ax-suffix>
2652
+ </ax-footer>
2653
+ }
2458
2654
  `,
2459
2655
  }]
2460
- }], propDecorators: { config: [{
2461
- type: Input
2462
- }], result: [{
2656
+ }], propDecorators: { result: [{
2463
2657
  type: Output
2464
2658
  }], layoutRenderer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPLayoutRendererComponent), { isSignal: true }] }] } });
2465
2659
 
@@ -2468,9 +2662,191 @@ var dialogRenderer_component = /*#__PURE__*/Object.freeze({
2468
2662
  AXPDialogRendererComponent: AXPDialogRendererComponent
2469
2663
  });
2470
2664
 
2665
+ //#region ---- Imports ----
2666
+ /**
2667
+ * `customWidget` only forwards keys from its options bag into the built node via `addSingleWidget`.
2668
+ * Designer / configurator persist `defaultValue` (and other extended fields) on the widget node root;
2669
+ * spreading `options` alone drops them, so preview never applied defaults.
2670
+ */
2671
+ /**
2672
+ * Widget options are sometimes persisted with an extra nesting (`options.options`) when context
2673
+ * was merged incorrectly. Flatten so list/data-source resolution sees `dataSource` at the top level.
2674
+ */
2675
+ function optionsBagForPreview(node) {
2676
+ const raw = (node.options ?? {});
2677
+ const inner = raw['options'];
2678
+ if (inner !== undefined && typeof inner === 'object' && !Array.isArray(inner)) {
2679
+ const { options: _nested, ...rest } = raw;
2680
+ return { ...rest, ...inner };
2681
+ }
2682
+ return { ...raw };
2683
+ }
2684
+ function extendedNodePropsForPreview(node) {
2685
+ const out = {};
2686
+ if (node.defaultValue !== undefined) {
2687
+ out['defaultValue'] = node.defaultValue;
2688
+ }
2689
+ if (node.triggers !== undefined) {
2690
+ out['triggers'] = node.triggers;
2691
+ }
2692
+ if (node.meta !== undefined) {
2693
+ out['meta'] = node.meta;
2694
+ }
2695
+ if (node.valueTransforms !== undefined) {
2696
+ out['valueTransforms'] = node.valueTransforms;
2697
+ }
2698
+ if (node.visible !== undefined) {
2699
+ out['visible'] = node.visible;
2700
+ }
2701
+ if (node.mode !== undefined) {
2702
+ out['mode'] = node.mode;
2703
+ }
2704
+ if (node.children !== undefined) {
2705
+ out['children'] = node.children;
2706
+ }
2707
+ return out;
2708
+ }
2709
+ //#endregion
2710
+ //#region ---- Command ----
2711
+ /**
2712
+ * Opens a dialog that previews a widget configuration (same behavior as the preview button on
2713
+ * `axp-widget-field-configurator`). Invoked from that component and from entity list actions.
2714
+ */
2715
+ class AXPPreviewWidgetFieldCommand {
2716
+ constructor() {
2717
+ this.formBuilderService = inject(AXPLayoutBuilderService);
2718
+ this.widgetRegistry = inject(AXPWidgetRegistryService);
2719
+ this.translationService = inject(AXTranslationService);
2720
+ this.mlResolver = inject(AXPMultiLanguageStringResolverService);
2721
+ this.crudService = inject(AXP_ENTITY_DEFINITION_CRUD_SERVICE, { optional: true });
2722
+ }
2723
+ async execute(input) {
2724
+ try {
2725
+ const merged = this.mergeInvocation(input);
2726
+ const currentWidget = this.normalizeWidget(merged['widget'] ?? merged['interface']);
2727
+ if (!currentWidget?.type) {
2728
+ return {
2729
+ success: false,
2730
+ message: { text: (await this.translationService.translateAsync('@general:messages.invalid-data')) || 'Invalid data' },
2731
+ };
2732
+ }
2733
+ const fieldName = String(merged['fieldName'] ?? merged['name'] ?? 'Field');
2734
+ const rawTitle = (merged['fieldTitle'] ?? merged['title']);
2735
+ const fieldTitleLabel = this.resolveFieldTitleLabel(rawTitle, fieldName);
2736
+ const dialogTitle = (await this.resolveWidgetDisplayTitle(currentWidget.type)) ||
2737
+ currentWidget.type ||
2738
+ fieldTitleLabel;
2739
+ const previewWidgetOptions = {
2740
+ ...optionsBagForPreview(currentWidget),
2741
+ name: fieldName,
2742
+ ...extendedNodePropsForPreview(currentWidget),
2743
+ };
2744
+ const dialogOutcome = await this.formBuilderService
2745
+ .create()
2746
+ .dialog((dialog) => {
2747
+ dialog
2748
+ .setTitle(dialogTitle)
2749
+ .setSize('md')
2750
+ .setCloseButton(true)
2751
+ .setContext({})
2752
+ .content((layoutBuilder) => {
2753
+ layoutBuilder.formField(fieldTitleLabel, (formField) => {
2754
+ formField.customWidget(currentWidget.type, previewWidgetOptions);
2755
+ });
2756
+ })
2757
+ .setActions((actions) => actions.cancel('@general:actions.close.title'));
2758
+ })
2759
+ .show();
2760
+ const cancelled = this.isCancelDialogOutcome(dialogOutcome);
2761
+ return {
2762
+ success: !cancelled,
2763
+ message: { text: '' },
2764
+ };
2765
+ }
2766
+ catch (error) {
2767
+ const message = error instanceof Error ? error.message : 'Unknown error';
2768
+ return {
2769
+ success: false,
2770
+ message: { text: message },
2771
+ };
2772
+ }
2773
+ }
2774
+ mergeInvocation(input) {
2775
+ const contextOptions = input.__context__?.options;
2776
+ const ctxData = input.__context__?.data;
2777
+ const { __context__: _ctx, ...rest } = input;
2778
+ return {
2779
+ ...(ctxData ?? {}),
2780
+ ...(contextOptions ?? {}),
2781
+ ...rest,
2782
+ };
2783
+ }
2784
+ normalizeWidget(raw) {
2785
+ if (raw == null)
2786
+ return null;
2787
+ if (typeof raw === 'string') {
2788
+ const t = raw.trim();
2789
+ return t ? { type: t, options: {} } : null;
2790
+ }
2791
+ if (typeof raw === 'object' && !Array.isArray(raw) && 'type' in raw) {
2792
+ const w = raw;
2793
+ return w.type ? cloneDeep(w) : null;
2794
+ }
2795
+ return null;
2796
+ }
2797
+ resolveFieldTitleLabel(raw, fallback) {
2798
+ let source = fallback;
2799
+ if (raw !== undefined && raw !== null) {
2800
+ if (typeof raw === 'string') {
2801
+ if (raw.trim() !== '') {
2802
+ source = raw;
2803
+ }
2804
+ }
2805
+ else if (typeof raw === 'object' && !Array.isArray(raw) && Object.keys(raw).length > 0) {
2806
+ source = raw;
2807
+ }
2808
+ }
2809
+ return this.mlResolver.resolve(source);
2810
+ }
2811
+ isCancelDialogOutcome(outcome) {
2812
+ if (outcome == null) {
2813
+ return false;
2814
+ }
2815
+ const ref = outcome;
2816
+ if (typeof ref.action !== 'function') {
2817
+ return false;
2818
+ }
2819
+ return ref.action() === 'cancel';
2820
+ }
2821
+ async resolveWidgetDisplayTitle(widgetType) {
2822
+ const crud = this.crudService;
2823
+ if (crud) {
2824
+ const interfaces = await crud.listInterfaces();
2825
+ const iface = interfaces.find((d) => d.name === widgetType);
2826
+ return iface?.title ?? iface?.name;
2827
+ }
2828
+ const config = this.widgetRegistry.getOptional(widgetType);
2829
+ if (!config) {
2830
+ return undefined;
2831
+ }
2832
+ const resolved = this.mlResolver.resolve(config.title);
2833
+ return resolved || undefined;
2834
+ }
2835
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPreviewWidgetFieldCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2836
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPreviewWidgetFieldCommand }); }
2837
+ }
2838
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPreviewWidgetFieldCommand, decorators: [{
2839
+ type: Injectable
2840
+ }] });
2841
+
2842
+ var previewWidgetField_command = /*#__PURE__*/Object.freeze({
2843
+ __proto__: null,
2844
+ AXPPreviewWidgetFieldCommand: AXPPreviewWidgetFieldCommand
2845
+ });
2846
+
2471
2847
  /**
2472
2848
  * Generated bundle index. Do not edit.
2473
2849
  */
2474
2850
 
2475
- export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, LayoutBuilderModule };
2851
+ export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, AXPPreviewWidgetFieldCommand, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, LayoutBuilderModule };
2476
2852
  //# sourceMappingURL=acorex-platform-layout-builder.mjs.map