@acorex/platform 21.0.0-next.85 → 21.0.0-next.89

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 (81) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +9 -3
  2. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  3. package/fesm2022/{acorex-platform-common-common-settings.provider-Ytey9uhY.mjs → acorex-platform-common-common-settings.provider-DilV4dql.mjs} +16 -3
  4. package/fesm2022/acorex-platform-common-common-settings.provider-DilV4dql.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +3426 -2488
  6. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-contracts.mjs +1160 -9
  8. package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-core.mjs +826 -152
  10. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-domain-contracts.mjs +58 -0
  12. package/fesm2022/acorex-platform-domain-contracts.mjs.map +1 -0
  13. package/fesm2022/acorex-platform-domain.mjs +2 -50
  14. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-builder.mjs +98 -189
  16. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  17. package/fesm2022/{acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs → acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs} +17 -4
  18. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-layout-components.mjs +181 -46
  20. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-designer.mjs +7 -6
  22. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-layout-entity-contracts.mjs +1208 -0
  25. package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -0
  26. package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
  27. package/fesm2022/acorex-platform-layout-entity.mjs +1080 -889
  28. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  29. package/fesm2022/acorex-platform-layout-views.mjs +1150 -247
  30. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  31. package/fesm2022/acorex-platform-layout-widget-core.mjs +388 -207
  32. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  33. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
  34. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
  35. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs} +4 -4
  36. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs} +2 -2
  38. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs.map} +1 -1
  39. package/fesm2022/acorex-platform-layout-widgets.mjs +1541 -394
  40. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  41. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  42. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs → acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs} +2 -3
  43. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
  44. package/fesm2022/acorex-platform-themes-default.mjs +956 -115
  45. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  46. package/fesm2022/{acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs → acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs} +50 -3
  47. package/fesm2022/acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs.map +1 -0
  48. package/fesm2022/acorex-platform-themes-shared.mjs +104 -24
  49. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  50. package/fesm2022/acorex-platform-workflow.mjs +6 -8
  51. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  52. package/package.json +9 -5
  53. package/types/acorex-platform-auth.d.ts +3 -1
  54. package/types/acorex-platform-common.d.ts +655 -1268
  55. package/types/acorex-platform-contracts.d.ts +1791 -260
  56. package/types/acorex-platform-core.d.ts +2302 -2800
  57. package/types/acorex-platform-domain-contracts.d.ts +416 -0
  58. package/types/acorex-platform-domain.d.ts +4 -415
  59. package/types/acorex-platform-layout-builder.d.ts +11 -20
  60. package/types/acorex-platform-layout-components.d.ts +29 -5
  61. package/types/acorex-platform-layout-designer.d.ts +2 -1
  62. package/types/acorex-platform-layout-entity-contracts.d.ts +889 -0
  63. package/types/acorex-platform-layout-entity.d.ts +143 -275
  64. package/types/acorex-platform-layout-views.d.ts +147 -31
  65. package/types/acorex-platform-layout-widget-core.d.ts +74 -14
  66. package/types/acorex-platform-layout-widgets.d.ts +136 -38
  67. package/types/acorex-platform-runtime.d.ts +1 -1
  68. package/types/acorex-platform-themes-default.d.ts +227 -73
  69. package/types/acorex-platform-themes-shared.d.ts +4 -0
  70. package/types/acorex-platform-workflow.d.ts +5 -18
  71. package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
  72. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +0 -1
  73. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
  74. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
  75. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map +0 -1
  76. package/fesm2022/acorex-platform-native.mjs +0 -155
  77. package/fesm2022/acorex-platform-native.mjs.map +0 -1
  78. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
  79. package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +0 -1
  80. package/native/README.md +0 -4
  81. package/types/acorex-platform-native.d.ts +0 -28
@@ -1,7 +1,7 @@
1
1
  import * as i2 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, viewChild, afterNextRender, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, signal, computed, Injectable, input, output, ViewContainerRef, Directive, DestroyRef, ElementRef, untracked } from '@angular/core';
4
+ import { inject, viewChild, afterNextRender, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, DestroyRef, signal, untracked, computed, InjectionToken, Injectable, input, output, ViewContainerRef, Directive, ElementRef } from '@angular/core';
5
5
  import { AXCommonModule } from '@acorex/cdk/common';
6
6
  import * as i4 from '@acorex/components/breadcrumbs';
7
7
  import { AXBreadcrumbsModule } from '@acorex/components/breadcrumbs';
@@ -12,9 +12,9 @@ import { AXDecoratorModule } from '@acorex/components/decorators';
12
12
  import * as i5 from '@acorex/components/dropdown';
13
13
  import { AXDropdownModule } from '@acorex/components/dropdown';
14
14
  import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
15
- import { AXPStickyDirective, AXPCommonSettings, AXPHomePageService, AXPSettingsService, axpIsEntityDetailsViewRoute, axpNavigateAppPath, AXPEntityCommandScope, AXPUnsavedChangesConfirmService, AXPUnsavedChangesPopstateService, createUnsavedChangesCanDeactivateGuard } from '@acorex/platform/common';
15
+ import { AXPTabNavigationService, AXPStickyDirective, AXPCommonSettings, AXPHomePageService, AXPSettingsService, AXPTabPreviewService, AXPUnsavedChangesConfirmService, AXPBrowserTitleService, axpJoinTabTitleSegments, normalizeRouterUrl, AXP_HOME_TAB_KEY, axpResolveTabKey, axpIsEntityDetailsViewRoute, axpNavigateAppPath, AXPEntityCommandScope, AXPNotFoundError, AXP_NOT_FOUND_ROUTE, AXPUnsavedChangesPopstateService, AXP_ENTITY_DELETED_WORKFLOW_EVENT_TYPE, createUnsavedChangesCanDeactivateGuard } from '@acorex/platform/common';
16
16
  import * as i8 from '@acorex/platform/core';
17
- import { AXPDeviceService, AXPComponentSlotModule, getSmart, AXPExpressionEvaluatorService, AXPContextStore, normalizeKeyboardShortcuts, AXPBroadcastEventService, AXPKeyboardShortcutRegistry, AXPKeyboardShortcutPriority } from '@acorex/platform/core';
17
+ import { AXPDeviceService, AXPComponentSlotModule, getSmart, AXPDebugService, OVERLAY_DETAILS_VIEW_TRACE_NS, AXPExpressionEvaluatorService, AXPContextEvalFactory, normalizeKeyboardShortcuts, AXPContextStore, AXPBroadcastEventService, AXPKeyboardShortcutRegistry, FORM_DIRTY_TRACE_NS, summarizeFormContextDirtyDiff, AXPKeyboardShortcutPriority } from '@acorex/platform/core';
18
18
  import * as i1 from '@acorex/cdk/drawer';
19
19
  import { AXDrawerDirectiveModule, AXDrawerContainerDirective } from '@acorex/cdk/drawer';
20
20
  import { AXDrawerModule } from '@acorex/components/drawer';
@@ -28,25 +28,25 @@ import { AXPWorkflowService } from '@acorex/platform/workflow';
28
28
  import { AXToastService } from '@acorex/components/toast';
29
29
  import { AXFormatService, AXFormatModule } from '@acorex/core/format';
30
30
  import { AXPSessionService } from '@acorex/platform/auth';
31
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
32
+ import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
31
33
  import { isEmpty, cloneDeep, get } from 'lodash-es';
34
+ import { filter } from 'rxjs/operators';
32
35
  import { AXBasePageComponent } from '@acorex/components/page';
33
- import * as i7 from '@acorex/platform/layout/widget-core';
36
+ import * as i6$1 from '@acorex/platform/layout/widget-core';
34
37
  import { AXPPageStatus, AXPWidgetContainerComponent, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
35
- import { Router, ActivatedRoute } from '@angular/router';
36
38
  import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
37
39
  import { AXBadgeModule } from '@acorex/components/badge';
38
40
  import { AXButtonGroupModule } from '@acorex/components/button-group';
39
- import * as i5$1 from '@acorex/components/loading';
40
- import { AXLoadingModule } from '@acorex/components/loading';
41
41
  import { AXMenuModule } from '@acorex/components/menu';
42
42
  import { AXSearchBoxModule } from '@acorex/components/search-box';
43
43
  import { AXDateTimeModule } from '@acorex/core/date-time';
44
44
  import { AXFileModule } from '@acorex/core/file';
45
- import * as i8$1 from '@acorex/components/form';
45
+ import * as i7 from '@acorex/components/form';
46
46
  import { AXFormModule } from '@acorex/components/form';
47
- import * as i6$1 from '@acorex/components/tabs';
47
+ import * as i5$1 from '@acorex/components/tabs';
48
48
  import { AXTabsModule } from '@acorex/components/tabs';
49
- import { Subject, takeUntil } from 'rxjs';
49
+ import { Subject, takeUntil, filter as filter$1 } from 'rxjs';
50
50
 
51
51
  class AXPPageLayoutBase {
52
52
  }
@@ -56,6 +56,7 @@ class AXPPageLayoutComponent {
56
56
  this.page = inject(AXPPageLayoutBase, { optional: true });
57
57
  this.layoutService = inject(AXPLayoutThemeService);
58
58
  this.deviceService = inject(AXPDeviceService);
59
+ this.tabNavigation = inject(AXPTabNavigationService);
59
60
  this.startSideDrawer = viewChild('startSideDrawer', ...(ngDevMode ? [{ debugName: "startSideDrawer" }] : /* istanbul ignore next */ []));
60
61
  this.workflow = inject(AXPWorkflowService);
61
62
  this.commandService = inject(AXPCommandService);
@@ -145,7 +146,7 @@ class AXPPageLayoutComponent {
145
146
  });
146
147
  }
147
148
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPageLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
148
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPageLayoutComponent, isStandalone: true, selector: "axp-page-layout", providers: [], viewQueries: [{ propertyName: "startSideDrawer", first: true, predicate: ["startSideDrawer"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.AXDrawerContainerDirective }], ngImport: i0, template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\"\n class=\"ax-z-50 ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div\n id=\"axp-page-badge\"\n class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\"\n [attr.aria-label]=\"page?.badge()?.title\"\n >\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type:
149
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPageLayoutComponent, isStandalone: true, selector: "axp-page-layout", providers: [], viewQueries: [{ propertyName: "startSideDrawer", first: true, predicate: ["startSideDrawer"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.AXDrawerContainerDirective }], ngImport: i0, template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\" class=\"ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div id=\"axp-page-badge\" class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\" [attr.aria-label]=\"page?.badge()?.title\">\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type:
149
150
  //
150
151
  AXCommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.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: AXBreadcrumbsModule }, { kind: "component", type: i4.AXBreadCrumbsComponent, selector: "ax-breadcrumbs" }, { kind: "component", type: i4.AXBreadCrumbsItemComponent, selector: "ax-breadcrumbs-item", inputs: ["disabled", "active"] }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.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: "component", type: i6.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i6.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "ngmodule", type: AXDrawerDirectiveModule }, { kind: "directive", type: i1.AXDrawerItemDirective, selector: "[axDrawerItem]", inputs: ["location", "collapsed", "backDrop", "mode", "transition", "closeOnBackdropClick", "backdropClass", "singleOpenMode"], outputs: ["collapseStateChanged", "locationChange", "collapsedChange", "backDropChange", "modeChange", "transitionChange", "closeOnBackdropClickChange", "backdropClassChange", "onBackdropClick", "singleOpenModeChange"], exportAs: ["axDrawerItem"] }, { kind: "ngmodule", type:
151
152
  //
@@ -173,7 +174,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
173
174
  AXPStickyDirective,
174
175
  AXPThemeLayoutContainerComponent,
175
176
  AXPStatusChipComponent,
176
- ], selector: 'axp-page-layout', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [AXDrawerContainerDirective], providers: [], template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\"\n class=\"ax-z-50 ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div\n id=\"axp-page-badge\"\n class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\"\n [attr.aria-label]=\"page?.badge()?.title\"\n >\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"] }]
177
+ ], selector: 'axp-page-layout', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [AXDrawerContainerDirective], providers: [], template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\" class=\"ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div id=\"axp-page-badge\" class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\" [attr.aria-label]=\"page?.badge()?.title\">\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"] }]
177
178
  }], propDecorators: { startSideDrawer: [{ type: i0.ViewChild, args: ['startSideDrawer', { isSignal: true }] }] } });
178
179
 
179
180
  //#region ---- Page Unsaved Changes Utilities ----
@@ -219,11 +220,57 @@ class AXPPageLayoutBaseComponent {
219
220
  this.homePageService = inject(AXPHomePageService);
220
221
  this.policyService = inject(AXPPolicyEngineService);
221
222
  this.settingsService = inject(AXPSettingsService);
223
+ this.tabNavigation = inject(AXPTabNavigationService);
224
+ this.tabPreviewService = inject(AXPTabPreviewService);
225
+ this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
226
+ this.browserTitleService = inject(AXPBrowserTitleService);
227
+ this.router = inject(Router);
228
+ this.pageLayoutDestroyRef = inject(DestroyRef);
222
229
  //#endregion
223
230
  //#region ---------------- Signal to force recomputation ----------------
224
231
  this._updateTrigger = signal(0, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : /* istanbul ignore next */ []));
232
+ /** Tab key captured at page init — stable while the route instance is cached. */
233
+ this.pageTabKey = signal(null, ...(ngDevMode ? [{ debugName: "pageTabKey" }] : /* istanbul ignore next */ []));
225
234
  this.updateTrigger = this._updateTrigger.asReadonly();
226
235
  //#endregion
236
+ //#region ---------------- Tab Title Sync ----------------
237
+ /** Refreshes tab title when this cached page becomes the active tab again. */
238
+ this.#syncTabTitleOnActivate = effect(() => {
239
+ const activeKey = this.tabNavigation.activeKey();
240
+ const pageKey = this.pageTabKey();
241
+ if (!activeKey || !pageKey || activeKey !== pageKey) {
242
+ return;
243
+ }
244
+ if (this.tabNavigation.effectiveMode() !== 'tabular') {
245
+ return;
246
+ }
247
+ untracked(() => {
248
+ this.recompute();
249
+ });
250
+ }, ...(ngDevMode ? [{ debugName: "#syncTabTitleOnActivate" }] : /* istanbul ignore next */ []));
251
+ /** Publishes structured tab preview (hover card + dirty badge) for this cached page. */
252
+ this.#syncTabStructuredPreview = effect(() => {
253
+ this.updateTrigger();
254
+ const tabKey = this.pageTabKey();
255
+ const titleValue = this.title();
256
+ const descriptionValue = this.description();
257
+ const icon = this.titleIcon();
258
+ const breadcrumbItems = this.breadcrumbs();
259
+ if (!tabKey || this.tabNavigation.effectiveMode() !== 'tabular') {
260
+ return;
261
+ }
262
+ const isDirty = this.hasUnsavedChanges();
263
+ untracked(() => {
264
+ void this.publishTabStructuredPreview(tabKey, {
265
+ titleValue,
266
+ descriptionValue,
267
+ icon,
268
+ breadcrumbItems,
269
+ isDirty,
270
+ });
271
+ });
272
+ }, ...(ngDevMode ? [{ debugName: "#syncTabStructuredPreview" }] : /* istanbul ignore next */ []));
273
+ //#endregion
227
274
  //#region ---------------- Title ----------------
228
275
  this.title = signal('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
229
276
  this.titleIcon = signal(null, ...(ngDevMode ? [{ debugName: "titleIcon" }] : /* istanbul ignore next */ []));
@@ -232,6 +279,12 @@ class AXPPageLayoutBaseComponent {
232
279
  this.title.set(await this.getPageTitle());
233
280
  const icon = await this.getPageIcon();
234
281
  this.titleIcon.set(icon);
282
+ if (this.tabNavigation.effectiveMode() === 'tabular') {
283
+ const tabKey = this.pageTabKey();
284
+ if (tabKey && icon) {
285
+ this.tabNavigation.syncTabIcon(tabKey, icon);
286
+ }
287
+ }
235
288
  }, ...(ngDevMode ? [{ debugName: "#titleEffect" }] : /* istanbul ignore next */ []));
236
289
  this.hasTitle = computed(() => {
237
290
  const value = this.title();
@@ -247,6 +300,19 @@ class AXPPageLayoutBaseComponent {
247
300
  return false;
248
301
  }, ...(ngDevMode ? [{ debugName: "hasTitle" }] : /* istanbul ignore next */ []));
249
302
  this.hasTitleIcon = computed(() => this.titleIcon() !== null, ...(ngDevMode ? [{ debugName: "hasTitleIcon" }] : /* istanbul ignore next */ []));
303
+ this.#browserTitleEffect = effect(() => {
304
+ if (this.tabNavigation.effectiveMode() === 'tabular') {
305
+ return;
306
+ }
307
+ if (!this.isActivePageForBrowserTitle()) {
308
+ return;
309
+ }
310
+ this.updateTrigger();
311
+ this.title();
312
+ untracked(() => {
313
+ void this.publishBrowserTitleIfActive();
314
+ });
315
+ }, ...(ngDevMode ? [{ debugName: "#browserTitleEffect" }] : /* istanbul ignore next */ []));
250
316
  //#endregion
251
317
  //#region ---------------- Description ----------------
252
318
  this.description = signal(null, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
@@ -285,7 +351,19 @@ class AXPPageLayoutBaseComponent {
285
351
  this.#breadcrumbsEffect = effect(async () => {
286
352
  this.updateTrigger();
287
353
  const breadCrumbs = await this.getPageBreadcrumbs();
288
- this.breadcrumbs.set([...this.defaultBreadCrumbs, ...breadCrumbs]);
354
+ const trail = [...this.defaultBreadCrumbs, ...breadCrumbs];
355
+ this.breadcrumbs.set(trail);
356
+ if (this.tabNavigation.effectiveMode() === 'tabular') {
357
+ const tabKey = this.pageTabKey();
358
+ const tabTitleSegments = await this.resolveBreadcrumbTabTitleSegments(breadCrumbs);
359
+ let tabTitle = tabTitleSegments.length ? axpJoinTabTitleSegments(tabTitleSegments) : null;
360
+ if (!tabTitle) {
361
+ tabTitle = await this.resolvePageTitleForTab();
362
+ }
363
+ if (tabKey && tabTitle) {
364
+ this.tabNavigation.syncTabTitle(tabKey, tabTitleSegments.length ? tabTitleSegments : tabTitle);
365
+ }
366
+ }
289
367
  }, ...(ngDevMode ? [{ debugName: "#breadcrumbsEffect" }] : /* istanbul ignore next */ []));
290
368
  this.hasBreadcrumbs = computed(() => this.breadcrumbs().length > 1, ...(ngDevMode ? [{ debugName: "hasBreadcrumbs" }] : /* istanbul ignore next */ []));
291
369
  //#endregion
@@ -343,9 +421,83 @@ class AXPPageLayoutBaseComponent {
343
421
  //#endregion
344
422
  //#region ---------------- Lifecycle hooks ----------------
345
423
  async ngOnInit() {
424
+ this.pageTabKey.set(this.resolvePageTabKey());
346
425
  this.translateService.langChanges$.subscribe(() => {
347
426
  this.recompute();
348
427
  });
428
+ this.router.events
429
+ .pipe(filter((event) => event instanceof NavigationEnd), takeUntilDestroyed(this.pageLayoutDestroyRef))
430
+ .subscribe(() => {
431
+ void this.publishBrowserTitleIfActive();
432
+ });
433
+ }
434
+ /** Maps the home-page route to the pinned home tab key instead of a path-based key. */
435
+ resolvePageTabKey() {
436
+ const homePath = this.homePageService.getCurrent().path;
437
+ if (homePath && normalizeRouterUrl(homePath) === normalizeRouterUrl(this.router.url)) {
438
+ return AXP_HOME_TAB_KEY;
439
+ }
440
+ return axpResolveTabKey(this.router);
441
+ }
442
+ /** Stable tab key for this cached page instance (tabular mode). */
443
+ getPageTabKey() {
444
+ return this.pageTabKey();
445
+ }
446
+ //#endregion
447
+ //#region ---------------- Tab Title Sync ----------------
448
+ /** Refreshes tab title when this cached page becomes the active tab again. */
449
+ #syncTabTitleOnActivate;
450
+ /** Publishes structured tab preview (hover card + dirty badge) for this cached page. */
451
+ #syncTabStructuredPreview;
452
+ async publishTabStructuredPreview(tabKey, input) {
453
+ const tab = this.tabNavigation.tabList().find((item) => item.key === tabKey);
454
+ const breadcrumbTrail = [];
455
+ for (const item of input.breadcrumbItems.slice(1)) {
456
+ const segment = await this.resolveBreadcrumbItemTitle(item);
457
+ if (segment && segment !== breadcrumbTrail[breadcrumbTrail.length - 1]) {
458
+ breadcrumbTrail.push(segment);
459
+ }
460
+ }
461
+ const fallbackTitle = await this.translateTextIfKey(breadcrumbTrail.join(' - ') || tab?.title || '');
462
+ const title = await this.resolveMultiLanguageText(input.titleValue, fallbackTitle);
463
+ const subtitle = await this.resolveMultiLanguageText(input.descriptionValue, '');
464
+ this.tabPreviewService.setPreview(tabKey, {
465
+ title,
466
+ subtitle: subtitle || undefined,
467
+ url: tab?.url ?? '',
468
+ icon: input.icon ?? tab?.icon,
469
+ isDirty: input.isDirty,
470
+ breadcrumbTrail,
471
+ });
472
+ }
473
+ async resolveMultiLanguageText(value, fallback) {
474
+ const resolvedFallback = await this.translateTextIfKey(fallback);
475
+ if (value == null || value === '') {
476
+ return resolvedFallback;
477
+ }
478
+ if (typeof value === 'string') {
479
+ const trimmed = value.trim();
480
+ if (!trimmed) {
481
+ return resolvedFallback;
482
+ }
483
+ if (trimmed.startsWith('@')) {
484
+ return (await this.translateService.translateAsync(trimmed)) || resolvedFallback;
485
+ }
486
+ return trimmed;
487
+ }
488
+ const resolved = this.translateService.resolve(value);
489
+ return resolved || resolvedFallback;
490
+ }
491
+ /** Resolves i18n keys (`@scope:key`); returns plain text unchanged. */
492
+ async translateTextIfKey(text) {
493
+ const trimmed = text.trim();
494
+ if (!trimmed) {
495
+ return '';
496
+ }
497
+ if (trimmed.startsWith('@')) {
498
+ return (await this.translateService.translateAsync(trimmed)) || trimmed;
499
+ }
500
+ return trimmed;
349
501
  }
350
502
  #titleEffect;
351
503
  getPageTitle() {
@@ -354,6 +506,33 @@ class AXPPageLayoutBaseComponent {
354
506
  getPageIcon() {
355
507
  return null;
356
508
  }
509
+ #browserTitleEffect;
510
+ /** Publishes the page title to the browser tab when this instance is the active route. */
511
+ async publishBrowserTitleIfActive() {
512
+ if (this.tabNavigation.effectiveMode() === 'tabular') {
513
+ return;
514
+ }
515
+ if (!this.isActivePageForBrowserTitle()) {
516
+ return;
517
+ }
518
+ const routeKey = this.pageTabKey();
519
+ if (!routeKey) {
520
+ return;
521
+ }
522
+ const pageTitle = await this.resolvePageTitleForTab();
523
+ if (!this.isActivePageForBrowserTitle()) {
524
+ return;
525
+ }
526
+ this.browserTitleService.setSimpleModePageTitle(pageTitle, routeKey);
527
+ }
528
+ /** True when this cached page instance matches the current router location. */
529
+ isActivePageForBrowserTitle() {
530
+ const pageKey = this.pageTabKey();
531
+ if (!pageKey) {
532
+ return false;
533
+ }
534
+ return pageKey === axpResolveTabKey(this.router);
535
+ }
357
536
  #descriptionEffect;
358
537
  getPageDescription() {
359
538
  return null;
@@ -362,10 +541,83 @@ class AXPPageLayoutBaseComponent {
362
541
  getPageBreadcrumbs() {
363
542
  return [];
364
543
  }
544
+ /** Collects resolved breadcrumb labels (Home excluded upstream) for tab chrome. */
545
+ async resolveBreadcrumbTabTitleSegments(pageBreadcrumbs) {
546
+ const segments = [];
547
+ for (const item of pageBreadcrumbs) {
548
+ const title = await this.resolveBreadcrumbItemTitle(item);
549
+ if (title && title !== segments[segments.length - 1]) {
550
+ segments.push(title);
551
+ }
552
+ }
553
+ return segments;
554
+ }
555
+ /** Joins breadcrumb segments as the stored tab title string. */
556
+ async resolveBreadcrumbTabTitle(pageBreadcrumbs) {
557
+ const segments = await this.resolveBreadcrumbTabTitleSegments(pageBreadcrumbs);
558
+ if (!segments.length) {
559
+ return null;
560
+ }
561
+ return axpJoinTabTitleSegments(segments);
562
+ }
563
+ /** Resolves a breadcrumb label the same way as page chrome (`t(item.title)`). */
564
+ async resolveBreadcrumbItemTitle(item) {
565
+ const raw = item?.title;
566
+ if (raw == null || raw === '') {
567
+ return null;
568
+ }
569
+ if (typeof raw === 'string') {
570
+ const trimmed = raw.trim();
571
+ if (!trimmed) {
572
+ return null;
573
+ }
574
+ if (trimmed.startsWith('@')) {
575
+ return (await this.translateService.translateAsync(trimmed)) || trimmed;
576
+ }
577
+ return trimmed;
578
+ }
579
+ if (typeof raw === 'object' && !Array.isArray(raw)) {
580
+ if (this.translateService.isValidMultiLanguageObject(raw)) {
581
+ const resolved = this.translateService.resolve(raw);
582
+ return resolved || null;
583
+ }
584
+ const resolved = this.translateService.resolve(raw);
585
+ return resolved || null;
586
+ }
587
+ return String(raw);
588
+ }
589
+ /** Fallback tab label from the page title when breadcrumbs are not ready yet. */
590
+ async resolvePageTitleForTab() {
591
+ const raw = await Promise.resolve(this.getPageTitle());
592
+ if (raw == null || raw === '') {
593
+ return null;
594
+ }
595
+ if (typeof raw === 'string') {
596
+ const trimmed = raw.trim();
597
+ if (trimmed.startsWith('@')) {
598
+ return (await this.translateService.translateAsync(trimmed)) || trimmed;
599
+ }
600
+ return trimmed;
601
+ }
602
+ if (typeof raw === 'object' && !Array.isArray(raw)) {
603
+ const resolved = this.translateService.resolve(raw);
604
+ return resolved || null;
605
+ }
606
+ return null;
607
+ }
365
608
  #badgeEffect;
366
609
  hasUnsavedChanges() {
367
610
  return false;
368
611
  }
612
+ /**
613
+ * Confirms closing this page as a background tab (no router navigation).
614
+ * Override when dirty detection differs from {@link hasUnsavedChanges}.
615
+ */
616
+ onBeforeTabClose() {
617
+ return this.unsavedChangesConfirm.confirmIfDirty(this.hasUnsavedChanges(), {
618
+ approveLeaveOnConfirm: false,
619
+ });
620
+ }
369
621
  async getPageBadge() {
370
622
  if (!this.hasUnsavedChanges()) {
371
623
  return null;
@@ -586,6 +838,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
586
838
  }]
587
839
  }], propDecorators: { layout: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPopupLayoutComponent), { isSignal: true }] }] } });
588
840
 
841
+ const AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER = new InjectionToken('AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER');
842
+ //#endregion
843
+
844
+ /** Trace namespace for details-view page / URL sync diagnostics. */
845
+ const DETAILS_VIEW_PAGE_TRACE_NS = 'details-view-page';
846
+
589
847
  //#region ---- Root-context widget expression resolution ----
590
848
  /**
591
849
  * Evaluates `{{ ... }}` strings inside `options.customFilterDefinitions` using `rootContext`
@@ -625,10 +883,11 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
625
883
  const state = {
626
884
  adapter: null,
627
885
  rootContext: {},
886
+ savedContext: {},
628
887
  previousContext: {},
629
888
  context: {},
630
889
  scope: null,
631
- status: AXPPageStatus.Processing,
890
+ status: AXPPageStatus.Idle,
632
891
  currentPage: null,
633
892
  currentTab: null,
634
893
  pageSelectedRows: [],
@@ -653,6 +912,10 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
653
912
  //
654
913
  isBusy: computed(() => store.status() == AXPPageStatus.Processing),
655
914
  isSaving: computed(() => store.status() == AXPPageStatus.Submitting),
915
+ isOverlayBusy: computed(() => store.status() === AXPPageStatus.Processing || store.status() === AXPPageStatus.Submitting),
916
+ isPageReady: computed(() => store.adapter() != null &&
917
+ store.currentPage() != null &&
918
+ store.status() === AXPPageStatus.Rendered),
656
919
  isDirty: computed(() => {
657
920
  if (store.currentPage()?.isReadonly) {
658
921
  return false;
@@ -676,64 +939,150 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
676
939
  const evaluatedByTab = store.evaluatedTabContentsById();
677
940
  return evaluatedByTab[tab.id] ?? [];
678
941
  }),
679
- })), withMethods((store, evaluatorService = inject(AXPExpressionEvaluatorService), router = inject(Router), route = inject(ActivatedRoute), deviceService = inject(AXPDeviceService), formatService = inject(AXFormatService), toastService = inject(AXToastService), translateService = inject(AXTranslationService), settingsService = inject(AXPSettingsService)) => {
680
- /** Monotonic counter so stale async page loads cannot overwrite newer results. */
681
- let pageLoadGeneration = 0;
682
- const resolveTargetPage = (adapter, pageId) => {
683
- const queryParams = router.routerState.snapshot.root.queryParams;
684
- const targetPageId = pageId || queryParams['page'];
685
- if (targetPageId) {
686
- return adapter.pages.find((p) => p.id === targetPageId) ?? null;
942
+ })), withMethods((store, evaluatorService = inject(AXPExpressionEvaluatorService), contextEvalFactory = inject(AXPContextEvalFactory), router = inject(Router), route = inject(ActivatedRoute), deviceService = inject(AXPDeviceService), formatService = inject(AXFormatService), toastService = inject(AXToastService), translateService = inject(AXTranslationService), settingsService = inject(AXPSettingsService), layout = inject(AXPLayoutThemeService), adapterLoader = inject(AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER)) => {
943
+ const resolvePageFromId = (adapter, pageId) => {
944
+ if (pageId) {
945
+ return adapter.pages.find((p) => p.id === pageId) ?? null;
687
946
  }
688
947
  if (deviceService.isLarge() || adapter.pages.length === 1) {
689
- return adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0];
948
+ return adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0] ?? null;
690
949
  }
691
950
  return null;
692
951
  };
693
- const executeLoadPage = async (pageId, forceRefresh) => {
952
+ /** Serializes page activation so route sync and UI cannot run overlapping loads. */
953
+ let pageActivationChain = Promise.resolve();
954
+ /** Serializes route-driven adapter loads (initial navigation and layout refresh). */
955
+ let routeLoadChain = Promise.resolve();
956
+ /** `page` query param from the browser URL (reliable on hard refresh). */
957
+ const readPageQueryParam = () => {
958
+ const page = router.parseUrl(router.url).queryParams['page'];
959
+ return typeof page === 'string' && page.length > 0 ? page : null;
960
+ };
961
+ /** Snapshot of all page-query sources for trace logs. */
962
+ const pageQueryTraceContext = (extra = {}) => ({
963
+ routerUrl: router.url,
964
+ pageFromRouterUrl: readPageQueryParam(),
965
+ pageFromRouteSnapshot: route.snapshot.queryParamMap.get('page'),
966
+ pageFromRootSnapshot: router.routerState.snapshot.root.queryParams['page'] ?? null,
967
+ currentPageId: store.currentPage()?.id ?? null,
968
+ adapterPageIds: store.adapter()?.pages.map((p) => p.id) ?? [],
969
+ ...extra,
970
+ });
971
+ /** Loads page data, context, and evaluated widgets for the target sidebar page. */
972
+ const activatePageById = async (pageId, forceRefresh) => {
973
+ const activation = pageActivationChain.then(() => runPageActivation(pageId, forceRefresh));
974
+ pageActivationChain = activation.catch(() => undefined);
975
+ await activation;
976
+ };
977
+ const runPageActivation = async (pageId, forceRefresh) => {
694
978
  const adapter = store.adapter();
695
979
  if (!adapter) {
696
- throw new Error('Adapter must be loaded before loading page');
980
+ return;
981
+ }
982
+ const targetPageId = pageId ?? readPageQueryParam() ?? undefined;
983
+ const currentPage = resolvePageFromId(adapter, targetPageId);
984
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'runPageActivation', () => pageQueryTraceContext({
985
+ passedPageId: pageId ?? null,
986
+ targetPageId: targetPageId ?? null,
987
+ resolvedPageId: currentPage?.id ?? null,
988
+ forceRefresh: forceRefresh ?? false,
989
+ vmStatus: store.status(),
990
+ }));
991
+ if (!forceRefresh && currentPage?.id === store.currentPage()?.id && store.status() === AXPPageStatus.Rendered) {
992
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'runPageActivation skipped (already rendered)', () => pageQueryTraceContext({
993
+ resolvedPageId: currentPage?.id ?? null,
994
+ }));
995
+ return;
996
+ }
997
+ const previousPageId = store.currentPage()?.id;
998
+ const isSidebarSwitch = previousPageId != null && previousPageId !== currentPage?.id;
999
+ if (isSidebarSwitch) {
1000
+ layout.setNavigationLoading(true);
1001
+ }
1002
+ const overlayAlreadyOn = layout.overlayTaskCount() > 0;
1003
+ if (!overlayAlreadyOn) {
1004
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'activatePage overlay ON', () => ({
1005
+ pageId: currentPage?.id,
1006
+ forceRefresh,
1007
+ isSidebarSwitch,
1008
+ }));
1009
+ layout.setOverlayLoading(true);
1010
+ }
1011
+ else {
1012
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'activatePage skipped overlay ON (task count > 0)', () => ({
1013
+ pageId: currentPage?.id,
1014
+ forceRefresh,
1015
+ isSidebarSwitch,
1016
+ taskCount: layout.overlayTaskCount(),
1017
+ }));
697
1018
  }
698
- const generation = ++pageLoadGeneration;
699
1019
  patchState(store, {
700
1020
  status: AXPPageStatus.Processing,
701
1021
  });
702
- const currentPage = resolveTargetPage(adapter, pageId);
703
- let context = {};
704
- if (currentPage) {
705
- const currentPageIndex = adapter.pages.findIndex((p) => p.id === currentPage.id);
706
- const loadResult = await adapter.pages[currentPageIndex]?.load?.({ forceRefresh });
707
- if (generation !== pageLoadGeneration) {
708
- return;
1022
+ try {
1023
+ let context = {};
1024
+ if (currentPage) {
1025
+ const currentPageIndex = adapter.pages.findIndex((p) => p.id === currentPage.id);
1026
+ const pageLoad = adapter.pages[currentPageIndex]?.load;
1027
+ if (typeof pageLoad === 'function') {
1028
+ const loadResult = await pageLoad({ forceRefresh });
1029
+ context = loadResult?.data ?? {};
1030
+ }
1031
+ else {
1032
+ // Component/list sidebar pages have no `load`; keep entity root context so widget
1033
+ // state is not cleared (Change History, etc. use `rootContext` instead).
1034
+ context = cloneDeep(store.rootContext());
1035
+ }
1036
+ }
1037
+ const currentTab = currentPage?.tabs?.[0] ?? null;
1038
+ const shouldSyncRootContext = forceRefresh === true && currentPage?.isPrimary === true && !isEmpty(context);
1039
+ const rootCtx = shouldSyncRootContext
1040
+ ? context
1041
+ : store.rootContext();
1042
+ const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(currentPage, rootCtx, evaluatorService);
1043
+ patchState(store, {
1044
+ previousContext: cloneDeep(context),
1045
+ context: cloneDeep(context),
1046
+ savedContext: cloneDeep(context),
1047
+ ...(shouldSyncRootContext ? { rootContext: cloneDeep(context) } : {}),
1048
+ status: AXPPageStatus.Rendered,
1049
+ currentPage,
1050
+ currentTab,
1051
+ evaluatedPageContent,
1052
+ evaluatedTabContentsById,
1053
+ formDirty: false,
1054
+ });
1055
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'activatePage VM ready (Rendered)', () => ({
1056
+ pageId: currentPage?.id,
1057
+ forceRefresh,
1058
+ }));
1059
+ const urlPageParam = readPageQueryParam();
1060
+ if (currentPage && axpIsEntityDetailsViewRoute(router)) {
1061
+ if (!urlPageParam) {
1062
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'URL sync — add missing ?page=', () => pageQueryTraceContext({
1063
+ navigateToPageId: currentPage.id,
1064
+ }));
1065
+ router.navigate([], {
1066
+ relativeTo: route,
1067
+ queryParams: { page: currentPage.id },
1068
+ queryParamsHandling: 'merge',
1069
+ replaceUrl: true,
1070
+ });
1071
+ }
1072
+ else {
1073
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'URL sync — skipped (page already in URL)', () => pageQueryTraceContext({
1074
+ urlPageParam,
1075
+ resolvedPageId: currentPage.id,
1076
+ }));
1077
+ }
709
1078
  }
710
- context = loadResult?.data ?? {};
711
- }
712
- const currentTab = currentPage?.tabs?.[0] ?? null;
713
- const rootCtx = store.rootContext();
714
- const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(currentPage, rootCtx, evaluatorService);
715
- if (generation !== pageLoadGeneration) {
716
- return;
717
1079
  }
718
- patchState(store, {
719
- previousContext: cloneDeep(context),
720
- context: cloneDeep(context),
721
- status: AXPPageStatus.Rendered,
722
- currentPage,
723
- currentTab,
724
- evaluatedPageContent,
725
- evaluatedTabContentsById,
726
- formDirty: false,
727
- });
728
- if (currentPage && axpIsEntityDetailsViewRoute(router)) {
729
- const pageParam = route.snapshot.queryParamMap.get('page');
730
- if (pageParam !== currentPage.id) {
731
- router.navigate([], {
732
- relativeTo: route,
733
- queryParams: { page: currentPage.id },
734
- queryParamsHandling: 'merge',
735
- replaceUrl: true,
736
- });
1080
+ finally {
1081
+ if (isSidebarSwitch) {
1082
+ layout.setNavigationLoading(false);
1083
+ }
1084
+ if (store.status() === AXPPageStatus.Processing) {
1085
+ patchState(store, { status: AXPPageStatus.Rendered });
737
1086
  }
738
1087
  }
739
1088
  };
@@ -747,16 +1096,33 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
747
1096
  if (!adapter) {
748
1097
  return;
749
1098
  }
750
- const targetPage = resolveTargetPage(adapter, params['page']);
751
- const loadedPageId = store.currentPage()?.id;
752
- const isRendered = store.status() === AXPPageStatus.Rendered;
753
- if (targetPage?.id === loadedPageId && isRendered) {
1099
+ // `load()` `loadPage()` owns the first activation while `currentPage` is still null.
1100
+ if (store.currentPage() == null) {
1101
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (currentPage null)', () => pageQueryTraceContext({
1102
+ paramsPage: params['page'] ?? null,
1103
+ }));
1104
+ return;
1105
+ }
1106
+ const pageId = params['page'];
1107
+ if (!pageId) {
1108
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (no page param)', () => pageQueryTraceContext({
1109
+ params,
1110
+ }));
754
1111
  return;
755
1112
  }
756
- if (loadedPageId == null && targetPage == null) {
1113
+ const targetPage = adapter.pages.find((p) => p.id === pageId);
1114
+ if (!targetPage || store.currentPage()?.id === targetPage.id) {
1115
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (same or unknown page)', () => pageQueryTraceContext({
1116
+ paramsPage: pageId,
1117
+ targetPageFound: !!targetPage,
1118
+ }));
757
1119
  return;
758
1120
  }
759
- void executeLoadPage(targetPage?.id);
1121
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — activatePageById', () => pageQueryTraceContext({
1122
+ paramsPage: pageId,
1123
+ activatePageId: targetPage.id,
1124
+ }));
1125
+ void activatePageById(targetPage.id);
760
1126
  });
761
1127
  onCleanup(() => subscription.unsubscribe());
762
1128
  });
@@ -817,7 +1183,12 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
817
1183
  evaluated = await evaluatorService.evaluate(raw, evalScope);
818
1184
  }
819
1185
  else if (typeof sourceAfterPreLocale === 'string') {
820
- evaluated = await formatService.format(sourceAfterPreLocale, 'string', formatContext);
1186
+ if (sourceAfterPreLocale.trim().startsWith('@')) {
1187
+ evaluated = await translateService.translateAsync(sourceAfterPreLocale);
1188
+ }
1189
+ else {
1190
+ evaluated = await formatService.format(sourceAfterPreLocale, 'string', formatContext);
1191
+ }
821
1192
  }
822
1193
  else {
823
1194
  evaluated = await formatService.format(raw, 'string', formatContext);
@@ -851,15 +1222,12 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
851
1222
  });
852
1223
  },
853
1224
  async loadPage(pageId, forceRefresh) {
854
- await executeLoadPage(pageId, forceRefresh);
1225
+ await activatePageById(pageId, forceRefresh);
855
1226
  },
856
- async load(adapter) {
857
- // Setup expression evaluator scope
1227
+ async load(adapter, forceRefresh, pageIdFromUrl) {
858
1228
  const scope = {
859
1229
  context: {
860
- eval: (path) => {
861
- return getSmart(store.context(), path);
862
- },
1230
+ ...contextEvalFactory.createLiveScope(() => store.context()),
863
1231
  isDirty: () => store.isDirty(),
864
1232
  },
865
1233
  };
@@ -868,7 +1236,81 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
868
1236
  });
869
1237
  //
870
1238
  await this.loadAdapter(adapter);
871
- await this.loadPage(undefined, true);
1239
+ const pageId = pageIdFromUrl ?? readPageQueryParam() ?? undefined;
1240
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'load — activate page', () => pageQueryTraceContext({
1241
+ pageIdFromUrl: pageIdFromUrl ?? null,
1242
+ resolvedPageId: pageId ?? null,
1243
+ forceRefresh: forceRefresh ?? false,
1244
+ }));
1245
+ await this.loadPage(pageId, forceRefresh);
1246
+ },
1247
+ async loadFromRoute(forceRefresh) {
1248
+ const run = async () => {
1249
+ const pageIdFromUrl = readPageQueryParam() ?? undefined;
1250
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'loadFromRoute start', () => pageQueryTraceContext({
1251
+ pageIdFromUrl: pageIdFromUrl ?? null,
1252
+ forceRefresh: forceRefresh ?? false,
1253
+ }));
1254
+ const moduleName = route.parent?.snapshot.paramMap.get('module');
1255
+ const entityName = route.snapshot.paramMap.get('entity');
1256
+ const id = route.snapshot.paramMap.get('id');
1257
+ if (!moduleName || !entityName || !id) {
1258
+ return;
1259
+ }
1260
+ layout.setNavigationLoading(true);
1261
+ if (layout.overlayTaskCount() === 0) {
1262
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'loadFromRoute overlay ON', () => ({
1263
+ moduleName,
1264
+ entityName,
1265
+ id,
1266
+ forceRefresh,
1267
+ }));
1268
+ layout.setOverlayLoading(true);
1269
+ }
1270
+ else {
1271
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'loadFromRoute skipped overlay ON (task count > 0)', () => ({
1272
+ moduleName,
1273
+ entityName,
1274
+ id,
1275
+ forceRefresh,
1276
+ taskCount: layout.overlayTaskCount(),
1277
+ }));
1278
+ }
1279
+ try {
1280
+ if (forceRefresh) {
1281
+ patchState(store, {
1282
+ currentPage: null,
1283
+ status: AXPPageStatus.Idle,
1284
+ });
1285
+ }
1286
+ const adapter = await adapterLoader.load({ moduleName, entityName, id });
1287
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'adapter loaded (overlay still ON — details-view releases)', () => ({
1288
+ moduleName,
1289
+ entityName,
1290
+ id,
1291
+ }));
1292
+ await this.load(adapter, forceRefresh, pageIdFromUrl);
1293
+ }
1294
+ catch (error) {
1295
+ AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'loadFromRoute overlay OFF (error)', () => ({
1296
+ moduleName,
1297
+ entityName,
1298
+ id,
1299
+ }));
1300
+ layout.setOverlayLoading(false);
1301
+ if (error instanceof AXPNotFoundError) {
1302
+ void router.navigateByUrl(AXP_NOT_FOUND_ROUTE);
1303
+ return;
1304
+ }
1305
+ throw error;
1306
+ }
1307
+ finally {
1308
+ layout.setNavigationLoading(false);
1309
+ }
1310
+ };
1311
+ const load = routeLoadChain.then(run);
1312
+ routeLoadChain = load.catch(() => undefined);
1313
+ await load;
872
1314
  },
873
1315
  updateContext(context) {
874
1316
  patchState(store, {
@@ -937,13 +1379,23 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
937
1379
  },
938
1380
  setCurrentPage(page) {
939
1381
  const previousPage = store.currentPage();
1382
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage', () => pageQueryTraceContext({
1383
+ requestedPageId: page?.id ?? null,
1384
+ previousPageId: previousPage?.id ?? null,
1385
+ }));
940
1386
  if (page) {
941
- const pageParam = route.snapshot.queryParamMap.get('page');
942
- const isSamePage = previousPage?.id === page.id && pageParam === page.id;
943
- if (isSamePage) {
1387
+ if (!previousPage) {
1388
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage ignored (initial load in progress)', () => pageQueryTraceContext({
1389
+ requestedPageId: page.id,
1390
+ }));
944
1391
  return;
945
1392
  }
946
- if (axpIsEntityDetailsViewRoute(router)) {
1393
+ const pageParam = readPageQueryParam();
1394
+ const isSamePage = previousPage?.id === page.id && pageParam === page.id;
1395
+ if (!isSamePage && axpIsEntityDetailsViewRoute(router)) {
1396
+ AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage — navigate', () => pageQueryTraceContext({
1397
+ navigateToPageId: page.id,
1398
+ }));
947
1399
  const queryParams = { page: page.id };
948
1400
  if (previousPage?.id && previousPage.id !== page.id) {
949
1401
  queryParams['filters'] = null;
@@ -955,17 +1407,16 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
955
1407
  // Push history for desktop sidebar switches and mobile page-list picks.
956
1408
  replaceUrl: false,
957
1409
  });
1410
+ return;
958
1411
  }
959
- void executeLoadPage(page.id);
1412
+ void activatePageById(page.id);
960
1413
  }
961
1414
  else {
962
- pageLoadGeneration += 1;
963
1415
  patchState(store, {
964
1416
  currentPage: null,
965
1417
  currentTab: null,
966
1418
  evaluatedPageContent: [],
967
1419
  evaluatedTabContentsById: {},
968
- status: AXPPageStatus.Rendered,
969
1420
  });
970
1421
  if (axpIsEntityDetailsViewRoute(router)) {
971
1422
  const currentParams = { ...route.snapshot.queryParams };
@@ -1087,12 +1538,16 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
1087
1538
  const snapshot = cloneDeep(context);
1088
1539
  patchState(store, {
1089
1540
  context: snapshot,
1541
+ savedContext: snapshot,
1090
1542
  previousContext: snapshot,
1091
1543
  formDirty: false,
1092
1544
  });
1093
1545
  },
1094
1546
  async discard() {
1547
+ const saved = cloneDeep(store.savedContext());
1095
1548
  patchState(store, {
1549
+ context: saved,
1550
+ previousContext: saved,
1096
1551
  formDirty: false,
1097
1552
  });
1098
1553
  },
@@ -1107,10 +1562,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
1107
1562
  });
1108
1563
  try {
1109
1564
  const result = await store.currentPage()?.execute?.(command, payload);
1110
- // Clear submitting before post-save refresh so the footer is not left disabled.
1111
- patchState(store, {
1112
- status: AXPPageStatus.Rendered,
1113
- });
1114
1565
  const enableOperationToasts = await settingsService.get(AXPCommonSettings.EnableOperationToasts);
1115
1566
  if (result?.success) {
1116
1567
  try {
@@ -1121,6 +1572,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
1121
1572
  }
1122
1573
  patchState(store, {
1123
1574
  previousContext: store.context(),
1575
+ savedContext: cloneDeep(store.context()),
1124
1576
  formDirty: false,
1125
1577
  });
1126
1578
  if (enableOperationToasts) {
@@ -1134,9 +1586,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
1134
1586
  timeOutProgress: true,
1135
1587
  });
1136
1588
  }
1137
- patchState(store, {
1138
- formDirty: false,
1139
- });
1140
1589
  return true;
1141
1590
  }
1142
1591
  const rawText = result?.message?.text;
@@ -1162,9 +1611,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
1162
1611
  const errorText = error instanceof Error
1163
1612
  ? error.message
1164
1613
  : await translateService.translateAsync('@general:messages.generic.error.description');
1165
- patchState(store, {
1166
- status: AXPPageStatus.Rendered,
1167
- });
1168
1614
  toastService.show({
1169
1615
  color: 'danger',
1170
1616
  title: await translateService.translateAsync('@general:messages.generic.error.title'),
@@ -1177,22 +1623,109 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
1177
1623
  return false;
1178
1624
  }
1179
1625
  finally {
1180
- if (store.status() === AXPPageStatus.Submitting) {
1181
- patchState(store, {
1182
- status: AXPPageStatus.Rendered,
1183
- });
1184
- }
1626
+ patchState(store, {
1627
+ status: AXPPageStatus.Rendered,
1628
+ });
1185
1629
  }
1186
1630
  },
1187
- goToListPage() {
1631
+ async goToListPage() {
1188
1632
  const exitUrl = store.adapter()?.exitUrl;
1189
1633
  if (exitUrl) {
1190
- void axpNavigateAppPath(router, exitUrl);
1634
+ await axpNavigateAppPath(router, exitUrl);
1191
1635
  }
1192
1636
  },
1193
1637
  };
1194
1638
  }));
1195
1639
 
1640
+ //#region ---- Details View Action Shortcut Utilities ----
1641
+ /** Platform defaults for known entity detail commands when `shortcuts` is omitted on the action. */
1642
+ const DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS = {
1643
+ 'delete-entity': ['ctrl+shift+delete'],
1644
+ };
1645
+ const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
1646
+ 'update-entity': ['ctrl+s'],
1647
+ discard: ['escape'],
1648
+ };
1649
+ const SAVE_FOOTER_COMMAND_SUFFIX = ':Save';
1650
+ const DISCARD_FOOTER_COMMAND_SUFFIX = ':Discard';
1651
+ /**
1652
+ * Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
1653
+ */
1654
+ function getDetailsViewActionCommandBaseName(commandName) {
1655
+ if (!commandName) {
1656
+ return '';
1657
+ }
1658
+ return commandName.split('&')[0];
1659
+ }
1660
+ /**
1661
+ * Resolves keyboard shortcuts for a header entity action.
1662
+ * Explicit `shortcuts` wins; pass `[]` to disable. Otherwise known commands use platform defaults.
1663
+ */
1664
+ function resolveDetailsViewActionShortcuts(commandBaseName, explicit) {
1665
+ if (explicit !== undefined) {
1666
+ const chords = flattenDetailsViewActionShortcuts(explicit);
1667
+ return chords.length ? chords : undefined;
1668
+ }
1669
+ const defaults = DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS[commandBaseName];
1670
+ return defaults?.length ? [...defaults] : undefined;
1671
+ }
1672
+ /**
1673
+ * Resolves save/discard footer command shortcuts from page settings.
1674
+ */
1675
+ function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
1676
+ if (explicit !== undefined) {
1677
+ const chords = flattenDetailsViewActionShortcuts(explicit);
1678
+ return chords.length ? chords : undefined;
1679
+ }
1680
+ const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
1681
+ if (defaults?.length) {
1682
+ return [...defaults];
1683
+ }
1684
+ return resolvePageFooterActionDefaultShortcuts(commandName);
1685
+ }
1686
+ /**
1687
+ * Platform defaults for component-page footer save/discard commands (e.g. `MetaDataBuilder:Save`).
1688
+ */
1689
+ function resolvePageFooterActionDefaultShortcuts(commandName) {
1690
+ if (isSaveFooterCommand(commandName)) {
1691
+ return [...DEFAULT_FOOTER_COMMAND_SHORTCUTS['update-entity']];
1692
+ }
1693
+ if (isDiscardFooterCommand(commandName)) {
1694
+ return [...DEFAULT_FOOTER_COMMAND_SHORTCUTS['discard']];
1695
+ }
1696
+ return undefined;
1697
+ }
1698
+ function isSaveFooterCommand(commandName) {
1699
+ return commandName === 'update-entity' || commandName.endsWith(SAVE_FOOTER_COMMAND_SUFFIX);
1700
+ }
1701
+ function isDiscardFooterCommand(commandName) {
1702
+ return commandName === 'discard' || commandName.endsWith(DISCARD_FOOTER_COMMAND_SUFFIX);
1703
+ }
1704
+ /**
1705
+ * Resolves keyboard shortcuts for a footer action on entity detail sub-pages.
1706
+ */
1707
+ function resolvePageFooterActionShortcuts(commandName, explicit) {
1708
+ return resolveDetailsViewFooterCommandShortcuts(commandName, explicit);
1709
+ }
1710
+ function flattenDetailsViewActionShortcuts(shortcuts) {
1711
+ const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
1712
+ return dedupeDetailsViewActionShortcuts(chords);
1713
+ }
1714
+ function dedupeDetailsViewActionShortcuts(shortcuts) {
1715
+ const seen = new Set();
1716
+ const result = [];
1717
+ for (const shortcut of shortcuts) {
1718
+ const token = shortcut.trim().toLowerCase();
1719
+ if (!token || seen.has(token)) {
1720
+ continue;
1721
+ }
1722
+ seen.add(token);
1723
+ result.push(shortcut.trim());
1724
+ }
1725
+ return result;
1726
+ }
1727
+ //#endregion
1728
+
1196
1729
  /**
1197
1730
  * Registry of rendered page component instances by component key.
1198
1731
  * Used so page execute can delegate to the actual component instance in the view.
@@ -1331,87 +1864,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1331
1864
  }]
1332
1865
  }], propDecorators: { componentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentKey", required: true }] }], rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: false }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], componentReady: [{ type: i0.Output, args: ["componentReady"] }] } });
1333
1866
 
1334
- //#region ---- Details View Action Shortcut Utilities ----
1335
- /** Platform defaults for known entity detail commands when `shortcuts` is omitted on the action. */
1336
- const DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS = {
1337
- 'delete-entity': ['ctrl+shift+delete'],
1338
- };
1339
- const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
1340
- 'update-entity': ['ctrl+s'],
1341
- discard: ['escape'],
1342
- };
1343
- /**
1344
- * Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
1345
- */
1346
- function getDetailsViewActionCommandBaseName(commandName) {
1347
- if (!commandName) {
1348
- return '';
1349
- }
1350
- return commandName.split('&')[0];
1351
- }
1352
- /**
1353
- * Resolves keyboard shortcuts for a header entity action.
1354
- * Explicit `shortcuts` wins; pass `[]` to disable. Otherwise known commands use platform defaults.
1355
- */
1356
- function resolveDetailsViewActionShortcuts(commandBaseName, explicit) {
1357
- if (explicit !== undefined) {
1358
- const chords = flattenDetailsViewActionShortcuts(explicit);
1359
- return chords.length ? chords : undefined;
1360
- }
1361
- const defaults = DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS[commandBaseName];
1362
- return defaults?.length ? [...defaults] : undefined;
1363
- }
1364
- /**
1365
- * Resolves save/discard footer command shortcuts from page settings.
1366
- */
1367
- function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
1368
- if (explicit !== undefined) {
1369
- const chords = flattenDetailsViewActionShortcuts(explicit);
1370
- return chords.length ? chords : undefined;
1371
- }
1372
- const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
1373
- return defaults?.length ? [...defaults] : undefined;
1374
- }
1375
- function flattenDetailsViewActionShortcuts(shortcuts) {
1376
- const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
1377
- return dedupeDetailsViewActionShortcuts(chords);
1378
- }
1379
- function dedupeDetailsViewActionShortcuts(shortcuts) {
1380
- const seen = new Set();
1381
- const result = [];
1382
- for (const shortcut of shortcuts) {
1383
- const token = shortcut.trim().toLowerCase();
1384
- if (!token || seen.has(token)) {
1385
- continue;
1386
- }
1387
- seen.add(token);
1388
- result.push(shortcut.trim());
1389
- }
1390
- return result;
1391
- }
1392
- //#endregion
1393
-
1394
1867
  class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1395
1868
  constructor() {
1396
1869
  super(...arguments);
1397
- this.adapter = input.required(...(ngDevMode ? [{ debugName: "adapter" }] : /* istanbul ignore next */ []));
1398
1870
  //
1399
1871
  this.vm = inject(AXPLayoutDetailsViewViewModel);
1400
- this.router = inject(Router);
1401
1872
  this.route = inject(ActivatedRoute);
1402
1873
  this.eventService = inject(AXPBroadcastEventService);
1403
1874
  this.deviceService = inject(AXPDeviceService);
1404
- this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
1405
1875
  this.unsavedChangesPopstate = inject(AXPUnsavedChangesPopstateService);
1406
1876
  this.pageComponentInstanceRegistry = inject(AXPPageComponentInstanceRegistryService);
1407
1877
  this.shortcutRegistry = inject(AXPKeyboardShortcutRegistry);
1878
+ this.workflowService = inject(AXPWorkflowService);
1408
1879
  this.destroyRef = inject(DestroyRef);
1409
1880
  this.elementRef = inject((ElementRef));
1410
- /** Prevents sidebar tab init events from pushing history before {@link ngOnInit} load completes. */
1411
- this.detailsLayoutReady = false;
1881
+ this.debug = inject(AXPDebugService);
1882
+ /** Prevents sidebar tab init events from pushing history before the first page activation completes. */
1883
+ this.detailsLayoutReady = signal(false, ...(ngDevMode ? [{ debugName: "detailsLayoutReady" }] : /* istanbul ignore next */ []));
1412
1884
  this.destroyed$ = new Subject();
1413
1885
  this.footerActionsGeneration = 0;
1414
1886
  this.keyboardShortcutRegistrationGeneration = 0;
1887
+ /** Page id the overlay release logic is bound to; reset on sidebar/page switch. */
1888
+ this.overlayTargetPageId = null;
1889
+ /** After a page switch, wait for widget registry to clear before accepting remounted widgets. */
1890
+ this.overlaySawZeroWidgetsAfterPageChange = false;
1891
+ /** Cancels in-flight overlay release when the page changes. */
1892
+ this.overlayReleaseGeneration = 0;
1415
1893
  /** Header actions with resolved shortcut chords, keyed by command name. */
1416
1894
  this.actionShortcutEntries = signal(new Map(), ...(ngDevMode ? [{ debugName: "actionShortcutEntries" }] : /* istanbul ignore next */ []));
1417
1895
  this.form = viewChild('form', ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
@@ -1430,6 +1908,11 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1430
1908
  return;
1431
1909
  }
1432
1910
  untracked(() => queueMicrotask(() => {
1911
+ this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'sidebarTabs select (sync indicator)', () => ({
1912
+ currentPageId: currentId,
1913
+ tabIndex: index,
1914
+ routerUrl: this.router.url,
1915
+ }));
1433
1916
  this.sidebarTabChangeSuppressed = true;
1434
1917
  try {
1435
1918
  this.sidebarTabs()?.select(index);
@@ -1439,6 +1922,114 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1439
1922
  }
1440
1923
  }));
1441
1924
  }, ...(ngDevMode ? [{ debugName: "#sidebarTabsIndicatorEffect" }] : /* istanbul ignore next */ []));
1925
+ /** Clears the page overlay reactively once VM + widget hydration are both idle. */
1926
+ this.#overlayReleaseEffect = effect(() => {
1927
+ const showPages = this.vm.showPages();
1928
+ const pageId = this.vm.currentPage()?.id;
1929
+ const isVmBusy = this.vm.isOverlayBusy();
1930
+ const isPageReady = this.vm.isPageReady();
1931
+ const container = this.widgetContainer();
1932
+ this.vm.currentPageContent();
1933
+ this.vm.activeTabContent();
1934
+ this.vm.context();
1935
+ container?.builderService.registeredWidgetsCount();
1936
+ container?.builderService.isHydrating();
1937
+ container?.isBusy();
1938
+ container?.isWidgetsReady();
1939
+ const widgetCount = container?.builderService.registeredWidgetsCount() ?? 0;
1940
+ const widgetsBusy = container?.isBusy() ?? false;
1941
+ const widgetsReady = container?.isWidgetsReady() ?? false;
1942
+ untracked(() => {
1943
+ const widgetSnapshot = container?.builderService.getWidgetStateSnapshot();
1944
+ if (pageId !== this.overlayTargetPageId) {
1945
+ const isInitialOverlayBind = this.overlayTargetPageId == null;
1946
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'page bind changed', () => ({
1947
+ pageId,
1948
+ previousPageId: this.overlayTargetPageId,
1949
+ isInitialOverlayBind,
1950
+ overlayReleaseGeneration: this.overlayReleaseGeneration + 1,
1951
+ }));
1952
+ this.overlayTargetPageId = pageId ?? null;
1953
+ // First bind: widgets mount without a prior page registry. Sidebar switch: require clear first.
1954
+ this.overlaySawZeroWidgetsAfterPageChange = isInitialOverlayBind;
1955
+ this.overlayReleaseGeneration += 1;
1956
+ this.overlayReleasePromise = undefined;
1957
+ this.clearOverlayFallback();
1958
+ }
1959
+ if (showPages) {
1960
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'showPages — release overlay', () => ({ isVmBusy }));
1961
+ this.overlayReleaseGeneration += 1;
1962
+ this.overlayReleasePromise = undefined;
1963
+ this.clearOverlayFallback();
1964
+ if (!isVmBusy) {
1965
+ this.clearPageOverlay('showPages — release overlay');
1966
+ }
1967
+ return;
1968
+ }
1969
+ if (isVmBusy || !isPageReady || !pageId) {
1970
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'waiting on VM', () => ({
1971
+ pageId,
1972
+ isVmBusy,
1973
+ isPageReady,
1974
+ }));
1975
+ this.overlayReleaseGeneration += 1;
1976
+ this.overlayReleasePromise = undefined;
1977
+ this.clearOverlayFallback();
1978
+ return;
1979
+ }
1980
+ if (this.getActivePageComponentKey()) {
1981
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'component page — release overlay', () => ({
1982
+ componentKey: this.getActivePageComponentKey(),
1983
+ }));
1984
+ this.overlayReleaseGeneration += 1;
1985
+ this.overlayReleasePromise = undefined;
1986
+ this.clearOverlayFallback();
1987
+ this.clearPageOverlay('component page — release overlay');
1988
+ return;
1989
+ }
1990
+ if (!this.pageHasWidgetNodes()) {
1991
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'no widget nodes — release overlay', () => ({ pageId }));
1992
+ this.overlayReleaseGeneration += 1;
1993
+ this.overlayReleasePromise = undefined;
1994
+ this.clearOverlayFallback();
1995
+ this.clearPageOverlay('no widget nodes — release overlay');
1996
+ return;
1997
+ }
1998
+ if (widgetCount === 0) {
1999
+ this.overlaySawZeroWidgetsAfterPageChange = true;
2000
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'widget registry cleared (remount gate open)', () => ({ pageId }));
2001
+ }
2002
+ if (!this.overlaySawZeroWidgetsAfterPageChange) {
2003
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'blocked: remount gate (await widgetCount=0)', () => ({
2004
+ pageId,
2005
+ widgetCount,
2006
+ ...widgetSnapshot,
2007
+ }));
2008
+ this.scheduleOverlayFallback();
2009
+ return;
2010
+ }
2011
+ if (!widgetsReady || widgetsBusy) {
2012
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'blocked: widgets not ready', () => ({
2013
+ pageId,
2014
+ widgetsReady,
2015
+ widgetsBusy,
2016
+ overlaySawZero: this.overlaySawZeroWidgetsAfterPageChange,
2017
+ releaseInFlight: !!this.overlayReleasePromise,
2018
+ ...widgetSnapshot,
2019
+ hydratingWidgets: widgetSnapshot?.widgets?.filter((w) => w.isHydrating).map((w) => w.id),
2020
+ renderingWidgets: widgetSnapshot?.widgets?.filter((w) => w.status === 'rendering').map((w) => w.id),
2021
+ }));
2022
+ this.scheduleOverlayFallback();
2023
+ return;
2024
+ }
2025
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'request overlay release', () => ({
2026
+ pageId,
2027
+ overlayReleaseGeneration: this.overlayReleaseGeneration,
2028
+ ...widgetSnapshot,
2029
+ }));
2030
+ void this.requestOverlayRelease(pageId);
2031
+ });
2032
+ }, ...(ngDevMode ? [{ debugName: "#overlayReleaseEffect" }] : /* istanbul ignore next */ []));
1442
2033
  this.footerPrimaryActions = signal([], ...(ngDevMode ? [{ debugName: "footerPrimaryActions" }] : /* istanbul ignore next */ []));
1443
2034
  this.footerSecondaryActions = signal([], ...(ngDevMode ? [{ debugName: "footerSecondaryActions" }] : /* istanbul ignore next */ []));
1444
2035
  this.footerActions = computed(() => [...this.footerPrimaryActions(), ...this.footerSecondaryActions()], ...(ngDevMode ? [{ debugName: "footerActions" }] : /* istanbul ignore next */ []));
@@ -1462,7 +2053,14 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1462
2053
  if (this.vm.currentPage()?.isReadonly || this.getActivePageComponentKey()) {
1463
2054
  return false;
1464
2055
  }
1465
- return this.widgetContainer()?.isFormDirty() ?? false;
2056
+ if (this.vm.isOverlayBusy()) {
2057
+ return false;
2058
+ }
2059
+ const container = this.widgetContainer();
2060
+ if (!container?.isSavedCommitted()) {
2061
+ return false;
2062
+ }
2063
+ return container.isFormDirty();
1466
2064
  }, ...(ngDevMode ? [{ debugName: "liveFormIsDirty" }] : /* istanbul ignore next */ []));
1467
2065
  this.hasVisibleFooterPrimaryActions = computed(() => {
1468
2066
  if (this.showSaveDiscardFooter()) {
@@ -1479,11 +2077,25 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1479
2077
  if (this.vm.currentPage()?.isReadonly || this.getActivePageComponentKey()) {
1480
2078
  return;
1481
2079
  }
1482
- const isDirty = this.liveFormIsDirty();
2080
+ if (this.vm.isOverlayBusy()) {
2081
+ return;
2082
+ }
2083
+ const container = this.widgetContainer();
2084
+ if (!container?.isSavedCommitted()) {
2085
+ if (this.vm.formDirty()) {
2086
+ untracked(() => this.vm.setFormDirty(false));
2087
+ }
2088
+ return;
2089
+ }
2090
+ const isDirty = container.isFormDirty();
1483
2091
  if (this.vm.formDirty() === isDirty) {
1484
2092
  return;
1485
2093
  }
1486
2094
  untracked(() => {
2095
+ this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'formDirty effect', () => ({
2096
+ isDirty,
2097
+ vmFormDirty: this.vm.formDirty(),
2098
+ }));
1487
2099
  this.vm.setFormDirty(isDirty);
1488
2100
  this.recompute();
1489
2101
  });
@@ -1499,18 +2111,21 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1499
2111
  const generation = ++this.footerActionsGeneration;
1500
2112
  this.updateTrigger();
1501
2113
  this.liveFormIsDirty();
1502
- this.vm.isSaving();
2114
+ this.vm.isOverlayBusy();
1503
2115
  void this.refreshFooterActions(generation);
1504
2116
  }, ...(ngDevMode ? [{ debugName: "#FooterActionsEffect" }] : /* istanbul ignore next */ []));
1505
2117
  this.#keyboardShortcutsEffect = effect(() => {
1506
2118
  const generation = ++this.keyboardShortcutRegistrationGeneration;
1507
2119
  this.updateTrigger();
1508
2120
  this.liveFormIsDirty();
1509
- this.vm.isSaving();
2121
+ this.isActivePageComponentDirty();
2122
+ this.vm.isOverlayBusy();
1510
2123
  this.vm.currentPage()?.id;
1511
2124
  untracked(() => void this.refreshKeyboardShortcutRegistrations(generation));
1512
2125
  }, ...(ngDevMode ? [{ debugName: "#keyboardShortcutsEffect" }] : /* istanbul ignore next */ []));
1513
2126
  }
2127
+ /** Safety cap when widget ready detection does not settle. */
2128
+ static { this.overlayMaxWaitMs = 30_000; }
1514
2129
  /** Save/discard use live {@link AXPLayoutDetailsViewViewModel.isDirty}; other actions use evaluated `visible`. */
1515
2130
  static isTruthyActionFlag(value) {
1516
2131
  if (value === true) {
@@ -1537,6 +2152,8 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1537
2152
  }
1538
2153
  /** Syncs the line indicator when the active page changes programmatically. */
1539
2154
  #sidebarTabsIndicatorEffect;
2155
+ /** Clears the page overlay reactively once VM + widget hydration are both idle. */
2156
+ #overlayReleaseEffect;
1540
2157
  isSaveDiscardFooterAction(action) {
1541
2158
  const commandName = action.command?.name;
1542
2159
  const acceptCommand = this.vm.currentPage()?.settings?.commands?.accept?.command?.name;
@@ -1555,35 +2172,43 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1555
2172
  return AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.visible);
1556
2173
  }
1557
2174
  isFooterActionDisabled(action) {
1558
- if (this.vm.isSaving()) {
2175
+ if (this.vm.isOverlayBusy()) {
1559
2176
  return true;
1560
2177
  }
1561
2178
  return AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.disabled);
1562
2179
  }
1563
2180
  /**
1564
- * Append timestamp query param to trigger router to re-run guards/resolvers
2181
+ * Re-fetches the entity adapter and reloads the active page.
1565
2182
  */
1566
2183
  async refreshLayout() {
1567
- const router = this.router;
1568
- const route = this.route;
1569
- const now = Date.now();
1570
2184
  this.unsavedChangesConfirm.markLeaveConfirmed();
1571
- await router.navigate([], {
1572
- relativeTo: route,
1573
- queryParams: { _ts: now },
1574
- queryParamsHandling: 'merge',
1575
- replaceUrl: true,
1576
- });
2185
+ this.detailsLayoutReady.set(false);
2186
+ try {
2187
+ await this.vm.loadFromRoute(true);
2188
+ }
2189
+ finally {
2190
+ this.detailsLayoutReady.set(true);
2191
+ }
1577
2192
  }
1578
2193
  async ngOnInit() {
1579
2194
  await super.ngOnInit();
2195
+ this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'ngOnInit — before loadFromRoute', () => ({
2196
+ routerUrl: this.router.url,
2197
+ pageFromRouterUrl: this.router.parseUrl(this.router.url).queryParams['page'] ?? null,
2198
+ pageFromRouteSnapshot: this.route.snapshot.queryParamMap.get('page'),
2199
+ }));
1580
2200
  this.unsavedChangesPopstate.registerSource({
1581
2201
  id: 'axp-layout-details-view',
1582
- isDirty: () => this.shouldPromptLeave(),
2202
+ isDirty: () => this.hasUnsavedChanges(),
1583
2203
  });
2204
+ this.destroyRef.onDestroy(() => this.unsavedChangesPopstate.unregisterSource('axp-layout-details-view'));
1584
2205
  //
1585
- await this.vm.load(this.adapter());
1586
- this.detailsLayoutReady = true;
2206
+ await this.vm.loadFromRoute();
2207
+ this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'ngOnInit — after loadFromRoute', () => ({
2208
+ routerUrl: this.router.url,
2209
+ currentPageId: this.vm.currentPage()?.id ?? null,
2210
+ }));
2211
+ this.detailsLayoutReady.set(true);
1587
2212
  void this.refreshKeyboardShortcutRegistrations(++this.keyboardShortcutRegistrationGeneration);
1588
2213
  this.eventService
1589
2214
  //TODO: Use the constant from the entity module
@@ -1594,6 +2219,37 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1594
2219
  this.refreshLayout();
1595
2220
  }
1596
2221
  });
2222
+ this.workflowService.events$
2223
+ .pipe(filter$1((event) => event.type === AXP_ENTITY_DELETED_WORKFLOW_EVENT_TYPE), takeUntil(this.destroyed$))
2224
+ .subscribe((event) => {
2225
+ void this.handleEntityDeleted(event.payload);
2226
+ });
2227
+ }
2228
+ /** Navigates to {@link AXPLayoutDetailsViewAdapter.exitUrl} when the open record was deleted. */
2229
+ async handleEntityDeleted(payload) {
2230
+ if (!payload?.entity || !payload.ids?.length) {
2231
+ return;
2232
+ }
2233
+ const adapterName = this.vm.adapter()?.name;
2234
+ const recordId = this.vm.context()?.['id'];
2235
+ if (!adapterName || recordId == null) {
2236
+ return;
2237
+ }
2238
+ const deletedIds = payload.ids.map((id) => String(id));
2239
+ if (payload.entity !== adapterName || !deletedIds.includes(String(recordId))) {
2240
+ return;
2241
+ }
2242
+ this.unsavedChangesConfirm.markLeaveConfirmed();
2243
+ if (this.tabNavigation.effectiveMode() === 'tabular') {
2244
+ const tabKey = this.getPageTabKey();
2245
+ await this.vm.goToListPage();
2246
+ if (tabKey) {
2247
+ this.unsavedChangesConfirm.markLeaveConfirmed();
2248
+ await this.tabNavigation.closeTab(tabKey);
2249
+ }
2250
+ return;
2251
+ }
2252
+ await this.vm.goToListPage();
1597
2253
  }
1598
2254
  async ngAfterViewInit() {
1599
2255
  const listWidget = (await this.widgetContainer()?.find('page-list_table'));
@@ -1608,9 +2264,12 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1608
2264
  }
1609
2265
  }
1610
2266
  ngOnDestroy() {
1611
- this.unsavedChangesPopstate.unregisterSource('axp-layout-details-view');
1612
2267
  this.onSelectionChangeSubscription?.unsubscribe();
1613
2268
  ++this.keyboardShortcutRegistrationGeneration;
2269
+ this.clearOverlayFallback();
2270
+ this.overlayReleaseGeneration += 1;
2271
+ this.overlayReleasePromise = undefined;
2272
+ this.clearPageOverlay('ngOnDestroy');
1614
2273
  this.destroyed$.next();
1615
2274
  this.destroyed$.complete();
1616
2275
  }
@@ -1631,44 +2290,199 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1631
2290
  this.footerSecondaryActions.set(footerSecondaryActions);
1632
2291
  }
1633
2292
  handleOnContextChanged(e) {
1634
- this.vm.setFormDirty(e.isFormDirty ?? false);
2293
+ if (!this.vm.currentPage()?.isReadonly &&
2294
+ !this.getActivePageComponentKey() &&
2295
+ this.widgetContainer()?.isSavedCommitted()) {
2296
+ const isDirty = e.isFormDirty ?? false;
2297
+ const container = this.widgetContainer();
2298
+ this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'handleOnContextChanged', () => ({
2299
+ isFormDirty: isDirty,
2300
+ vmFormDirty: this.vm.formDirty(),
2301
+ changePath: e.path,
2302
+ changeOrigin: e.origin,
2303
+ userEditedSinceCommit: container?.contextService.hasUserEditedSinceCommit(),
2304
+ dirtyPaths: container
2305
+ ? summarizeFormContextDirtyDiff(container.contextService.data(), container.contextService.saved())
2306
+ : [],
2307
+ }));
2308
+ if (this.vm.formDirty() !== isDirty) {
2309
+ this.vm.setFormDirty(isDirty);
2310
+ }
2311
+ }
1635
2312
  this.recompute();
1636
2313
  }
1637
2314
  getLiveFormContext() {
1638
2315
  const container = this.widgetContainer();
1639
2316
  return (container?.contextService.data() ?? this.vm.context());
1640
2317
  }
2318
+ /** Whether the active page renders widget nodes (not only hosted components). */
2319
+ pageHasWidgetNodes() {
2320
+ const pageWidgets = this.vm.currentPageContent();
2321
+ if (pageWidgets.some((item) => !('type' in item && item.type === 'component'))) {
2322
+ return true;
2323
+ }
2324
+ return this.vm.activeTabContent().length > 0;
2325
+ }
2326
+ /** Clears all overlay loading tasks once the page (or hosted view) is ready. */
2327
+ clearPageOverlay(reason) {
2328
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', reason, () => ({
2329
+ taskCount: this.layoutService.overlayTaskCount(),
2330
+ }));
2331
+ this.layoutService.clearOverlayLoading();
2332
+ }
2333
+ scheduleOverlayFallback() {
2334
+ if (this.overlayFallbackTimer) {
2335
+ return;
2336
+ }
2337
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'schedule fallback timer', () => ({
2338
+ timeoutMs: AXPLayoutDetailsViewComponent.overlayMaxWaitMs,
2339
+ pageId: this.overlayTargetPageId,
2340
+ }));
2341
+ this.overlayFallbackTimer = setTimeout(() => {
2342
+ this.overlayFallbackTimer = undefined;
2343
+ const isOverlayLoading = this.layoutService.isOverlayLoading();
2344
+ const isVmBusy = this.vm.isOverlayBusy();
2345
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'fallback timer fired', () => ({
2346
+ isOverlayLoading,
2347
+ isVmBusy,
2348
+ pageId: this.overlayTargetPageId,
2349
+ }));
2350
+ if (!isOverlayLoading) {
2351
+ return;
2352
+ }
2353
+ if (!isVmBusy) {
2354
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'fallback forcing overlay off', () => ({
2355
+ taskCount: this.layoutService.overlayTaskCount(),
2356
+ }));
2357
+ this.clearPageOverlay('fallback forcing overlay off');
2358
+ }
2359
+ }, AXPLayoutDetailsViewComponent.overlayMaxWaitMs);
2360
+ }
2361
+ clearOverlayFallback() {
2362
+ if (this.overlayFallbackTimer) {
2363
+ clearTimeout(this.overlayFallbackTimer);
2364
+ this.overlayFallbackTimer = undefined;
2365
+ }
2366
+ }
2367
+ /**
2368
+ * Hides overlay after the widget container reports continuous idle (same gate as saved baseline).
2369
+ */
2370
+ requestOverlayRelease(pageId) {
2371
+ if (this.overlayReleasePromise) {
2372
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release skipped — already in flight', () => ({ pageId }));
2373
+ return;
2374
+ }
2375
+ const generation = this.overlayReleaseGeneration;
2376
+ const container = this.widgetContainer();
2377
+ if (!container) {
2378
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release skipped — no container', () => ({ pageId }));
2379
+ this.scheduleOverlayFallback();
2380
+ return;
2381
+ }
2382
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'waitUntilSettled started', () => ({ pageId, generation }));
2383
+ this.overlayReleasePromise = container
2384
+ .waitUntilSettled()
2385
+ .then(() => {
2386
+ const latest = this.widgetContainer();
2387
+ const snapshot = latest?.builderService.getWidgetStateSnapshot();
2388
+ if (generation !== this.overlayReleaseGeneration) {
2389
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — generation mismatch', () => ({
2390
+ pageId,
2391
+ generation,
2392
+ currentGeneration: this.overlayReleaseGeneration,
2393
+ }));
2394
+ return;
2395
+ }
2396
+ if (pageId !== this.overlayTargetPageId || pageId !== this.vm.currentPage()?.id) {
2397
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — page changed', () => ({
2398
+ pageId,
2399
+ overlayTargetPageId: this.overlayTargetPageId,
2400
+ currentPageId: this.vm.currentPage()?.id,
2401
+ }));
2402
+ return;
2403
+ }
2404
+ if (this.vm.isOverlayBusy()) {
2405
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — VM still busy', () => ({ pageId }));
2406
+ return;
2407
+ }
2408
+ if (!latest?.isWidgetsReady() || latest.isBusy()) {
2409
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — widgets not ready after settle', () => ({
2410
+ pageId,
2411
+ widgetsReady: latest?.isWidgetsReady(),
2412
+ widgetsBusy: latest?.isBusy(),
2413
+ ...snapshot,
2414
+ }));
2415
+ return;
2416
+ }
2417
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release overlay OFF', () => ({
2418
+ pageId,
2419
+ generation,
2420
+ taskCount: this.layoutService.overlayTaskCount(),
2421
+ ...snapshot,
2422
+ }));
2423
+ this.clearOverlayFallback();
2424
+ this.clearPageOverlay('widgets settled — release overlay');
2425
+ })
2426
+ .finally(() => {
2427
+ this.overlayReleasePromise = undefined;
2428
+ });
2429
+ }
1641
2430
  async finalizeSave() {
1642
2431
  const container = this.widgetContainer();
1643
2432
  if (!container) {
1644
2433
  this.vm.setFormDirty(false);
1645
2434
  return;
1646
2435
  }
1647
- const savedContext = this.vm.context();
1648
- await container.replaceContext(savedContext);
1649
- this.vm.applySavedState(container.contextService.data());
2436
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'finalizeSave overlay ON');
2437
+ this.layoutService.setOverlayLoading(true);
2438
+ try {
2439
+ const savedContext = this.vm.context();
2440
+ await container.replaceContext(savedContext);
2441
+ this.vm.applySavedState(container.contextService.data());
2442
+ if (!this.getActivePageComponentKey()) {
2443
+ await container.settleSavedBaseline();
2444
+ }
2445
+ }
2446
+ finally {
2447
+ this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'finalizeSave overlay OFF');
2448
+ this.layoutService.setOverlayLoading(false);
2449
+ }
1650
2450
  }
1651
2451
  finalizeDiscard() {
2452
+ this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'finalizeDiscard');
1652
2453
  const container = this.widgetContainer();
1653
- if (!container) {
2454
+ if (container) {
2455
+ container.revertAndSettle();
2456
+ const saved = container.contextService.saved();
2457
+ this.vm.applySavedState(saved);
1654
2458
  return;
1655
2459
  }
1656
- container.revertAndSettle();
1657
- this.vm.applySavedState(container.contextService.data());
2460
+ void this.vm.discard();
2461
+ }
2462
+ /** Reverts widget form state and view-model context to the last saved baseline. */
2463
+ async discardUnsavedChanges() {
2464
+ this.finalizeDiscard();
2465
+ this.recompute();
1658
2466
  }
1659
2467
  /**
1660
2468
  * `ax-tabs` selects on click before we can confirm. Revert synchronously, then confirm + switch.
1661
2469
  */
1662
2470
  handleSidebarTabChanged(event) {
1663
- if (!this.detailsLayoutReady || this.sidebarTabChangeSuppressed) {
2471
+ if (!this.detailsLayoutReady() || this.sidebarTabChangeSuppressed) {
1664
2472
  return;
1665
2473
  }
1666
2474
  const pages = this.vm.adapter()?.pages ?? [];
1667
2475
  const target = pages[event.index];
1668
2476
  const currentId = this.vm.currentPage()?.id;
1669
- if (!target || target.id === currentId) {
2477
+ if (!currentId || !target || target.id === currentId) {
1670
2478
  return;
1671
2479
  }
2480
+ this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'handleSidebarTabChanged', () => ({
2481
+ routerUrl: this.router.url,
2482
+ targetPageId: target.id,
2483
+ currentPageId: currentId ?? null,
2484
+ tabIndex: event.index,
2485
+ }));
1672
2486
  const activeIndex = pages.findIndex((page) => page.id === currentId);
1673
2487
  if (activeIndex >= 0) {
1674
2488
  this.sidebarTabChangeSuppressed = true;
@@ -1750,6 +2564,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1750
2564
  async getBackButton() {
1751
2565
  return this.vm.getBackButton();
1752
2566
  }
2567
+ hasUnsavedChanges() {
2568
+ return this.shouldPromptLeave();
2569
+ }
1753
2570
  async getPageBadge() {
1754
2571
  if (this.vm.currentPage()?.isReadonly) {
1755
2572
  return null;
@@ -1794,6 +2611,15 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1794
2611
  }
1795
2612
  return this.confirmLeaveIfDirty();
1796
2613
  }
2614
+ /** Background tab close — confirm without discarding (the cached instance is destroyed). */
2615
+ onBeforeTabClose() {
2616
+ if (this.unsavedChangesConfirm.hasLeaveConfirmed()) {
2617
+ return Promise.resolve(true);
2618
+ }
2619
+ return this.unsavedChangesConfirm.confirmIfDirty(this.shouldPromptLeave(), {
2620
+ approveLeaveOnConfirm: false,
2621
+ });
2622
+ }
1797
2623
  /** Active entity component page instance, when the current details sub-page is component-based. */
1798
2624
  getActivePageComponentInstance() {
1799
2625
  const componentKey = this.getActivePageComponentKey();
@@ -1818,10 +2644,33 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1818
2644
  static isComponentPageContent(item) {
1819
2645
  return 'type' in item && item.type === 'component';
1820
2646
  }
2647
+ pageContentTrackKey(item, index) {
2648
+ if (AXPLayoutDetailsViewComponent.isComponentPageContent(item)) {
2649
+ return `component:${item.componentKey}`;
2650
+ }
2651
+ return item.name ?? `widget:${index}`;
2652
+ }
1821
2653
  /** Whether the active component-based entity page has unsaved edits. */
1822
2654
  isActivePageComponentDirty() {
1823
2655
  return this.getActivePageComponentInstance()?.hasUnsavedChanges() ?? false;
1824
2656
  }
2657
+ /**
2658
+ * Widget-form dirty state for leave guards (popstate, canDeactivate).
2659
+ * Unlike {@link liveFormIsDirty}, does not suppress dirty while overlay is busy.
2660
+ */
2661
+ hasWidgetFormUnsavedChanges() {
2662
+ if (this.getActivePageComponentKey()) {
2663
+ return false;
2664
+ }
2665
+ const container = this.widgetContainer();
2666
+ if (!container) {
2667
+ return this.vm.formDirty();
2668
+ }
2669
+ if (container.isSavedCommitted()) {
2670
+ return container.isFormDirty();
2671
+ }
2672
+ return container.contextService.hasUserEditedSinceCommit() || this.vm.formDirty();
2673
+ }
1825
2674
  /** Whether the current details page has user-origin unsaved edits (form or component page). */
1826
2675
  shouldPromptLeave() {
1827
2676
  if (this.vm.currentPage()?.isReadonly) {
@@ -1830,11 +2679,16 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1830
2679
  if (this.isActivePageComponentDirty()) {
1831
2680
  return true;
1832
2681
  }
1833
- return this.liveFormIsDirty();
2682
+ return this.hasWidgetFormUnsavedChanges();
1834
2683
  }
1835
2684
  /** Single gate for leaving the page or switching details sub-pages when dirty. */
1836
- confirmLeaveIfDirty() {
1837
- return this.unsavedChangesConfirm.confirmIfDirty(this.shouldPromptLeave());
2685
+ async confirmLeaveIfDirty() {
2686
+ const shouldPrompt = this.shouldPromptLeave();
2687
+ const confirmed = await this.unsavedChangesConfirm.confirmIfDirty(shouldPrompt);
2688
+ if (confirmed && shouldPrompt) {
2689
+ await this.discardUnsavedChanges();
2690
+ }
2691
+ return confirmed;
1838
2692
  }
1839
2693
  //#endregion
1840
2694
  //#region ---- Command Execution ----
@@ -1853,9 +2707,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1853
2707
  return;
1854
2708
  }
1855
2709
  if (command.name == rejectCommand) {
1856
- await this.vm.discard();
1857
- this.finalizeDiscard();
1858
- this.recompute();
2710
+ await this.discardUnsavedChanges();
1859
2711
  return;
1860
2712
  }
1861
2713
  // Handle status update command
@@ -1918,9 +2770,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1918
2770
  return;
1919
2771
  }
1920
2772
  if (isDiscardCommand(command.name, rejectCommand)) {
1921
- await this.vm.discard();
1922
- this.finalizeDiscard();
1923
- this.recompute();
2773
+ await this.discardUnsavedChanges();
1924
2774
  return;
1925
2775
  }
1926
2776
  if (!this.isActivePageComponentDirty()) {
@@ -1954,17 +2804,59 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1954
2804
  this.registerCoreKeyboardShortcuts();
1955
2805
  this.registerActionKeyboardShortcuts(entries);
1956
2806
  }
2807
+ /** i18n scope label for the active details sub-page shortcut group in the help dialog. */
2808
+ getKeyboardShortcutScope() {
2809
+ const page = this.vm.currentPage();
2810
+ if (page?.isPrimary) {
2811
+ return '@general:keyboard-shortcuts.groups.entity-details';
2812
+ }
2813
+ const label = page?.label;
2814
+ if (typeof label === 'string' && label.length > 0) {
2815
+ return label;
2816
+ }
2817
+ return page?.id ?? '@general:keyboard-shortcuts.groups.entity-details';
2818
+ }
2819
+ /** Primary overview page backed by the entity widget form (not a component-hosted sub-page). */
2820
+ isWidgetFormPrimaryPage() {
2821
+ return !!this.vm.currentPage()?.isPrimary && !this.getActivePageComponentKey();
2822
+ }
2823
+ registerDetailsViewShortcutScope(id, shortcuts) {
2824
+ const scope = this.getKeyboardShortcutScope();
2825
+ this.shortcutRegistry.register({
2826
+ owner: this.destroyRef,
2827
+ elementRef: this.elementRef,
2828
+ id,
2829
+ priority: AXPKeyboardShortcutPriority.Page,
2830
+ scope,
2831
+ shortcuts,
2832
+ });
2833
+ }
1957
2834
  async collectActionShortcutEntries() {
1958
2835
  const map = new Map();
1959
2836
  if (this.vm.showPages()) {
1960
2837
  return map;
1961
2838
  }
1962
- const [primaryActions, secondaryActions] = await Promise.all([
1963
- this.getAllPrimaryActions(),
1964
- this.getAllSecondaryActions(),
2839
+ const includeAdapterActions = this.isWidgetFormPrimaryPage();
2840
+ const [adapterPrimaryActions, adapterSecondaryActions, pagePrimaryActions, pageSecondaryActions] = await Promise.all([
2841
+ includeAdapterActions ? this.vm.primaryActions() : Promise.resolve([]),
2842
+ includeAdapterActions ? this.vm.secondaryActions() : Promise.resolve([]),
2843
+ this.vm.currentPagePrimaryActions(),
2844
+ this.vm.currentPageSecondaryActions(),
1965
2845
  ]);
1966
- for (const action of [...primaryActions, ...secondaryActions]) {
1967
- if (action.zone !== 'header' || this.isSaveDiscardFooterAction(action)) {
2846
+ for (const action of [
2847
+ ...adapterPrimaryActions,
2848
+ ...adapterSecondaryActions,
2849
+ ...pagePrimaryActions,
2850
+ ...pageSecondaryActions,
2851
+ ]) {
2852
+ const zone = action.zone ?? 'header';
2853
+ if (zone !== 'header' && zone !== 'footer') {
2854
+ continue;
2855
+ }
2856
+ if (zone === 'footer' && this.isWidgetFormPrimaryPage() && this.isSaveDiscardFooterAction(action)) {
2857
+ continue;
2858
+ }
2859
+ if (zone === 'header' && this.isSaveDiscardFooterAction(action)) {
1968
2860
  continue;
1969
2861
  }
1970
2862
  const commandName = action.command?.name;
@@ -1973,7 +2865,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1973
2865
  continue;
1974
2866
  }
1975
2867
  const commandBaseName = getDetailsViewActionCommandBaseName(commandName);
1976
- const chords = resolveDetailsViewActionShortcuts(commandBaseName, action.shortcuts);
2868
+ const chords = zone === 'footer'
2869
+ ? resolvePageFooterActionShortcuts(commandBaseName, action.shortcuts)
2870
+ : resolveDetailsViewActionShortcuts(commandBaseName, action.shortcuts);
1977
2871
  if (!chords?.length) {
1978
2872
  continue;
1979
2873
  }
@@ -1981,13 +2875,13 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1981
2875
  command,
1982
2876
  title: typeof action.title === 'string' ? action.title : '',
1983
2877
  chords,
1984
- visible: this.isHeaderActionAvailable(action),
2878
+ visible: this.isShortcutActionAvailable(action),
1985
2879
  disabled: AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.disabled),
1986
2880
  });
1987
2881
  }
1988
2882
  return map;
1989
2883
  }
1990
- isHeaderActionAvailable(action) {
2884
+ isShortcutActionAvailable(action) {
1991
2885
  if (AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.hidden)) {
1992
2886
  return false;
1993
2887
  }
@@ -1996,15 +2890,15 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
1996
2890
  }
1997
2891
  return true;
1998
2892
  }
1999
- /** Whether save/discard core shortcuts are listed in the help dialog (page supports them). */
2893
+ /** Whether save/discard core shortcuts are listed in the help dialog (widget overview page only). */
2000
2894
  isCoreSaveShortcutAvailable() {
2001
- return !this.vm.currentPage()?.isReadonly && !!this.acceptFooterCommand();
2895
+ return this.isWidgetFormPrimaryPage() && !this.vm.currentPage()?.isReadonly && !!this.acceptFooterCommand();
2002
2896
  }
2003
2897
  isCoreDiscardShortcutAvailable() {
2004
- return !this.vm.currentPage()?.isReadonly && !!this.rejectFooterCommand();
2898
+ return this.isWidgetFormPrimaryPage() && !this.vm.currentPage()?.isReadonly && !!this.rejectFooterCommand();
2005
2899
  }
2006
2900
  canExecuteSaveShortcut() {
2007
- if (this.vm.currentPage()?.isReadonly || this.vm.isSaving()) {
2901
+ if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
2008
2902
  return false;
2009
2903
  }
2010
2904
  if (!this.acceptFooterCommand()) {
@@ -2013,7 +2907,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
2013
2907
  return this.shouldPromptLeave();
2014
2908
  }
2015
2909
  canExecuteDiscardShortcut() {
2016
- if (this.vm.currentPage()?.isReadonly || this.vm.isSaving()) {
2910
+ if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
2017
2911
  return false;
2018
2912
  }
2019
2913
  if (this.unsavedChangesConfirm.isConfirmPending()) {
@@ -2038,8 +2932,31 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
2038
2932
  }
2039
2933
  await this.execute({ name: rejectCommandName });
2040
2934
  }
2935
+ async executeActionShortcut(entry) {
2936
+ const commandName = entry.command.name;
2937
+ if (isDiscardFooterCommand(commandName)) {
2938
+ if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
2939
+ return;
2940
+ }
2941
+ if (this.unsavedChangesConfirm.isConfirmPending()) {
2942
+ return;
2943
+ }
2944
+ if (!this.shouldPromptLeave()) {
2945
+ return;
2946
+ }
2947
+ const confirmed = await this.unsavedChangesConfirm.confirmIfDirty(true, {
2948
+ title: '@general:messages.unsaved-changes.title',
2949
+ message: '@general:messages.discard-changes.message',
2950
+ approveLeaveOnConfirm: false,
2951
+ });
2952
+ if (!confirmed) {
2953
+ return;
2954
+ }
2955
+ }
2956
+ await this.execute(entry.command);
2957
+ }
2041
2958
  isActionShortcutActive(entryId) {
2042
- if (this.vm.currentPage()?.isReadonly || this.vm.isSaving()) {
2959
+ if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
2043
2960
  return false;
2044
2961
  }
2045
2962
  const entry = this.actionShortcutEntries().get(entryId);
@@ -2049,18 +2966,23 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
2049
2966
  return entry.visible && !entry.disabled;
2050
2967
  }
2051
2968
  registerCoreKeyboardShortcuts() {
2969
+ if (!this.isWidgetFormPrimaryPage()) {
2970
+ this.registerDetailsViewShortcutScope('layout-details-view-core', []);
2971
+ return;
2972
+ }
2052
2973
  const accept = this.vm.currentPage()?.settings?.commands?.accept;
2053
2974
  const reject = this.vm.currentPage()?.settings?.commands?.reject;
2054
2975
  const acceptCommandName = accept?.command.name ?? 'update-entity';
2055
2976
  const rejectCommandName = reject?.command.name ?? 'discard';
2056
2977
  const saveKeys = resolveDetailsViewFooterCommandShortcuts(acceptCommandName, accept?.shortcuts);
2057
2978
  const discardKeys = resolveDetailsViewFooterCommandShortcuts(rejectCommandName, reject?.shortcuts);
2979
+ const scope = this.getKeyboardShortcutScope();
2058
2980
  const shortcuts = [];
2059
2981
  if (saveKeys?.length && this.isCoreSaveShortcutAvailable()) {
2060
2982
  shortcuts.push({
2061
2983
  keys: saveKeys,
2062
2984
  title: accept?.title ?? '@general:actions.save.title',
2063
- group: '@general:keyboard-shortcuts.groups.entity-details',
2985
+ group: scope,
2064
2986
  allowInEditableFields: true,
2065
2987
  when: () => this.canExecuteSaveShortcut(),
2066
2988
  handler: () => {
@@ -2072,7 +2994,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
2072
2994
  shortcuts.push({
2073
2995
  keys: discardKeys,
2074
2996
  title: reject?.title ?? '@general:actions.discard.title',
2075
- group: '@general:keyboard-shortcuts.groups.entity-details',
2997
+ group: scope,
2076
2998
  allowInEditableFields: true,
2077
2999
  when: () => this.canExecuteDiscardShortcut(),
2078
3000
  handler: () => {
@@ -2080,62 +3002,44 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
2080
3002
  },
2081
3003
  });
2082
3004
  }
2083
- if (shortcuts.length === 0) {
2084
- return;
2085
- }
2086
- this.shortcutRegistry.register({
2087
- owner: this.destroyRef,
2088
- elementRef: this.elementRef,
2089
- id: 'layout-details-view-core',
2090
- priority: AXPKeyboardShortcutPriority.Page,
2091
- scope: '@general:keyboard-shortcuts.groups.entity-details',
2092
- shortcuts,
2093
- });
3005
+ this.registerDetailsViewShortcutScope('layout-details-view-core', shortcuts);
2094
3006
  }
2095
3007
  registerActionKeyboardShortcuts(entries) {
3008
+ const scope = this.getKeyboardShortcutScope();
2096
3009
  const shortcuts = [];
2097
3010
  for (const [entryId, entry] of entries) {
2098
3011
  for (const chord of entry.chords) {
2099
3012
  shortcuts.push({
2100
3013
  keys: [chord],
2101
3014
  title: entry.title,
2102
- group: '@general:keyboard-shortcuts.groups.entity-details',
3015
+ group: scope,
3016
+ allowInEditableFields: entry.command.name ? isSaveFooterCommand(entry.command.name) || isDiscardFooterCommand(entry.command.name) : false,
2103
3017
  when: () => this.isActionShortcutActive(entryId),
2104
3018
  handler: () => {
2105
3019
  if (!this.isActionShortcutActive(entryId)) {
2106
3020
  return;
2107
3021
  }
2108
- void this.execute(entry.command);
3022
+ void this.executeActionShortcut(entry);
2109
3023
  },
2110
3024
  });
2111
3025
  }
2112
3026
  }
2113
- if (shortcuts.length === 0) {
2114
- return;
2115
- }
2116
- this.shortcutRegistry.register({
2117
- owner: this.destroyRef,
2118
- elementRef: this.elementRef,
2119
- id: 'layout-details-view-actions',
2120
- priority: AXPKeyboardShortcutPriority.Page,
2121
- scope: '@general:keyboard-shortcuts.groups.entity-details',
2122
- shortcuts,
2123
- });
3027
+ this.registerDetailsViewShortcutScope('layout-details-view-actions', shortcuts);
2124
3028
  }
2125
3029
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutDetailsViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
2126
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLayoutDetailsViewComponent, isStandalone: true, selector: "axp-layout-details-view", inputs: { adapter: { classPropertyName: "adapter", publicName: "adapter", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
3030
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLayoutDetailsViewComponent, isStandalone: true, selector: "axp-layout-details-view", providers: [
2127
3031
  {
2128
3032
  provide: AXPPageLayoutBase,
2129
3033
  useExisting: AXPLayoutDetailsViewComponent,
2130
3034
  },
2131
3035
  AXPLayoutDetailsViewViewModel,
2132
- ], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "sidebarTabs", first: true, predicate: ["sidebarTabs"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n (formatService.format(vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''), 'string', vm.rootContext())\n | translate\n | async)\n }}</axp-layout-title>\n <axp-layout-description>{{\n (formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async)\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs\n #sidebarTabs\n class=\"axp-vertical-tabs\"\n [look]=\"'with-line-color'\"\n [location]=\"'end'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\"\n >\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item\n [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n @if (vm.isBusy()) {\n <div class=\"ax-flex ax-h-full ax-w-full ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container\n #widgetsContainerRef\n [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\"\n >\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track $index) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div\n axp-page-component-renderer\n [componentKey]=\"$any(item).componentKey\"\n [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\"\n [options]=\"$any(item).options\"\n (componentReady)=\"recompute()\"\n ></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item\n (onClick)=\"vm.setCurrentTab(tab)\"\n [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\"\n [color]=\"'default'\"\n >\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item\n [text]=\"(t(action.title) | async)!\"\n [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(reject.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"reject.color\"\n (onClick)=\"execute(reject.command)\"\n >\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(accept.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"accept.color\"\n (onClick)=\"execute(accept.command)\"\n >\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item\n [text]=\"(t(sub.title) | async)!\"\n [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\"\n (onClick)=\"execute(sub.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>\n", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"], dependencies: [{ kind: "ngmodule", type:
3036
+ ], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "sidebarTabs", first: true, predicate: ["sidebarTabs"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n formatService.format(\n vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''),\n 'string',\n vm.rootContext()\n )\n | translate\n | async\n }}</axp-layout-title>\n <axp-layout-description>{{\n formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs #sidebarTabs class=\"axp-vertical-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\">\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container #widgetsContainerRef [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\">\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track pageContentTrackKey($any(item), $index)) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div axp-page-component-renderer [componentKey]=\"$any(item).componentKey\" [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\" [options]=\"$any(item).options\" (componentReady)=\"recompute()\"></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item (onClick)=\"vm.setCurrentTab(tab)\" [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item [text]=\"(t(action.title) | async)!\" [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\" (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(reject.title) | async)!\" [look]=\"'solid'\" [color]=\"reject.color\" (onClick)=\"execute(reject.command)\">\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(accept.title) | async)!\" [look]=\"'solid'\" [color]=\"accept.color\" (onClick)=\"execute(accept.command)\">\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\" [look]=\"'solid'\" [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\" (onClick)=\"execute(sub.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"], dependencies: [{ kind: "ngmodule", type:
2133
3037
  // Angular
2134
3038
  CommonModule }, { kind: "ngmodule", type:
2135
3039
  // ACoreX
2136
- AXMenuModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.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: "component", type: i6.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i6.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.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: i5$1.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: AXFileModule }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i6$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i6$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "component", type:
3040
+ AXMenuModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.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: "component", type: i6.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i6.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.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: AXBreadcrumbsModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: AXFileModule }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i5$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i5$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "component", type:
2137
3041
  //
2138
- AXPThemeLayoutListComponent, selector: "axp-layout-list" }, { kind: "component", type: AXPThemeLayoutListItemComponent, selector: "axp-layout-list-item" }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i7.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i7.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i8$1.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }, { kind: "directive", type: AXPPageComponentRendererDirective, selector: "[axp-page-component-renderer]", inputs: ["componentKey", "rootContext", "pageConfig", "options"], outputs: ["componentReady"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
3042
+ AXPThemeLayoutListComponent, selector: "axp-layout-list" }, { kind: "component", type: AXPThemeLayoutListItemComponent, selector: "axp-layout-list-item" }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i7.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }, { kind: "directive", type: AXPPageComponentRendererDirective, selector: "[axp-page-component-renderer]", inputs: ["componentKey", "rootContext", "pageConfig", "options"], outputs: ["componentReady"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2139
3043
  }
2140
3044
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutDetailsViewComponent, decorators: [{
2141
3045
  type: Component,
@@ -2150,7 +3054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2150
3054
  AXDropdownModule,
2151
3055
  AXTranslationModule,
2152
3056
  AXDecoratorModule,
2153
- AXLoadingModule,
2154
3057
  AXBreadcrumbsModule,
2155
3058
  AXBadgeModule,
2156
3059
  AXSearchBoxModule,
@@ -2175,8 +3078,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2175
3078
  useExisting: AXPLayoutDetailsViewComponent,
2176
3079
  },
2177
3080
  AXPLayoutDetailsViewViewModel,
2178
- ], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n (formatService.format(vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''), 'string', vm.rootContext())\n | translate\n | async)\n }}</axp-layout-title>\n <axp-layout-description>{{\n (formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async)\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs\n #sidebarTabs\n class=\"axp-vertical-tabs\"\n [look]=\"'with-line-color'\"\n [location]=\"'end'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\"\n >\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item\n [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n @if (vm.isBusy()) {\n <div class=\"ax-flex ax-h-full ax-w-full ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container\n #widgetsContainerRef\n [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\"\n >\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track $index) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div\n axp-page-component-renderer\n [componentKey]=\"$any(item).componentKey\"\n [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\"\n [options]=\"$any(item).options\"\n (componentReady)=\"recompute()\"\n ></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item\n (onClick)=\"vm.setCurrentTab(tab)\"\n [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\"\n [color]=\"'default'\"\n >\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item\n [text]=\"(t(action.title) | async)!\"\n [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(reject.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"reject.color\"\n (onClick)=\"execute(reject.command)\"\n >\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(accept.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"accept.color\"\n (onClick)=\"execute(accept.command)\"\n >\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item\n [text]=\"(t(sub.title) | async)!\"\n [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\"\n (onClick)=\"execute(sub.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>\n", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"] }]
2179
- }], propDecorators: { adapter: [{ type: i0.Input, args: [{ isSignal: true, alias: "adapter", required: true }] }], form: [{ type: i0.ViewChild, args: ['form', { isSignal: true }] }], widgetContainer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPWidgetContainerComponent), { isSignal: true }] }], sidebarTabs: [{ type: i0.ViewChild, args: ['sidebarTabs', { isSignal: true }] }] } });
3081
+ ], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n formatService.format(\n vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''),\n 'string',\n vm.rootContext()\n )\n | translate\n | async\n }}</axp-layout-title>\n <axp-layout-description>{{\n formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs #sidebarTabs class=\"axp-vertical-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\">\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container #widgetsContainerRef [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\">\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track pageContentTrackKey($any(item), $index)) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div axp-page-component-renderer [componentKey]=\"$any(item).componentKey\" [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\" [options]=\"$any(item).options\" (componentReady)=\"recompute()\"></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item (onClick)=\"vm.setCurrentTab(tab)\" [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item [text]=\"(t(action.title) | async)!\" [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\" (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(reject.title) | async)!\" [look]=\"'solid'\" [color]=\"reject.color\" (onClick)=\"execute(reject.command)\">\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(accept.title) | async)!\" [look]=\"'solid'\" [color]=\"accept.color\" (onClick)=\"execute(accept.command)\">\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\" [look]=\"'solid'\" [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\" (onClick)=\"execute(sub.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"] }]
3082
+ }], propDecorators: { form: [{ type: i0.ViewChild, args: ['form', { isSignal: true }] }], widgetContainer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPWidgetContainerComponent), { isSignal: true }] }], sidebarTabs: [{ type: i0.ViewChild, args: ['sidebarTabs', { isSignal: true }] }] } });
2180
3083
 
2181
3084
  //#region ---- Details View Can Deactivate Guard ----
2182
3085
  /**
@@ -2189,5 +3092,5 @@ const axpDetailsViewCanDeactivateGuard = createUnsavedChangesCanDeactivateGuard(
2189
3092
  * Generated bundle index. Do not edit.
2190
3093
  */
2191
3094
 
2192
- export { AXPLayoutDetailsViewComponent, AXPLayoutDetailsViewViewModel, AXPPageComponentInstanceRegistryService, AXPPageComponentRendererDirective, AXPPageLayoutBase, AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPopupLayoutBase, AXPPopupLayoutBaseComponent, AXPPopupLayoutComponent, axpDetailsViewCanDeactivateGuard, buildNotSavedPageBadge, getDetailsViewActionCommandBaseName, isDiscardCommand, resolveDetailsViewActionShortcuts, resolveDetailsViewFooterCommandShortcuts };
3095
+ export { AXPLayoutDetailsViewComponent, AXPLayoutDetailsViewViewModel, AXPPageComponentInstanceRegistryService, AXPPageComponentRendererDirective, AXPPageLayoutBase, AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPopupLayoutBase, AXPPopupLayoutBaseComponent, AXPPopupLayoutComponent, AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER, axpDetailsViewCanDeactivateGuard, buildNotSavedPageBadge, getDetailsViewActionCommandBaseName, isDiscardCommand, isDiscardFooterCommand, isSaveFooterCommand, resolveDetailsViewActionShortcuts, resolveDetailsViewFooterCommandShortcuts, resolvePageFooterActionDefaultShortcuts, resolvePageFooterActionShortcuts };
2193
3096
  //# sourceMappingURL=acorex-platform-layout-views.mjs.map