@acorex/platform 21.0.0-next.83 → 21.0.0-next.88

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 (74) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +1 -1
  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-VfmZct9H.mjs} +43 -3
  4. package/fesm2022/acorex-platform-common-common-settings.provider-VfmZct9H.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +1709 -870
  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 +210 -131
  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.map +1 -1
  16. package/fesm2022/acorex-platform-layout-components.mjs +61 -23
  17. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  18. package/fesm2022/acorex-platform-layout-designer.mjs +3 -2
  19. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  20. package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-entity-contracts.mjs +1114 -0
  22. package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -0
  23. package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-layout-entity.mjs +661 -742
  25. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  26. package/fesm2022/acorex-platform-layout-views.mjs +376 -176
  27. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  28. package/fesm2022/acorex-platform-layout-widget-core.mjs +11 -105
  29. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  30. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
  31. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
  32. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-D4MOHEpI.mjs} +4 -4
  33. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-D4MOHEpI.mjs.map +1 -0
  34. package/fesm2022/acorex-platform-layout-widgets.mjs +871 -59
  35. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  36. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  37. 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
  38. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
  39. package/fesm2022/acorex-platform-themes-default.mjs +740 -96
  40. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  41. package/fesm2022/{acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs → acorex-platform-themes-shared-settings.provider-BUwPqwUS.mjs} +3 -3
  42. package/fesm2022/acorex-platform-themes-shared-settings.provider-BUwPqwUS.mjs.map +1 -0
  43. package/fesm2022/acorex-platform-themes-shared.mjs +4 -3
  44. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  45. package/fesm2022/acorex-platform-workflow.mjs +6 -8
  46. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  47. package/package.json +9 -5
  48. package/types/acorex-platform-auth.d.ts +2 -1
  49. package/types/acorex-platform-common.d.ts +419 -1083
  50. package/types/acorex-platform-contracts.d.ts +1791 -260
  51. package/types/acorex-platform-core.d.ts +2153 -2806
  52. package/types/acorex-platform-domain-contracts.d.ts +416 -0
  53. package/types/acorex-platform-domain.d.ts +4 -415
  54. package/types/acorex-platform-layout-builder.d.ts +2 -1
  55. package/types/acorex-platform-layout-components.d.ts +15 -4
  56. package/types/acorex-platform-layout-designer.d.ts +2 -1
  57. package/types/acorex-platform-layout-entity-contracts.d.ts +864 -0
  58. package/types/acorex-platform-layout-entity.d.ts +88 -269
  59. package/types/acorex-platform-layout-views.d.ts +48 -14
  60. package/types/acorex-platform-layout-widget-core.d.ts +9 -5
  61. package/types/acorex-platform-layout-widgets.d.ts +89 -13
  62. package/types/acorex-platform-runtime.d.ts +1 -1
  63. package/types/acorex-platform-themes-default.d.ts +173 -70
  64. package/types/acorex-platform-workflow.d.ts +5 -18
  65. package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
  66. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
  67. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
  68. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map +0 -1
  69. package/fesm2022/acorex-platform-native.mjs +0 -155
  70. package/fesm2022/acorex-platform-native.mjs.map +0 -1
  71. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
  72. package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +0 -1
  73. package/native/README.md +0 -4
  74. package/types/acorex-platform-native.d.ts +0 -28
@@ -27,7 +27,7 @@ import { AXTranslationModule, AXTranslationService, translateSync } from '@acore
27
27
  import * as i2 from '@acorex/core/utils';
28
28
  import { AXUnsubscriber } from '@acorex/core/utils';
29
29
  import { AXPAuthModule, AXPSessionService, AXPSessionStatus } from '@acorex/platform/auth';
30
- import { AXPRefreshEvent, AXPSettingsService, AXPCommonSettings, axpIsEntityListRoute, axpReplaceEntityListRouteQueryParams, axpIsEntityListPath, AXP_PLATFORM_CONFIG_TOKEN, AXPMenuService, AXPMenuVisibilityService, AXP_PROTECTED_ROUTE_GUARDS, AXPCommonModule } from '@acorex/platform/common';
30
+ import { AXPRefreshEvent, AXPSettingsService, AXPCommonSettings, axpIsEntityListRoute, axpReplaceEntityListRouteQueryParams, axpIsEntityListPath, AXPTabNavigationService, AXPTabPreviewService, AXP_HOME_TAB_KEY, AXP_PLATFORM_CONFIG_TOKEN, AXPMenuService, AXPMenuVisibilityService, axpMenuPathsMatch, AXPTabRouteCacheRegistry, axpResolveTabKeyFromSnapshot, axpHasTabScope, axpPathFromSnapshot, axpIsTabEligibleUrl, axpResolveTabKeyFromRouteConfig, AXP_PROTECTED_ROUTE_GUARDS, AXPCommonModule } from '@acorex/platform/common';
31
31
  import * as i1$5 from '@acorex/platform/core';
32
32
  import { AXPDeviceService, AXHighlightService, AXPGridLayoutDirective, AXPComponentSlotModule, AXPKeyboardShortcutRegistry, AXPKeyboardShortcutPriority, AXPBroadcastEventService, AXPContextStore } from '@acorex/platform/core';
33
33
  import { AXP_CATEGORY_TREE_ROOT_TITLE_I18N_KEY, AXPEntityDefinitionRegistryService, AXPCategoryTreeService, AXPEntityListViewColumnViewModel, AXPEntityMasterListCardSelectActionName, applyDataSourcePagingWithoutLoad, getDataSourcePageIndex, restoreEntityListExpandedRows, AXP_ENTITY_CONFIG_TOKEN } from '@acorex/platform/layout/entity';
@@ -39,14 +39,14 @@ import { AXPWorkflowService, ofType } from '@acorex/platform/workflow';
39
39
  import * as i1$1 from '@angular/common';
40
40
  import { CommonModule, AsyncPipe } from '@angular/common';
41
41
  import * as i0 from '@angular/core';
42
- import { inject, signal, computed, effect, ViewChild, Input, ChangeDetectionStrategy, ViewEncapsulation, Component, input, viewChild, afterNextRender, output, untracked, DestroyRef, NgModule } from '@angular/core';
42
+ import { inject, signal, computed, effect, ViewChild, Input, ChangeDetectionStrategy, ViewEncapsulation, Component, input, viewChild, afterNextRender, Injector, output, untracked, ElementRef, DestroyRef, NgModule } from '@angular/core';
43
43
  import { FormsModule } from '@angular/forms';
44
44
  import * as i1$6 from '@angular/router';
45
45
  import { RouterModule, Router, ActivatedRoute, NavigationStart, NavigationEnd, RouteReuseStrategy, ROUTES } from '@angular/router';
46
46
  import { Subject, takeUntil, filter, firstValueFrom } from 'rxjs';
47
47
  import * as i1$4 from '@acorex/core/platform';
48
48
  import { AXPThemeLayoutBlockComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutToolbarComponent, AXPStateMessageComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewsComponent, AXPQueryColumnsComponent, AXPThemeLayoutStartSideComponent, AXPTaskBadgeService, AXPMenuBadgeHelper, AXPTaskBadgeDirective, AXPLogoComponent } from '@acorex/platform/layout/components';
49
- import { DragDropModule } from '@angular/cdk/drag-drop';
49
+ import { DragDropModule, CdkDropList, CdkDrag, CdkDragHandle, CdkDragPreview } from '@angular/cdk/drag-drop';
50
50
  import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
51
51
  import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
52
52
  import * as i2$2 from '@acorex/components/skeleton';
@@ -59,12 +59,12 @@ import * as i1$3 from '@acorex/components/data-pager';
59
59
  import { AXDataPagerModule } from '@acorex/components/data-pager';
60
60
  import * as i3$3 from '@acorex/components/check-box';
61
61
  import { AXCheckBoxModule } from '@acorex/components/check-box';
62
+ import * as i4 from '@acorex/components/menu';
63
+ import { AXContextMenuComponent, AXMenuModule } from '@acorex/components/menu';
62
64
  import * as i2$3 from '@acorex/components/side-menu';
63
65
  import { AXSideMenuModule } from '@acorex/components/side-menu';
64
66
  import { AXAvatarModule } from '@acorex/components/avatar';
65
67
  import { AXImageModule } from '@acorex/components/image';
66
- import * as i4 from '@acorex/components/menu';
67
- import { AXMenuModule } from '@acorex/components/menu';
68
68
  import sortBy$1 from 'lodash-es/sortBy';
69
69
  import { AXResizableDirective } from '@acorex/cdk/resizable';
70
70
 
@@ -872,19 +872,23 @@ class AXPEntityCategoryComponent {
872
872
  return children;
873
873
  }
874
874
  /**
875
- * Refreshes the tree view component
875
+ * Reloads tree data from the server and optionally expands a parent node.
876
876
  */
877
- refreshTree() {
877
+ async refreshAfterChange(parentId) {
878
878
  const treeComponent = this.tree();
879
- if (treeComponent) {
880
- treeComponent.refresh();
879
+ if (!treeComponent) {
880
+ return;
881
+ }
882
+ await treeComponent.reloadData();
883
+ const expandId = parentId ?? ROOT_NODE_ID;
884
+ try {
885
+ if (!treeComponent.isNodeExpanded(expandId)) {
886
+ await treeComponent.expandNode(expandId);
887
+ }
888
+ }
889
+ catch {
890
+ // Parent node may not exist yet after reload; ignore.
881
891
  }
882
- }
883
- /**
884
- * Refreshes tree after CRUD operations
885
- */
886
- async refreshAfterChange(parentId) {
887
- this.refreshTree();
888
892
  }
889
893
  /**
890
894
  * Adds a new node to the tree after create operation
@@ -1236,8 +1240,8 @@ class AXPEntityMasterToolbarViewComponent {
1236
1240
  this.router = inject(Router);
1237
1241
  this.activeRoute = inject(ActivatedRoute);
1238
1242
  this.settingsService = inject(AXPSettingsService);
1243
+ this.injector = inject(Injector);
1239
1244
  this.isInitializing = false;
1240
- this.pendingInitialFilters = true;
1241
1245
  this.pendingInitialSorts = true;
1242
1246
  this.filterTriggerMode = 'manual';
1243
1247
  this.previousFilterQueries = signal([], ...(ngDevMode ? [{ debugName: "previousFilterQueries" }] : /* istanbul ignore next */ []));
@@ -1286,7 +1290,7 @@ class AXPEntityMasterToolbarViewComponent {
1286
1290
  this.applyTimer = null;
1287
1291
  this.#effect = effect(() => {
1288
1292
  // Keep definitions up to date; initial filters are set explicitly from settings or view
1289
- this.filtersDefinitions.set(this.vm.filtersDef);
1293
+ this.filtersDefinitions.set(this.vm.filterDefinitions());
1290
1294
  }, ...(ngDevMode ? [{ debugName: "#effect" }] : /* istanbul ignore next */ []));
1291
1295
  this.sortQueries = computed(() => this.vm
1292
1296
  .sortedFields()
@@ -1315,20 +1319,34 @@ class AXPEntityMasterToolbarViewComponent {
1315
1319
  }, ...(ngDevMode ? [{ debugName: "sortDefinitions" }] : /* istanbul ignore next */ []));
1316
1320
  }
1317
1321
  async ngOnInit() {
1318
- // Prefer saved settings (view/columns/sorts/filters) if available, then apply
1322
+ // Prefer saved settings (view/columns/sorts/filters) if available, then apply once
1319
1323
  await this.loadSettings();
1320
1324
  await this.vm.setView();
1321
1325
  await this.vm.ensureListPagingResolved();
1322
- this.filtersDefinitions.set(this.vm.filtersDef);
1326
+ this.filtersDefinitions.set(this.vm.filterDefinitions());
1327
+ await this.runInitialListLoad();
1328
+ }
1329
+ /**
1330
+ * Applies persisted view/filters/sorts once after query-filters syncs `initialFilters`.
1331
+ * Avoids a second list query from `scheduleApply` plus a follow-up `onFiltersChanged` emit.
1332
+ */
1333
+ async runInitialListLoad() {
1323
1334
  this.isInitializing = true;
1324
- // this.pendingInitialFilters = true;
1325
- // this.pendingInitialSorts = true;
1335
+ this.pendingInitialSorts = true;
1326
1336
  this.setInitialFiltersFromSettingsOrView();
1327
- // Ensure initial load even when filters/sorts are absent
1328
- setTimeout(() => {
1329
- this.isInitializing = false;
1330
- this.scheduleApply();
1331
- }, 0);
1337
+ await this.waitForQueryFiltersSync();
1338
+ await this.vm.applyFilterAndSort();
1339
+ this.previousFilterQueries.set(this.vm.filterQueries());
1340
+ this.isInitializing = false;
1341
+ this.pendingInitialSorts = false;
1342
+ }
1343
+ /** Waits until query-filters has rendered and synced converted `initialFilters`. */
1344
+ waitForQueryFiltersSync() {
1345
+ return new Promise((resolve) => {
1346
+ afterNextRender(() => {
1347
+ queueMicrotask(() => resolve());
1348
+ }, { injector: this.injector });
1349
+ });
1332
1350
  }
1333
1351
  async loadSettings() {
1334
1352
  const filterTriggerMode = await this.settingsService.get(AXPCommonSettings.EntityFilterApplyMode);
@@ -1349,15 +1367,7 @@ class AXPEntityMasterToolbarViewComponent {
1349
1367
  if (axpIsEntityListRoute(this.router)) {
1350
1368
  axpReplaceEntityListRouteQueryParams(this.router, { view: view.name });
1351
1369
  }
1352
- this.isInitializing = true;
1353
- this.pendingInitialFilters = true;
1354
- this.pendingInitialSorts = true;
1355
- this.setInitialFiltersFromSettingsOrView();
1356
- // Ensure initial load after view change
1357
- setTimeout(() => {
1358
- this.isInitializing = false;
1359
- this.scheduleApply();
1360
- }, 0);
1370
+ await this.runInitialListLoad();
1361
1371
  }
1362
1372
  #effect;
1363
1373
  setInitialFiltersFromSettingsOrView() {
@@ -1376,8 +1386,9 @@ class AXPEntityMasterToolbarViewComponent {
1376
1386
  })));
1377
1387
  }
1378
1388
  onFiltersChanged(filters) {
1379
- if (this.isInitializing || this.pendingInitialFilters) {
1380
- this.pendingInitialFilters = false;
1389
+ if (this.isInitializing) {
1390
+ this.vm.filterQueries.set(filters);
1391
+ this.previousFilterQueries.set(filters);
1381
1392
  return;
1382
1393
  }
1383
1394
  this.vm.filterQueries.set(filters);
@@ -1388,7 +1399,7 @@ class AXPEntityMasterToolbarViewComponent {
1388
1399
  applyFilters() {
1389
1400
  this.previousFilterQueries.set(this.vm.filterQueries());
1390
1401
  this.vm.saveSettings('filters', this.vm.filterQueries());
1391
- this.scheduleApply();
1402
+ void this.vm.applyFilterAndSort();
1392
1403
  }
1393
1404
  onSortQueriesChange(e) {
1394
1405
  if (this.isInitializing || this.pendingInitialSorts) {
@@ -1774,10 +1785,15 @@ class AXPEntityMasterListCardListComponent {
1774
1785
  await this.vm().executeCommand(name, row);
1775
1786
  }
1776
1787
  onPageChanged(event) {
1777
- if (event.isUserInteraction && !this.vm().skipListPagingPersistence) {
1788
+ applyDataSourcePagingWithoutLoad(this.vm().dataSource, { take: event.take, skip: event.skip });
1789
+ this.pageIndex.set(getDataSourcePageIndex(this.vm().dataSource));
1790
+ this.pageSize.set(event.take);
1791
+ if (!event.isUserInteraction) {
1792
+ return;
1793
+ }
1794
+ if (!this.vm().skipListPagingPersistence) {
1778
1795
  this.vm().saveListPaging(event.take, event.skip);
1779
1796
  }
1780
- applyDataSourcePagingWithoutLoad(this.vm().dataSource, { take: event.take, skip: event.skip });
1781
1797
  this.pageChanged.emit(event);
1782
1798
  void this.reload(false);
1783
1799
  }
@@ -1946,7 +1962,6 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
1946
1962
  this.platform = platform;
1947
1963
  //#region ---- Services & Dependencies ----
1948
1964
  this.activeRoute = inject(ActivatedRoute);
1949
- this.router = inject(Router);
1950
1965
  //#endregion
1951
1966
  //#region ---- View State ----
1952
1967
  this.vm = this.activeRoute.snapshot.data['vm'];
@@ -1957,6 +1972,7 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
1957
1972
  //#endregion
1958
1973
  //#region ---- View References ----
1959
1974
  this.dataTable = viewChild(AXPEntityMasterListDataTableComponent, ...(ngDevMode ? [{ debugName: "dataTable" }] : /* istanbul ignore next */ []));
1975
+ this.cardList = viewChild(AXPEntityMasterListCardListComponent, ...(ngDevMode ? [{ debugName: "cardList" }] : /* istanbul ignore next */ []));
1960
1976
  this.initializedFromRoute = false;
1961
1977
  this.lastEvaluatedViewName = null;
1962
1978
  this.componentDestroyed = new Subject();
@@ -2173,6 +2189,10 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
2173
2189
  await this.vm.ensureListPagingResolved();
2174
2190
  this.vm.applyPagingToDataSourceWithoutLoad();
2175
2191
  }
2192
+ if (this.vm.activeListLayout() === 'card') {
2193
+ await this.cardList()?.reload(resetPagination);
2194
+ return;
2195
+ }
2176
2196
  const grid = this.grid();
2177
2197
  if (grid) {
2178
2198
  await grid.refresh({ reset: resetPagination });
@@ -2310,7 +2330,7 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
2310
2330
  provide: AXPPageLayoutBase,
2311
2331
  useExisting: AXPEntityMasterListViewComponent,
2312
2332
  },
2313
- ], viewQueries: [{ propertyName: "dataTable", first: true, predicate: AXPEntityMasterListDataTableComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.entityDef.category) {\n <axp-layout-start-side id=\"axp-entity-category-drawer\">\n <axp-entity-category\n id=\"axp-entity-category\"\n class=\"ax-w-80\"\n [vm]=\"vm\"\n [searchValue]=\"categorySearchValue()\"\n ></axp-entity-category>\n </axp-layout-start-side>\n }\n <axp-page-toolbar id=\"axp-entity-toolbar\">\n <axp-entity-master-toolbar-view [viewModel]=\"vm\"></axp-entity-master-toolbar-view>\n </axp-page-toolbar>\n <axp-page-content class=\"ax-overflow-auto ax-pt-0\">\n <div\n class=\"ax-flex ax-items-center ax-justify-between ax-gap-1 ax-pb-1 ax-text-muted ax-text-sm\"\n [class.ax-invisible]=\"!vm.selectedItems().length\"\n >\n <span\n >{{ vm.selectedItems().length }}\n <span>{{ '@general:terms.interface.items-selected' | translate | async }}</span>\n </span>\n <ax-button text=\"@general:terms.interface.unselect-all\" class=\"ax-xs\" (onClick)=\"handleUnselectAll()\"></ax-button>\n </div>\n @if (vm.enabledListLayouts().includes('table')) {\n <axp-entity-master-list-data-table\n class=\"axp-entity-list-host\"\n [class.axp-entity-list-host--hidden]=\"vm.activeListLayout() !== 'table'\"\n [vm]=\"vm\"\n (pageChanged)=\"onListPageChanged()\"\n ></axp-entity-master-list-data-table>\n }\n @if (vm.enabledListLayouts().includes('card')) {\n <axp-entity-master-list-card-list\n class=\"axp-entity-list-host\"\n [class.axp-entity-list-host--hidden]=\"vm.activeListLayout() !== 'card'\"\n [vm]=\"vm\"\n (pageChanged)=\"onListPageChanged()\"\n ></axp-entity-master-list-card-list>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axp-entity-master-list axp-layout-start-side{min-width:20rem!important;border-inline-end-width:1px}axp-entity-master-list axp-layout-header{padding-bottom:.25rem!important}axp-entity-master-list .axp-entity-list-host{display:flex;height:100%;min-height:0px;flex-direction:column}axp-entity-master-list axp-page-content{display:flex;min-height:0px;flex-direction:column}axp-entity-master-list .axp-entity-list-host--hidden{display:none!important}.cdk-drag-preview{border-radius:.375rem;border-width:1px;--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background:rgba(var(--ax-color-on-surface));padding:.5rem;height:max-content!important}.collapsed-search-box{margin-top:0;height:0px;opacity:0}.view-drawer{width:85vw}@media(min-width:768px){.view-drawer{width:45vw}}@media(min-width:1024px){.view-drawer{width:35vw}}@media(min-width:1536px){.view-drawer{width:20vw}}.view-drawer{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lightest-surface),var(--tw-bg-opacity, 1));border-inline-start-width:1px;border-inline-start-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));border-top-width:1px;--tw-border-opacity: 1;border-top-color:rgba(var(--ax-sys-color-primary-600),var(--tw-border-opacity, 1))}.view-drawer ax-header{display:flex;align-items:center;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lighter-surface),var(--tw-bg-opacity, 1));padding:.5rem 1rem}.view-drawer ax-header h2{font-size:1.25rem;line-height:1.75rem;font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lighter-surface),var(--tw-text-opacity, 1))}.view-drawer ax-footer{position:absolute!important;bottom:0!important;width:100%!important;justify-content:flex-start!important;border-top-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1))!important;padding:.5rem 1rem!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXActionSheetModule }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "ngmodule", type: AXDialogModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: DragDropModule }, { kind: "ngmodule", type: AXPAuthModule }, { kind: "component", type: AXPEntityMasterToolbarViewComponent, selector: "axp-entity-master-toolbar-view", inputs: ["viewModel"] }, { 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: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPEntityCategoryComponent, selector: "axp-entity-category", inputs: ["vm", "searchValue", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "searchWithChildren"] }, { kind: "component", type: AXPEntityMasterListDataTableComponent, selector: "axp-entity-master-list-data-table", inputs: ["vm"], outputs: ["pageChanged"] }, { kind: "component", type: AXPEntityMasterListCardListComponent, selector: "axp-entity-master-list-card-list", inputs: ["vm"], outputs: ["pageChanged"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2333
+ ], viewQueries: [{ propertyName: "dataTable", first: true, predicate: AXPEntityMasterListDataTableComponent, descendants: true, isSignal: true }, { propertyName: "cardList", first: true, predicate: AXPEntityMasterListCardListComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.entityDef.category) {\n <axp-layout-start-side id=\"axp-entity-category-drawer\">\n <axp-entity-category\n id=\"axp-entity-category\"\n class=\"ax-w-80\"\n [vm]=\"vm\"\n [searchValue]=\"categorySearchValue()\"\n ></axp-entity-category>\n </axp-layout-start-side>\n }\n <axp-page-toolbar id=\"axp-entity-toolbar\">\n <axp-entity-master-toolbar-view [viewModel]=\"vm\"></axp-entity-master-toolbar-view>\n </axp-page-toolbar>\n <axp-page-content class=\"ax-overflow-auto ax-pt-0\">\n <div\n class=\"ax-flex ax-items-center ax-justify-between ax-gap-1 ax-pb-1 ax-text-muted ax-text-sm\"\n [class.ax-invisible]=\"!vm.selectedItems().length\"\n >\n <span\n >{{ vm.selectedItems().length }}\n <span>{{ '@general:terms.interface.items-selected' | translate | async }}</span>\n </span>\n <ax-button text=\"@general:terms.interface.unselect-all\" class=\"ax-xs\" (onClick)=\"handleUnselectAll()\"></ax-button>\n </div>\n @if (vm.enabledListLayouts().includes('table')) {\n <axp-entity-master-list-data-table\n class=\"axp-entity-list-host\"\n [class.axp-entity-list-host--hidden]=\"vm.activeListLayout() !== 'table'\"\n [vm]=\"vm\"\n (pageChanged)=\"onListPageChanged()\"\n ></axp-entity-master-list-data-table>\n }\n @if (vm.enabledListLayouts().includes('card')) {\n <axp-entity-master-list-card-list\n class=\"axp-entity-list-host\"\n [class.axp-entity-list-host--hidden]=\"vm.activeListLayout() !== 'card'\"\n [vm]=\"vm\"\n (pageChanged)=\"onListPageChanged()\"\n ></axp-entity-master-list-card-list>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axp-entity-master-list axp-layout-start-side{min-width:20rem!important;border-inline-end-width:1px}axp-entity-master-list axp-layout-header{padding-bottom:.25rem!important}axp-entity-master-list .axp-entity-list-host{display:flex;height:100%;min-height:0px;flex-direction:column}axp-entity-master-list axp-page-content{display:flex;min-height:0px;flex-direction:column}axp-entity-master-list .axp-entity-list-host--hidden{display:none!important}.cdk-drag-preview{border-radius:.375rem;border-width:1px;--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background:rgba(var(--ax-color-on-surface));padding:.5rem;height:max-content!important}.collapsed-search-box{margin-top:0;height:0px;opacity:0}.view-drawer{width:85vw}@media(min-width:768px){.view-drawer{width:45vw}}@media(min-width:1024px){.view-drawer{width:35vw}}@media(min-width:1536px){.view-drawer{width:20vw}}.view-drawer{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lightest-surface),var(--tw-bg-opacity, 1));border-inline-start-width:1px;border-inline-start-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));border-top-width:1px;--tw-border-opacity: 1;border-top-color:rgba(var(--ax-sys-color-primary-600),var(--tw-border-opacity, 1))}.view-drawer ax-header{display:flex;align-items:center;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lighter-surface),var(--tw-bg-opacity, 1));padding:.5rem 1rem}.view-drawer ax-header h2{font-size:1.25rem;line-height:1.75rem;font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lighter-surface),var(--tw-text-opacity, 1))}.view-drawer ax-footer{position:absolute!important;bottom:0!important;width:100%!important;justify-content:flex-start!important;border-top-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1))!important;padding:.5rem 1rem!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXActionSheetModule }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "ngmodule", type: AXDialogModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: DragDropModule }, { kind: "ngmodule", type: AXPAuthModule }, { kind: "component", type: AXPEntityMasterToolbarViewComponent, selector: "axp-entity-master-toolbar-view", inputs: ["viewModel"] }, { 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: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPEntityCategoryComponent, selector: "axp-entity-category", inputs: ["vm", "searchValue", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "searchWithChildren"] }, { kind: "component", type: AXPEntityMasterListDataTableComponent, selector: "axp-entity-master-list-data-table", inputs: ["vm"], outputs: ["pageChanged"] }, { kind: "component", type: AXPEntityMasterListCardListComponent, selector: "axp-entity-master-list-card-list", inputs: ["vm"], outputs: ["pageChanged"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2314
2334
  }
2315
2335
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityMasterListViewComponent, decorators: [{
2316
2336
  type: Component,
@@ -2349,7 +2369,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2349
2369
  useExisting: AXPEntityMasterListViewComponent,
2350
2370
  },
2351
2371
  ], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.entityDef.category) {\n <axp-layout-start-side id=\"axp-entity-category-drawer\">\n <axp-entity-category\n id=\"axp-entity-category\"\n class=\"ax-w-80\"\n [vm]=\"vm\"\n [searchValue]=\"categorySearchValue()\"\n ></axp-entity-category>\n </axp-layout-start-side>\n }\n <axp-page-toolbar id=\"axp-entity-toolbar\">\n <axp-entity-master-toolbar-view [viewModel]=\"vm\"></axp-entity-master-toolbar-view>\n </axp-page-toolbar>\n <axp-page-content class=\"ax-overflow-auto ax-pt-0\">\n <div\n class=\"ax-flex ax-items-center ax-justify-between ax-gap-1 ax-pb-1 ax-text-muted ax-text-sm\"\n [class.ax-invisible]=\"!vm.selectedItems().length\"\n >\n <span\n >{{ vm.selectedItems().length }}\n <span>{{ '@general:terms.interface.items-selected' | translate | async }}</span>\n </span>\n <ax-button text=\"@general:terms.interface.unselect-all\" class=\"ax-xs\" (onClick)=\"handleUnselectAll()\"></ax-button>\n </div>\n @if (vm.enabledListLayouts().includes('table')) {\n <axp-entity-master-list-data-table\n class=\"axp-entity-list-host\"\n [class.axp-entity-list-host--hidden]=\"vm.activeListLayout() !== 'table'\"\n [vm]=\"vm\"\n (pageChanged)=\"onListPageChanged()\"\n ></axp-entity-master-list-data-table>\n }\n @if (vm.enabledListLayouts().includes('card')) {\n <axp-entity-master-list-card-list\n class=\"axp-entity-list-host\"\n [class.axp-entity-list-host--hidden]=\"vm.activeListLayout() !== 'card'\"\n [vm]=\"vm\"\n (pageChanged)=\"onListPageChanged()\"\n ></axp-entity-master-list-card-list>\n }\n </axp-page-content>\n</axp-page-layout>\n", styles: ["axp-entity-master-list axp-layout-start-side{min-width:20rem!important;border-inline-end-width:1px}axp-entity-master-list axp-layout-header{padding-bottom:.25rem!important}axp-entity-master-list .axp-entity-list-host{display:flex;height:100%;min-height:0px;flex-direction:column}axp-entity-master-list axp-page-content{display:flex;min-height:0px;flex-direction:column}axp-entity-master-list .axp-entity-list-host--hidden{display:none!important}.cdk-drag-preview{border-radius:.375rem;border-width:1px;--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background:rgba(var(--ax-color-on-surface));padding:.5rem;height:max-content!important}.collapsed-search-box{margin-top:0;height:0px;opacity:0}.view-drawer{width:85vw}@media(min-width:768px){.view-drawer{width:45vw}}@media(min-width:1024px){.view-drawer{width:35vw}}@media(min-width:1536px){.view-drawer{width:20vw}}.view-drawer{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lightest-surface),var(--tw-bg-opacity, 1));border-inline-start-width:1px;border-inline-start-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));border-top-width:1px;--tw-border-opacity: 1;border-top-color:rgba(var(--ax-sys-color-primary-600),var(--tw-border-opacity, 1))}.view-drawer ax-header{display:flex;align-items:center;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lighter-surface),var(--tw-bg-opacity, 1));padding:.5rem 1rem}.view-drawer ax-header h2{font-size:1.25rem;line-height:1.75rem;font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lighter-surface),var(--tw-text-opacity, 1))}.view-drawer ax-footer{position:absolute!important;bottom:0!important;width:100%!important;justify-content:flex-start!important;border-top-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1))!important;padding:.5rem 1rem!important}\n"] }]
2352
- }], ctorParameters: () => [{ type: i1$4.AXPlatform }], propDecorators: { dataTable: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPEntityMasterListDataTableComponent), { isSignal: true }] }] } });
2372
+ }], ctorParameters: () => [{ type: i1$4.AXPlatform }], propDecorators: { dataTable: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPEntityMasterListDataTableComponent), { isSignal: true }] }], cardList: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPEntityMasterListCardListComponent), { isSignal: true }] }] } });
2353
2373
 
2354
2374
  var entityMasterListView_component = /*#__PURE__*/Object.freeze({
2355
2375
  __proto__: null,
@@ -2369,6 +2389,433 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2369
2389
  ], template: "<div class=\"ax-flex ax-items-center ax-justify-start ax-gap-1\">\n <axp-component-slot name=\"root-footer-start\"></axp-component-slot>\n</div>\n<div class=\"ax-flex ax-items-center ax-justify-end ax-gap-1\">\n <axp-component-slot name=\"root-footer-end\"></axp-component-slot>\n</div>\n" }]
2370
2390
  }] });
2371
2391
 
2392
+ //#region ---- Types ----
2393
+ //#endregion
2394
+ //#region ---- Layout ----
2395
+ const DEFAULT_MIN_WIDTH_PX = 88;
2396
+ const DEFAULT_MAX_WIDTH_PX = 192;
2397
+ const DEFAULT_TAB_GAP_PX = 8;
2398
+ /**
2399
+ * Chrome-like tab strip layout: equal flexible widths between min/max; horizontal scroll when needed.
2400
+ */
2401
+ function computeRouteTabBarLayout(stripWidthPx, tabs, _activeKey, options = {}) {
2402
+ const minWidthPx = options.minWidthPx ?? DEFAULT_MIN_WIDTH_PX;
2403
+ const maxWidthPx = options.maxWidthPx ?? DEFAULT_MAX_WIDTH_PX;
2404
+ const tabGapPx = options.tabGapPx ?? DEFAULT_TAB_GAP_PX;
2405
+ if (stripWidthPx <= 0 || !tabs.length) {
2406
+ return {
2407
+ tabWidthPx: minWidthPx,
2408
+ isScrollable: false,
2409
+ };
2410
+ }
2411
+ const count = tabs.length;
2412
+ const gapsForAll = Math.max(0, count - 1) * tabGapPx;
2413
+ const rawWidth = (stripWidthPx - gapsForAll) / count;
2414
+ const fittedWidth = Math.min(maxWidthPx, Math.max(minWidthPx, rawWidth));
2415
+ const needsScroll = count * fittedWidth + gapsForAll > stripWidthPx;
2416
+ const tabWidthPx = needsScroll ? minWidthPx : Math.floor(fittedWidth);
2417
+ return {
2418
+ tabWidthPx,
2419
+ isScrollable: needsScroll,
2420
+ };
2421
+ }
2422
+ //#endregion
2423
+
2424
+ class AXPRouteTabBarComponent {
2425
+ constructor() {
2426
+ //#region ---- Services & Dependencies ----
2427
+ this.tabNavigation = inject(AXPTabNavigationService);
2428
+ this.tabPreviewService = inject(AXPTabPreviewService);
2429
+ this.translateService = inject(AXTranslationService);
2430
+ this.host = inject((ElementRef));
2431
+ this.tabStrip = viewChild('tabStrip', ...(ngDevMode ? [{ debugName: "tabStrip" }] : /* istanbul ignore next */ []));
2432
+ this.tabsScroll = viewChild('tabsScroll', ...(ngDevMode ? [{ debugName: "tabsScroll" }] : /* istanbul ignore next */ []));
2433
+ this.contextMenu = viewChild('tabContextMenu', ...(ngDevMode ? [{ debugName: "contextMenu" }] : /* istanbul ignore next */ []));
2434
+ this.suppressTabChange = signal(false, ...(ngDevMode ? [{ debugName: "suppressTabChange" }] : /* istanbul ignore next */ []));
2435
+ this.contextTabKey = signal(null, ...(ngDevMode ? [{ debugName: "contextTabKey" }] : /* istanbul ignore next */ []));
2436
+ this.stripWidthPx = signal(0, ...(ngDevMode ? [{ debugName: "stripWidthPx" }] : /* istanbul ignore next */ []));
2437
+ this.isTabDragging = signal(false, ...(ngDevMode ? [{ debugName: "isTabDragging" }] : /* istanbul ignore next */ []));
2438
+ this.inHeader = signal(false, ...(ngDevMode ? [{ debugName: "inHeader" }] : /* istanbul ignore next */ []));
2439
+ //#endregion
2440
+ //#region ---- Layout State ----
2441
+ this.layout = computed(() => computeRouteTabBarLayout(this.stripWidthPx(), this.tabNavigation.tabList(), this.tabNavigation.activeKey()), ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
2442
+ this.tabWidthPx = computed(() => this.layout().tabWidthPx, ...(ngDevMode ? [{ debugName: "tabWidthPx" }] : /* istanbul ignore next */ []));
2443
+ this.hasHorizontalOverflow = signal(false, ...(ngDevMode ? [{ debugName: "hasHorizontalOverflow" }] : /* istanbul ignore next */ []));
2444
+ this.canScrollForward = signal(false, ...(ngDevMode ? [{ debugName: "canScrollForward" }] : /* istanbul ignore next */ []));
2445
+ this.canScrollBackward = signal(false, ...(ngDevMode ? [{ debugName: "canScrollBackward" }] : /* istanbul ignore next */ []));
2446
+ this.scrollForwardIcon = computed(() => this.#isTabsRtl() ? 'fa-solid fa-chevron-left' : 'fa-solid fa-chevron-right', ...(ngDevMode ? [{ debugName: "scrollForwardIcon" }] : /* istanbul ignore next */ []));
2447
+ this.scrollBackwardIcon = computed(() => this.#isTabsRtl() ? 'fa-solid fa-chevron-right' : 'fa-solid fa-chevron-left', ...(ngDevMode ? [{ debugName: "scrollBackwardIcon" }] : /* istanbul ignore next */ []));
2448
+ this.isMiddlePanning = signal(false, ...(ngDevMode ? [{ debugName: "isMiddlePanning" }] : /* istanbul ignore next */ []));
2449
+ this.middlePanSession = null;
2450
+ this.middlePanMoved = false;
2451
+ //#endregion
2452
+ //#region ---- Layout Helpers ----
2453
+ this.#onTabsScroll = () => {
2454
+ this.#updateScrollState();
2455
+ };
2456
+ this.#onMiddlePanMove = (event) => {
2457
+ const session = this.middlePanSession;
2458
+ if (!session) {
2459
+ return;
2460
+ }
2461
+ const deltaX = event.clientX - session.lastX;
2462
+ session.lastX = event.clientX;
2463
+ if (Math.abs(event.clientX - session.startX) > 2) {
2464
+ session.moved = true;
2465
+ }
2466
+ session.container.scrollBy({ left: -deltaX });
2467
+ this.#updateScrollState();
2468
+ };
2469
+ this.#onMiddlePanUp = (event) => {
2470
+ if (event.button !== 1 && event.buttons !== 0) {
2471
+ return;
2472
+ }
2473
+ this.#endMiddlePan();
2474
+ };
2475
+ //#endregion
2476
+ //#region ---- Tab Strip Sync ----
2477
+ /** Scrolls the active tab into view when the strip overflows horizontally. */
2478
+ this.#scrollActiveTabIntoView = effect(() => {
2479
+ const activeKey = this.tabNavigation.activeKey();
2480
+ const tabs = this.tabNavigation.tabList();
2481
+ this.tabWidthPx();
2482
+ this.stripWidthPx();
2483
+ if (!activeKey || !tabs.length) {
2484
+ return;
2485
+ }
2486
+ untracked(() => {
2487
+ queueMicrotask(() => {
2488
+ this.#updateScrollState();
2489
+ this.#scrollTabIntoView(activeKey);
2490
+ });
2491
+ });
2492
+ }, ...(ngDevMode ? [{ debugName: "#scrollActiveTabIntoView" }] : /* istanbul ignore next */ []));
2493
+ }
2494
+ //#endregion
2495
+ //#region ---- Lifecycle Methods ----
2496
+ ngAfterViewInit() {
2497
+ this.inHeader.set(this.host.nativeElement.classList.contains('axp-route-tab-bar--in-header'));
2498
+ const strip = this.tabStrip()?.nativeElement;
2499
+ if (!strip) {
2500
+ return;
2501
+ }
2502
+ this.stripWidthPx.set(strip.clientWidth);
2503
+ this.stripResizeObserver = new ResizeObserver(() => {
2504
+ this.stripWidthPx.set(strip.clientWidth);
2505
+ this.#updateScrollState();
2506
+ });
2507
+ this.stripResizeObserver.observe(strip);
2508
+ const scrollElement = this.tabsScroll()?.nativeElement;
2509
+ if (scrollElement) {
2510
+ this.tabsScrollElement = scrollElement;
2511
+ scrollElement.addEventListener('scroll', this.#onTabsScroll, { passive: true });
2512
+ this.tabsScrollObserver = new ResizeObserver(() => {
2513
+ this.#updateScrollState();
2514
+ });
2515
+ this.tabsScrollObserver.observe(scrollElement);
2516
+ const tabList = scrollElement.querySelector('.axp-route-tab-bar__tab-list');
2517
+ if (tabList) {
2518
+ this.tabsScrollObserver.observe(tabList);
2519
+ }
2520
+ }
2521
+ this.#updateScrollState();
2522
+ }
2523
+ ngOnDestroy() {
2524
+ this.#endMiddlePan();
2525
+ this.tabsScrollElement?.removeEventListener('scroll', this.#onTabsScroll);
2526
+ this.stripResizeObserver?.disconnect();
2527
+ this.tabsScrollObserver?.disconnect();
2528
+ }
2529
+ //#endregion
2530
+ //#region ---- Layout Helpers ----
2531
+ #onTabsScroll;
2532
+ /** Updates overflow and edge scroll affordances from the live tab strip. */
2533
+ #updateScrollState() {
2534
+ const tabsElement = this.#getTabsScrollElement();
2535
+ if (!tabsElement) {
2536
+ this.hasHorizontalOverflow.set(false);
2537
+ this.canScrollForward.set(false);
2538
+ this.canScrollBackward.set(false);
2539
+ return;
2540
+ }
2541
+ const hasOverflow = tabsElement.scrollWidth - tabsElement.clientWidth > 1;
2542
+ this.hasHorizontalOverflow.set(hasOverflow);
2543
+ if (!hasOverflow) {
2544
+ this.canScrollForward.set(false);
2545
+ this.canScrollBackward.set(false);
2546
+ return;
2547
+ }
2548
+ this.canScrollForward.set(!!this.#findScrollTarget(tabsElement, 'forward'));
2549
+ this.canScrollBackward.set(!!this.#findScrollTarget(tabsElement, 'backward'));
2550
+ }
2551
+ #getTabsScrollElement() {
2552
+ return this.tabsScrollElement ?? this.tabsScroll()?.nativeElement ?? null;
2553
+ }
2554
+ #isTabsRtl() {
2555
+ const tabsElement = this.#getTabsScrollElement();
2556
+ if (!tabsElement) {
2557
+ return false;
2558
+ }
2559
+ return getComputedStyle(tabsElement).direction === 'rtl';
2560
+ }
2561
+ #findScrollTarget(container, direction) {
2562
+ const tabs = Array.from(container.querySelectorAll('[data-tab-key]'));
2563
+ if (!tabs.length) {
2564
+ return null;
2565
+ }
2566
+ const bounds = container.getBoundingClientRect();
2567
+ const epsilon = 2;
2568
+ const isRtl = this.#isTabsRtl();
2569
+ if (direction === 'forward') {
2570
+ if (!isRtl) {
2571
+ return tabs.find((tab) => tab.getBoundingClientRect().right > bounds.right + epsilon) ?? null;
2572
+ }
2573
+ return [...tabs].reverse().find((tab) => tab.getBoundingClientRect().left < bounds.left - epsilon) ?? null;
2574
+ }
2575
+ if (!isRtl) {
2576
+ return [...tabs].reverse().find((tab) => tab.getBoundingClientRect().left < bounds.left - epsilon) ?? null;
2577
+ }
2578
+ return tabs.find((tab) => tab.getBoundingClientRect().right > bounds.right + epsilon) ?? null;
2579
+ }
2580
+ /** Scrolls the strip toward hidden tabs on the requested edge. */
2581
+ scrollTabs(direction) {
2582
+ const container = this.#getTabsScrollElement();
2583
+ if (!container) {
2584
+ return;
2585
+ }
2586
+ const target = this.#findScrollTarget(container, direction);
2587
+ target?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
2588
+ }
2589
+ /** Smoothly brings a tab header into view inside the scrollable strip. */
2590
+ #scrollTabIntoView(key) {
2591
+ const scrollElement = this.#getTabsScrollElement();
2592
+ const activeTab = scrollElement?.querySelector(`[data-tab-key="${key}"]`);
2593
+ activeTab?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
2594
+ }
2595
+ /** Starts middle-mouse drag scrolling on the tab strip. */
2596
+ onTabsScrollMouseDown(event) {
2597
+ if (event.button !== 1) {
2598
+ return;
2599
+ }
2600
+ if (event.target.closest('.axp-route-tab-bar__close')) {
2601
+ return;
2602
+ }
2603
+ const container = this.#getTabsScrollElement();
2604
+ if (!container) {
2605
+ return;
2606
+ }
2607
+ event.preventDefault();
2608
+ this.middlePanSession = {
2609
+ container,
2610
+ startX: event.clientX,
2611
+ lastX: event.clientX,
2612
+ moved: false,
2613
+ };
2614
+ this.isMiddlePanning.set(true);
2615
+ document.body.style.cursor = 'grabbing';
2616
+ window.addEventListener('mousemove', this.#onMiddlePanMove);
2617
+ window.addEventListener('mouseup', this.#onMiddlePanUp);
2618
+ }
2619
+ #onMiddlePanMove;
2620
+ #onMiddlePanUp;
2621
+ #endMiddlePan() {
2622
+ window.removeEventListener('mousemove', this.#onMiddlePanMove);
2623
+ window.removeEventListener('mouseup', this.#onMiddlePanUp);
2624
+ document.body.style.cursor = '';
2625
+ this.isMiddlePanning.set(false);
2626
+ this.middlePanMoved = this.middlePanSession?.moved ?? false;
2627
+ this.middlePanSession = null;
2628
+ }
2629
+ //#endregion
2630
+ //#region ---- UI Handlers ----
2631
+ /** Whether a tab can be dragged (home tab stays fixed at the start). */
2632
+ isTabDragDisabled(tab) {
2633
+ return tab.key === AXP_HOME_TAB_KEY;
2634
+ }
2635
+ onTabDragStarted() {
2636
+ this.isTabDragging.set(true);
2637
+ }
2638
+ onTabDragEnded() {
2639
+ queueMicrotask(() => {
2640
+ this.isTabDragging.set(false);
2641
+ });
2642
+ }
2643
+ onTabDropped(event) {
2644
+ this.tabNavigation.reorderTabs(event.previousIndex, event.currentIndex);
2645
+ }
2646
+ async onTabActivate(tab, event) {
2647
+ if (this.isTabDragging() || this.suppressTabChange()) {
2648
+ return;
2649
+ }
2650
+ if (event.defaultPrevented) {
2651
+ return;
2652
+ }
2653
+ this.#scrollTabIntoView(tab.key);
2654
+ if (tab.key === this.tabNavigation.activeKey()) {
2655
+ return;
2656
+ }
2657
+ await this.tabNavigation.activateTabKey(tab.key);
2658
+ }
2659
+ /** Resolves tab metadata for context menu actions. */
2660
+ findTab(key) {
2661
+ return this.tabNavigation.tabList().find((item) => item.key === key);
2662
+ }
2663
+ /** Normalizes menu/page icon classes for `ax-icon`. */
2664
+ resolveTabIcon(tab) {
2665
+ const icon = tab.icon?.trim();
2666
+ if (!icon) {
2667
+ return 'fa-light fa-window';
2668
+ }
2669
+ if (icon.includes(' ')) {
2670
+ return icon;
2671
+ }
2672
+ return `fa-light ${icon}`;
2673
+ }
2674
+ /** Closes a tab when the close button is clicked. */
2675
+ async onTabCloseClick(tab, event) {
2676
+ if (!tab.closable || tab.pinned) {
2677
+ return;
2678
+ }
2679
+ event.preventDefault();
2680
+ event.stopPropagation();
2681
+ this.suppressTabChange.set(true);
2682
+ try {
2683
+ await this.tabNavigation.closeTab(tab.key);
2684
+ }
2685
+ finally {
2686
+ this.suppressTabChange.set(false);
2687
+ }
2688
+ }
2689
+ /** Closes a tab on middle mouse button click (browser-style). */
2690
+ async onTabMiddleClick(tab, event) {
2691
+ if (this.middlePanMoved) {
2692
+ this.middlePanMoved = false;
2693
+ event.preventDefault();
2694
+ event.stopPropagation();
2695
+ return;
2696
+ }
2697
+ if (event.button !== 1 || !tab.closable || tab.pinned) {
2698
+ return;
2699
+ }
2700
+ event.preventDefault();
2701
+ event.stopPropagation();
2702
+ this.suppressTabChange.set(true);
2703
+ try {
2704
+ await this.tabNavigation.closeTab(tab.key);
2705
+ }
2706
+ finally {
2707
+ this.suppressTabChange.set(false);
2708
+ }
2709
+ }
2710
+ async openTabContextMenu(event, key) {
2711
+ event.preventDefault();
2712
+ event.stopPropagation();
2713
+ this.contextTabKey.set(key);
2714
+ const tab = this.findTab(key);
2715
+ const isHomeTab = key === AXP_HOME_TAB_KEY;
2716
+ const closableTabs = this.tabNavigation.tabList().filter((item) => item.closable && !item.pinned);
2717
+ const otherClosableCount = closableTabs.filter((item) => item.key !== key).length;
2718
+ const canCloseTab = !!tab?.closable && !tab.pinned;
2719
+ const [pinText, unpinText, closeText, closeOthersText, closeAllText] = await Promise.all([
2720
+ this.translateService.translateAsync('@general:actions.pin-tab.title'),
2721
+ this.translateService.translateAsync('@general:actions.unpin-tab.title'),
2722
+ this.translateService.translateAsync('@general:actions.close-tab.title'),
2723
+ this.translateService.translateAsync('@general:actions.close-other-tabs.title'),
2724
+ this.translateService.translateAsync('@general:actions.close-all-tabs.title'),
2725
+ ]);
2726
+ const items = [
2727
+ {
2728
+ name: 'toggle-pin',
2729
+ text: tab?.pinned ? unpinText : pinText,
2730
+ icon: tab?.pinned ? 'fa-light fa-thumbtack-slash' : 'fa-light fa-thumbtack',
2731
+ disabled: isHomeTab,
2732
+ },
2733
+ {
2734
+ name: 'close',
2735
+ text: closeText,
2736
+ icon: 'fa-light fa-xmark',
2737
+ disabled: !canCloseTab,
2738
+ break: true,
2739
+ },
2740
+ {
2741
+ name: 'close-others',
2742
+ text: closeOthersText,
2743
+ icon: 'fa-light fa-clone',
2744
+ disabled: otherClosableCount === 0,
2745
+ break: true,
2746
+ },
2747
+ {
2748
+ name: 'close-all',
2749
+ text: closeAllText,
2750
+ icon: 'fa-light fa-table-columns',
2751
+ disabled: closableTabs.length === 0,
2752
+ },
2753
+ ];
2754
+ const menu = this.contextMenu();
2755
+ const targetElement = event.currentTarget;
2756
+ if (!menu) {
2757
+ return;
2758
+ }
2759
+ const openingEvent = {
2760
+ sender: menu,
2761
+ canceled: false,
2762
+ targetElement,
2763
+ items,
2764
+ };
2765
+ menu.showAt({ x: event.clientX, y: event.clientY }, targetElement, openingEvent);
2766
+ }
2767
+ async handleTabContextMenuItemClick(event) {
2768
+ const key = this.contextTabKey();
2769
+ if (!key) {
2770
+ return;
2771
+ }
2772
+ const action = event.item.name;
2773
+ this.suppressTabChange.set(true);
2774
+ try {
2775
+ switch (action) {
2776
+ case 'toggle-pin':
2777
+ this.tabNavigation.toggleTabPinned(key);
2778
+ break;
2779
+ case 'close':
2780
+ await this.tabNavigation.closeTab(key);
2781
+ break;
2782
+ case 'close-others':
2783
+ await this.tabNavigation.closeOtherTabs(key);
2784
+ break;
2785
+ case 'close-all':
2786
+ await this.tabNavigation.closeAllTabs();
2787
+ break;
2788
+ }
2789
+ }
2790
+ finally {
2791
+ this.suppressTabChange.set(false);
2792
+ this.contextTabKey.set(null);
2793
+ }
2794
+ }
2795
+ //#endregion
2796
+ //#region ---- Tab Strip Sync ----
2797
+ /** Scrolls the active tab into view when the strip overflows horizontally. */
2798
+ #scrollActiveTabIntoView;
2799
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRouteTabBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2800
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPRouteTabBarComponent, isStandalone: true, selector: "axp-route-tab-bar", host: { properties: { "class.axp-route-tab-bar--scrollable": "hasHorizontalOverflow()" }, classAttribute: "axp-route-tab-bar" }, viewQueries: [{ propertyName: "tabStrip", first: true, predicate: ["tabStrip"], descendants: true, isSignal: true }, { propertyName: "tabsScroll", first: true, predicate: ["tabsScroll"], descendants: true, isSignal: true }, { propertyName: "contextMenu", first: true, predicate: ["tabContextMenu"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (tabNavigation.isTabBarVisible()) {\n <div class=\"axp-route-tab-bar__strip\" #tabStrip [style.--axp-tab-width.px]=\"tabWidthPx()\">\n <div class=\"axp-route-tab-bar__viewport\">\n @if (canScrollBackward()) {\n <div class=\"axp-route-tab-bar__scroll-rail axp-route-tab-bar__scroll-rail--start\">\n <button\n type=\"button\"\n class=\"axp-route-tab-bar__scroll-btn\"\n [title]=\"'@general:actions.scroll-tabs-back.title' | translate | async\"\n [attr.aria-label]=\"'@general:actions.scroll-tabs-back.title' | translate | async\"\n (click)=\"scrollTabs('backward')\"\n >\n <ax-icon [icon]=\"scrollBackwardIcon()\"></ax-icon>\n </button>\n </div>\n }\n\n <div\n class=\"axp-route-tab-bar__scroll-wrap\"\n [class.axp-route-tab-bar__scroll-wrap--overflow-start]=\"canScrollBackward()\"\n [class.axp-route-tab-bar__scroll-wrap--overflow-end]=\"canScrollForward()\"\n >\n <div\n #tabsScroll\n class=\"axp-route-tab-bar__scroll\"\n [class.axp-route-tab-bar__scroll--panning]=\"isMiddlePanning()\"\n (mousedown)=\"onTabsScrollMouseDown($event)\"\n >\n <div\n class=\"axp-route-tab-bar__tab-list\"\n cdkDropList\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"tabNavigation.tabList()\"\n (cdkDropListDropped)=\"onTabDropped($event)\"\n >\n @for (tab of tabNavigation.tabList(); track tab.key) {\n @let tabTitle = (tab.title | translate | async) || '';\n <div\n class=\"axp-route-tab-bar__tab\"\n [class.axp-route-tab-bar__tab--active]=\"tabNavigation.activeKey() === tab.key\"\n [class.axp-route-tab-bar__tab--dragging]=\"isTabDragging()\"\n [attr.data-tab-key]=\"tab.key\"\n role=\"tab\"\n [attr.aria-selected]=\"tabNavigation.activeKey() === tab.key\"\n cdkDrag\n cdkDragLockAxis=\"x\"\n [cdkDragData]=\"tab\"\n [cdkDragDisabled]=\"isTabDragDisabled(tab)\"\n (cdkDragStarted)=\"onTabDragStarted()\"\n (cdkDragEnded)=\"onTabDragEnded()\"\n (click)=\"onTabActivate(tab, $event)\"\n >\n <div\n class=\"axp-route-tab-bar__tab-inner\"\n cdkDragHandle\n [title]=\"tabTitle\"\n (contextmenu)=\"openTabContextMenu($event, tab.key)\"\n (auxclick)=\"onTabMiddleClick(tab, $event)\"\n >\n @if (tabPreviewService.previews()[tab.key]?.isDirty) {\n <span\n class=\"axp-route-tab-bar__dirty-badge\"\n [attr.aria-label]=\"'@general:terms.interface.save-status.not-saved.title' | translate | async\"\n ></span>\n }\n\n <span class=\"axp-route-tab-bar__tab-icon\" aria-hidden=\"true\">\n <ax-icon [icon]=\"resolveTabIcon(tab)\"></ax-icon>\n </span>\n\n <span class=\"axp-route-tab-bar__tab-title-fade\" axpRouteTabTitleOverflow>\n <span class=\"axp-route-tab-bar__tab-title\">{{ tabTitle }}</span>\n </span>\n\n @if (tab.pinned) {\n <span class=\"axp-route-tab-bar__pin\" aria-hidden=\"true\">\n <ax-icon icon=\"fa-solid fa-thumbtack\"></ax-icon>\n </span>\n } @else if (tab.closable) {\n <button\n type=\"button\"\n class=\"axp-route-tab-bar__close\"\n [title]=\"'@general:actions.close-tab.title' | translate | async\"\n (click)=\"onTabCloseClick(tab, $event)\"\n >\n <ax-icon icon=\"far fa-xmark\"></ax-icon>\n </button>\n }\n </div>\n\n <ng-template cdkDragPreview>\n <div\n class=\"axp-route-tab-bar__drag-preview\"\n [class.axp-route-tab-bar__drag-preview--in-header]=\"inHeader()\"\n [class.axp-route-tab-bar__drag-preview--active]=\"tabNavigation.activeKey() === tab.key\"\n [style.width.px]=\"tabWidthPx()\"\n >\n <div class=\"axp-route-tab-bar__drag-preview-inner\">\n <span class=\"axp-route-tab-bar__tab-icon\" aria-hidden=\"true\">\n <ax-icon [icon]=\"resolveTabIcon(tab)\"></ax-icon>\n </span>\n <span class=\"axp-route-tab-bar__tab-title\">{{ tabTitle }}</span>\n </div>\n </div>\n </ng-template>\n </div>\n }\n </div>\n </div>\n </div>\n\n @if (canScrollForward()) {\n <div class=\"axp-route-tab-bar__scroll-rail axp-route-tab-bar__scroll-rail--end\">\n <button\n type=\"button\"\n class=\"axp-route-tab-bar__scroll-btn\"\n [title]=\"'@general:actions.scroll-tabs-forward.title' | translate | async\"\n [attr.aria-label]=\"'@general:actions.scroll-tabs-forward.title' | translate | async\"\n (click)=\"scrollTabs('forward')\"\n >\n <ax-icon [icon]=\"scrollForwardIcon()\"></ax-icon>\n </button>\n </div>\n }\n </div>\n </div>\n}\n\n<ax-context-menu\n #tabContextMenu\n [closeOn]=\"'click'\"\n [orientation]=\"'vertical'\"\n (onItemClick)=\"handleTabContextMenuItemClick($event)\"\n></ax-context-menu>\n", styles: ["axp-route-tab-bar{display:block;min-width:0;--axp-route-tab-bar-fade: var(--ax-sys-color-lightest-surface);--axp-route-tab-bar-chevron-size: 2rem}axp-route-tab-bar .axp-route-tab-bar__strip{display:flex;align-items:stretch;gap:.5rem;min-width:0}axp-route-tab-bar .axp-route-tab-bar__viewport{display:flex;flex-direction:row;align-items:center;flex:1 1 auto;min-width:0;height:100%;gap:.25rem}axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs,axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs .ax-tabs-scroll-area,axp-route-tab-bar .axp-route-tab-bar__viewport .axp-route-tab-bar__tab-list{overflow:visible!important;scrollbar-width:none!important;-ms-overflow-style:none!important}axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs::-webkit-scrollbar,axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs .ax-tabs-scroll-area::-webkit-scrollbar,axp-route-tab-bar .axp-route-tab-bar__viewport .axp-route-tab-bar__tab-list::-webkit-scrollbar{display:none!important;width:0!important;height:0!important}axp-route-tab-bar .axp-route-tab-bar__scroll-rail{display:flex;flex:0 0 var(--axp-route-tab-bar-chevron-size);align-items:center;justify-content:center;align-self:center;width:var(--axp-route-tab-bar-chevron-size);min-width:var(--axp-route-tab-bar-chevron-size);height:var(--axp-route-tab-bar-tab-row-height, 100%)}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap{position:relative;flex:1 1 auto;min-width:0;height:100%;overflow:hidden}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-start:before,axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-end:after{content:\"\";position:absolute;inset-block:0;width:1.5rem;z-index:1;pointer-events:none}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-start:before{inset-inline-start:0;background:linear-gradient(to right,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-end:after{inset-inline-end:0;background:linear-gradient(to left,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}[dir=rtl] axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-start:before{background:linear-gradient(to left,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}[dir=rtl] axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-end:after{background:linear-gradient(to right,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}axp-route-tab-bar .axp-route-tab-bar__scroll{width:100%;min-width:0;height:100%;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;cursor:default;scrollbar-width:none!important;-ms-overflow-style:none!important}axp-route-tab-bar .axp-route-tab-bar__scroll::-webkit-scrollbar{display:none!important;width:0!important;height:0!important;background:transparent!important}axp-route-tab-bar .axp-route-tab-bar__scroll.axp-route-tab-bar__scroll--panning,axp-route-tab-bar .axp-route-tab-bar__scroll.axp-route-tab-bar__scroll--panning *{cursor:grabbing!important;-webkit-user-select:none;user-select:none}axp-route-tab-bar .axp-route-tab-bar__tabs-host{height:100%;min-width:0;width:max-content}axp-route-tab-bar .axp-route-tab-bar__tab-list{display:flex;flex:none;flex-wrap:nowrap;align-items:stretch;width:max-content;min-width:max-content;height:100%;gap:.5rem}axp-route-tab-bar .axp-route-tab-bar__tab{cursor:pointer;flex:0 0 var(--axp-tab-width, 5.5rem);width:var(--axp-tab-width, 5.5rem);min-width:var(--axp-tab-width, 5.5rem);max-width:var(--axp-tab-width, 5.5rem);height:100%;transform:translateY(0);transition:background-color .15s ease,color .15s ease,border-color .15s ease,transform .22s cubic-bezier(.4,0,.2,1)}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-disabled{cursor:pointer}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-dragging,axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-dragging .axp-route-tab-bar__tab-inner{cursor:grabbing}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-placeholder{opacity:.35}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-animating{transition:transform .22s cubic-bezier(.4,0,.2,1)}axp-route-tab-bar .axp-route-tab-bar__tab-list.cdk-drop-list-dragging .axp-route-tab-bar__tab:not(.cdk-drag-placeholder){transition:transform .22s cubic-bezier(.4,0,.2,1)}axp-route-tab-bar .axp-route-tab-bar__scroll-btn{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;margin:0;padding:0;border:none;background:transparent;color:inherit;cursor:pointer;opacity:.88;border-radius:var(--ax-sys-border-radius);transition:opacity .15s ease}axp-route-tab-bar .axp-route-tab-bar__scroll-btn ax-icon{font-size:.75rem}axp-route-tab-bar .axp-route-tab-bar__scroll-btn:hover{opacity:1}axp-route-tab-bar .axp-route-tab-bar__scroll-btn:focus-visible{opacity:1;outline:2px solid rgb(var(--ax-sys-color-primary-500));outline-offset:1px}axp-route-tab-bar .axp-route-tab-bar__tab-inner{position:relative;display:flex;justify-content:space-between;width:100%;align-items:center;gap:.375rem;min-width:0;max-width:100%;height:100%;padding-inline:.625rem;cursor:pointer}axp-route-tab-bar .axp-route-tab-bar__tab-inner.cdk-drag-handle{cursor:pointer}axp-route-tab-bar .axp-route-tab-bar__dirty-badge{position:absolute;top:.25rem;inset-inline-end:.25rem;width:.4375rem;height:.4375rem;border-radius:50%;background:rgb(var(--ax-sys-color-warning-500));border:1px solid rgb(var(--ax-sys-color-lightest-surface));pointer-events:none;z-index:1}axp-route-tab-bar .axp-route-tab-bar__tab-icon{display:inline-flex;flex-shrink:0}axp-route-tab-bar .axp-route-tab-bar__tab-icon ax-icon{font-size:.875rem}axp-route-tab-bar .axp-route-tab-bar__tab-title-fade{position:relative;flex:1 1 auto;min-width:0;max-width:100%;overflow:hidden}axp-route-tab-bar .axp-route-tab-bar__tab-title{display:block;width:100%;white-space:nowrap;overflow:hidden;font-size:.875rem;line-height:1.25rem}axp-route-tab-bar .axp-route-tab-bar__tab-title-fade--overflowing .axp-route-tab-bar__tab-title{-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 1.25rem),transparent 100%);mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 1.25rem),transparent 100%)}[dir=rtl] axp-route-tab-bar .axp-route-tab-bar__tab-title-fade--overflowing .axp-route-tab-bar__tab-title{-webkit-mask-image:linear-gradient(to left,#000 0,#000 calc(100% - 1.25rem),transparent 100%);mask-image:linear-gradient(to left,#000 0,#000 calc(100% - 1.25rem),transparent 100%)}axp-route-tab-bar .axp-route-tab-bar__pin{display:inline-flex;flex-shrink:0;color:inherit}axp-route-tab-bar .axp-route-tab-bar__pin ax-icon{font-size:.6875rem}axp-route-tab-bar .axp-route-tab-bar__close{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:0;height:1.25rem;margin:0;padding:0;overflow:hidden;border:none;background:transparent;color:inherit;border-radius:var(--ax-sys-border-radius);opacity:0;pointer-events:none;cursor:pointer;transition:opacity .15s ease,width .15s ease,background-color .15s ease}axp-route-tab-bar .axp-route-tab-bar__close ax-icon{font-size:.75rem}axp-route-tab-bar .axp-route-tab-bar__tab:hover .axp-route-tab-bar__close,axp-route-tab-bar .axp-route-tab-bar__close:focus-visible{width:1.25rem;opacity:.72;pointer-events:auto}axp-route-tab-bar .axp-route-tab-bar__close:hover{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-route-tab-bar:not(.axp-route-tab-bar--in-header){border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface))}axp-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__strip{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));padding-inline:.5rem}axp-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__tab{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-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__tab:hover:not(.axp-route-tab-bar__tab--active){background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}axp-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active{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-route-tab-bar.axp-route-tab-bar--in-header{align-self:stretch;height:100%;--axp-route-tab-bar-fade: var(--ax-sys-color-primary-surface);--axp-route-tab-bar-tab-row-height: 2.25rem}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__strip{display:flex;align-self:stretch;height:100%;align-items:stretch;background:transparent;color:rgb(var(--ax-sys-color-on-primary-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__viewport{align-items:flex-end}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll-rail{align-self:flex-end;margin-bottom:0}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll-wrap--overflow-start:before,axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll-wrap--overflow-end:after{inset-block-end:0;inset-block-start:auto;height:var(--axp-route-tab-bar-tab-row-height)}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll{cursor:default}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab-list{align-self:stretch;align-items:flex-end;min-height:0;padding-top:1rem}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab{align-self:center;padding:0;border-top-left-radius:.5rem;border-top-right-radius:.5rem;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:rgb(var(--ax-sys-color-primary-dark-surface));color:rgb(var(--ax-sys-color-on-primary-dark-surface));border-color:rgb(var(--ax-sys-color-border-primary-dark-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab ax-icon{color:inherit}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab:hover:not(.axp-route-tab-bar__tab--active){background-color:rgb(var(--ax-sys-color-primary-light-surface));color:rgb(var(--ax-sys-color-on-primary-light-surface));border-color:rgb(var(--ax-sys-color-border-primary-light-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active{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-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-primary-darkest-surface));color:rgb(var(--ax-sys-color-on-primary-darkest-surface));border-color:rgb(var(--ax-sys-color-border-primary-darkest-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab .axp-route-tab-bar__close:hover{background-color:rgb(var(--ax-sys-color-primary-light-surface));color:rgb(var(--ax-sys-color-on-primary-light-surface));border-color:rgb(var(--ax-sys-color-border-primary-light-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active .axp-route-tab-bar__close:hover{background-color:rgb(var(--ax-sys-color-primary-light-surface));color:rgb(var(--ax-sys-color-on-primary-light-surface));border-color:rgb(var(--ax-sys-color-border-primary-light-surface))}.cdk-drag-preview.axp-route-tab-bar__drag-preview{display:flex;align-items:center;box-sizing:border-box;height:var(--axp-route-tab-bar-tab-row-height, 2.25rem);opacity:.96;cursor:grabbing;box-shadow:0 4px 12px rgb(var(--ax-sys-color-dark)/.16),0 1px 3px rgb(var(--ax-sys-color-dark)/.12)}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__drag-preview-inner{display:flex;align-items:center;gap:.5rem;width:100%;min-width:0;height:100%;padding-inline:.625rem}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__tab-icon{display:inline-flex;flex-shrink:0}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__tab-icon ax-icon{font-size:.875rem}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__tab-title{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem}.cdk-drag-preview.axp-route-tab-bar__drag-preview.axp-route-tab-bar__drag-preview--in-header{border-top-left-radius:.5rem;border-top-right-radius:.5rem;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:rgb(var(--ax-sys-color-primary-dark-surface));color:rgb(var(--ax-sys-color-on-primary-dark-surface));border-color:rgb(var(--ax-sys-color-border-primary-dark-surface))}.cdk-drag-preview.axp-route-tab-bar__drag-preview.axp-route-tab-bar__drag-preview--in-header.axp-route-tab-bar__drag-preview--active{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))}.cdk-drag-preview.axp-route-tab-bar__drag-preview.axp-route-tab-bar__drag-preview--in-header.axp-route-tab-bar__drag-preview--active:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-primary-darkest-surface));color:rgb(var(--ax-sys-color-on-primary-darkest-surface));border-color:rgb(var(--ax-sys-color-border-primary-darkest-surface))}.cdk-drag-preview.axp-route-tab-bar__drag-preview:not(.axp-route-tab-bar__drag-preview--in-header){border-radius:.375rem;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))}.cdk-drag-preview.axp-route-tab-bar__drag-preview:not(.axp-route-tab-bar__drag-preview--in-header).axp-route-tab-bar__drag-preview--active{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))}\n"], dependencies: [{ kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXContextMenuComponent, selector: "ax-context-menu", inputs: ["orientation", "openOn", "closeOn", "closeOnRouteChange", "items", "target"], outputs: ["onItemClick", "onOpening", "onClose"] }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2801
+ }
2802
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRouteTabBarComponent, decorators: [{
2803
+ type: Component,
2804
+ args: [{ selector: 'axp-route-tab-bar', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
2805
+ class: 'axp-route-tab-bar',
2806
+ '[class.axp-route-tab-bar--scrollable]': 'hasHorizontalOverflow()',
2807
+ }, imports: [
2808
+ CdkDropList,
2809
+ CdkDrag,
2810
+ CdkDragHandle,
2811
+ CdkDragPreview,
2812
+ AXDecoratorModule,
2813
+ AXTranslationModule,
2814
+ AXContextMenuComponent,
2815
+ AsyncPipe,
2816
+ ], template: "@if (tabNavigation.isTabBarVisible()) {\n <div class=\"axp-route-tab-bar__strip\" #tabStrip [style.--axp-tab-width.px]=\"tabWidthPx()\">\n <div class=\"axp-route-tab-bar__viewport\">\n @if (canScrollBackward()) {\n <div class=\"axp-route-tab-bar__scroll-rail axp-route-tab-bar__scroll-rail--start\">\n <button\n type=\"button\"\n class=\"axp-route-tab-bar__scroll-btn\"\n [title]=\"'@general:actions.scroll-tabs-back.title' | translate | async\"\n [attr.aria-label]=\"'@general:actions.scroll-tabs-back.title' | translate | async\"\n (click)=\"scrollTabs('backward')\"\n >\n <ax-icon [icon]=\"scrollBackwardIcon()\"></ax-icon>\n </button>\n </div>\n }\n\n <div\n class=\"axp-route-tab-bar__scroll-wrap\"\n [class.axp-route-tab-bar__scroll-wrap--overflow-start]=\"canScrollBackward()\"\n [class.axp-route-tab-bar__scroll-wrap--overflow-end]=\"canScrollForward()\"\n >\n <div\n #tabsScroll\n class=\"axp-route-tab-bar__scroll\"\n [class.axp-route-tab-bar__scroll--panning]=\"isMiddlePanning()\"\n (mousedown)=\"onTabsScrollMouseDown($event)\"\n >\n <div\n class=\"axp-route-tab-bar__tab-list\"\n cdkDropList\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"tabNavigation.tabList()\"\n (cdkDropListDropped)=\"onTabDropped($event)\"\n >\n @for (tab of tabNavigation.tabList(); track tab.key) {\n @let tabTitle = (tab.title | translate | async) || '';\n <div\n class=\"axp-route-tab-bar__tab\"\n [class.axp-route-tab-bar__tab--active]=\"tabNavigation.activeKey() === tab.key\"\n [class.axp-route-tab-bar__tab--dragging]=\"isTabDragging()\"\n [attr.data-tab-key]=\"tab.key\"\n role=\"tab\"\n [attr.aria-selected]=\"tabNavigation.activeKey() === tab.key\"\n cdkDrag\n cdkDragLockAxis=\"x\"\n [cdkDragData]=\"tab\"\n [cdkDragDisabled]=\"isTabDragDisabled(tab)\"\n (cdkDragStarted)=\"onTabDragStarted()\"\n (cdkDragEnded)=\"onTabDragEnded()\"\n (click)=\"onTabActivate(tab, $event)\"\n >\n <div\n class=\"axp-route-tab-bar__tab-inner\"\n cdkDragHandle\n [title]=\"tabTitle\"\n (contextmenu)=\"openTabContextMenu($event, tab.key)\"\n (auxclick)=\"onTabMiddleClick(tab, $event)\"\n >\n @if (tabPreviewService.previews()[tab.key]?.isDirty) {\n <span\n class=\"axp-route-tab-bar__dirty-badge\"\n [attr.aria-label]=\"'@general:terms.interface.save-status.not-saved.title' | translate | async\"\n ></span>\n }\n\n <span class=\"axp-route-tab-bar__tab-icon\" aria-hidden=\"true\">\n <ax-icon [icon]=\"resolveTabIcon(tab)\"></ax-icon>\n </span>\n\n <span class=\"axp-route-tab-bar__tab-title-fade\" axpRouteTabTitleOverflow>\n <span class=\"axp-route-tab-bar__tab-title\">{{ tabTitle }}</span>\n </span>\n\n @if (tab.pinned) {\n <span class=\"axp-route-tab-bar__pin\" aria-hidden=\"true\">\n <ax-icon icon=\"fa-solid fa-thumbtack\"></ax-icon>\n </span>\n } @else if (tab.closable) {\n <button\n type=\"button\"\n class=\"axp-route-tab-bar__close\"\n [title]=\"'@general:actions.close-tab.title' | translate | async\"\n (click)=\"onTabCloseClick(tab, $event)\"\n >\n <ax-icon icon=\"far fa-xmark\"></ax-icon>\n </button>\n }\n </div>\n\n <ng-template cdkDragPreview>\n <div\n class=\"axp-route-tab-bar__drag-preview\"\n [class.axp-route-tab-bar__drag-preview--in-header]=\"inHeader()\"\n [class.axp-route-tab-bar__drag-preview--active]=\"tabNavigation.activeKey() === tab.key\"\n [style.width.px]=\"tabWidthPx()\"\n >\n <div class=\"axp-route-tab-bar__drag-preview-inner\">\n <span class=\"axp-route-tab-bar__tab-icon\" aria-hidden=\"true\">\n <ax-icon [icon]=\"resolveTabIcon(tab)\"></ax-icon>\n </span>\n <span class=\"axp-route-tab-bar__tab-title\">{{ tabTitle }}</span>\n </div>\n </div>\n </ng-template>\n </div>\n }\n </div>\n </div>\n </div>\n\n @if (canScrollForward()) {\n <div class=\"axp-route-tab-bar__scroll-rail axp-route-tab-bar__scroll-rail--end\">\n <button\n type=\"button\"\n class=\"axp-route-tab-bar__scroll-btn\"\n [title]=\"'@general:actions.scroll-tabs-forward.title' | translate | async\"\n [attr.aria-label]=\"'@general:actions.scroll-tabs-forward.title' | translate | async\"\n (click)=\"scrollTabs('forward')\"\n >\n <ax-icon [icon]=\"scrollForwardIcon()\"></ax-icon>\n </button>\n </div>\n }\n </div>\n </div>\n}\n\n<ax-context-menu\n #tabContextMenu\n [closeOn]=\"'click'\"\n [orientation]=\"'vertical'\"\n (onItemClick)=\"handleTabContextMenuItemClick($event)\"\n></ax-context-menu>\n", styles: ["axp-route-tab-bar{display:block;min-width:0;--axp-route-tab-bar-fade: var(--ax-sys-color-lightest-surface);--axp-route-tab-bar-chevron-size: 2rem}axp-route-tab-bar .axp-route-tab-bar__strip{display:flex;align-items:stretch;gap:.5rem;min-width:0}axp-route-tab-bar .axp-route-tab-bar__viewport{display:flex;flex-direction:row;align-items:center;flex:1 1 auto;min-width:0;height:100%;gap:.25rem}axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs,axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs .ax-tabs-scroll-area,axp-route-tab-bar .axp-route-tab-bar__viewport .axp-route-tab-bar__tab-list{overflow:visible!important;scrollbar-width:none!important;-ms-overflow-style:none!important}axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs::-webkit-scrollbar,axp-route-tab-bar .axp-route-tab-bar__viewport ax-tabs .ax-tabs-scroll-area::-webkit-scrollbar,axp-route-tab-bar .axp-route-tab-bar__viewport .axp-route-tab-bar__tab-list::-webkit-scrollbar{display:none!important;width:0!important;height:0!important}axp-route-tab-bar .axp-route-tab-bar__scroll-rail{display:flex;flex:0 0 var(--axp-route-tab-bar-chevron-size);align-items:center;justify-content:center;align-self:center;width:var(--axp-route-tab-bar-chevron-size);min-width:var(--axp-route-tab-bar-chevron-size);height:var(--axp-route-tab-bar-tab-row-height, 100%)}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap{position:relative;flex:1 1 auto;min-width:0;height:100%;overflow:hidden}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-start:before,axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-end:after{content:\"\";position:absolute;inset-block:0;width:1.5rem;z-index:1;pointer-events:none}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-start:before{inset-inline-start:0;background:linear-gradient(to right,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-end:after{inset-inline-end:0;background:linear-gradient(to left,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}[dir=rtl] axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-start:before{background:linear-gradient(to left,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}[dir=rtl] axp-route-tab-bar .axp-route-tab-bar__scroll-wrap--overflow-end:after{background:linear-gradient(to right,rgb(var(--axp-route-tab-bar-fade)) 0%,rgb(var(--axp-route-tab-bar-fade)/.72) 35%,transparent 100%)}axp-route-tab-bar .axp-route-tab-bar__scroll{width:100%;min-width:0;height:100%;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;cursor:default;scrollbar-width:none!important;-ms-overflow-style:none!important}axp-route-tab-bar .axp-route-tab-bar__scroll::-webkit-scrollbar{display:none!important;width:0!important;height:0!important;background:transparent!important}axp-route-tab-bar .axp-route-tab-bar__scroll.axp-route-tab-bar__scroll--panning,axp-route-tab-bar .axp-route-tab-bar__scroll.axp-route-tab-bar__scroll--panning *{cursor:grabbing!important;-webkit-user-select:none;user-select:none}axp-route-tab-bar .axp-route-tab-bar__tabs-host{height:100%;min-width:0;width:max-content}axp-route-tab-bar .axp-route-tab-bar__tab-list{display:flex;flex:none;flex-wrap:nowrap;align-items:stretch;width:max-content;min-width:max-content;height:100%;gap:.5rem}axp-route-tab-bar .axp-route-tab-bar__tab{cursor:pointer;flex:0 0 var(--axp-tab-width, 5.5rem);width:var(--axp-tab-width, 5.5rem);min-width:var(--axp-tab-width, 5.5rem);max-width:var(--axp-tab-width, 5.5rem);height:100%;transform:translateY(0);transition:background-color .15s ease,color .15s ease,border-color .15s ease,transform .22s cubic-bezier(.4,0,.2,1)}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-disabled{cursor:pointer}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-dragging,axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-dragging .axp-route-tab-bar__tab-inner{cursor:grabbing}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-placeholder{opacity:.35}axp-route-tab-bar .axp-route-tab-bar__tab.cdk-drag-animating{transition:transform .22s cubic-bezier(.4,0,.2,1)}axp-route-tab-bar .axp-route-tab-bar__tab-list.cdk-drop-list-dragging .axp-route-tab-bar__tab:not(.cdk-drag-placeholder){transition:transform .22s cubic-bezier(.4,0,.2,1)}axp-route-tab-bar .axp-route-tab-bar__scroll-btn{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;margin:0;padding:0;border:none;background:transparent;color:inherit;cursor:pointer;opacity:.88;border-radius:var(--ax-sys-border-radius);transition:opacity .15s ease}axp-route-tab-bar .axp-route-tab-bar__scroll-btn ax-icon{font-size:.75rem}axp-route-tab-bar .axp-route-tab-bar__scroll-btn:hover{opacity:1}axp-route-tab-bar .axp-route-tab-bar__scroll-btn:focus-visible{opacity:1;outline:2px solid rgb(var(--ax-sys-color-primary-500));outline-offset:1px}axp-route-tab-bar .axp-route-tab-bar__tab-inner{position:relative;display:flex;justify-content:space-between;width:100%;align-items:center;gap:.375rem;min-width:0;max-width:100%;height:100%;padding-inline:.625rem;cursor:pointer}axp-route-tab-bar .axp-route-tab-bar__tab-inner.cdk-drag-handle{cursor:pointer}axp-route-tab-bar .axp-route-tab-bar__dirty-badge{position:absolute;top:.25rem;inset-inline-end:.25rem;width:.4375rem;height:.4375rem;border-radius:50%;background:rgb(var(--ax-sys-color-warning-500));border:1px solid rgb(var(--ax-sys-color-lightest-surface));pointer-events:none;z-index:1}axp-route-tab-bar .axp-route-tab-bar__tab-icon{display:inline-flex;flex-shrink:0}axp-route-tab-bar .axp-route-tab-bar__tab-icon ax-icon{font-size:.875rem}axp-route-tab-bar .axp-route-tab-bar__tab-title-fade{position:relative;flex:1 1 auto;min-width:0;max-width:100%;overflow:hidden}axp-route-tab-bar .axp-route-tab-bar__tab-title{display:block;width:100%;white-space:nowrap;overflow:hidden;font-size:.875rem;line-height:1.25rem}axp-route-tab-bar .axp-route-tab-bar__tab-title-fade--overflowing .axp-route-tab-bar__tab-title{-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 1.25rem),transparent 100%);mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 1.25rem),transparent 100%)}[dir=rtl] axp-route-tab-bar .axp-route-tab-bar__tab-title-fade--overflowing .axp-route-tab-bar__tab-title{-webkit-mask-image:linear-gradient(to left,#000 0,#000 calc(100% - 1.25rem),transparent 100%);mask-image:linear-gradient(to left,#000 0,#000 calc(100% - 1.25rem),transparent 100%)}axp-route-tab-bar .axp-route-tab-bar__pin{display:inline-flex;flex-shrink:0;color:inherit}axp-route-tab-bar .axp-route-tab-bar__pin ax-icon{font-size:.6875rem}axp-route-tab-bar .axp-route-tab-bar__close{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:0;height:1.25rem;margin:0;padding:0;overflow:hidden;border:none;background:transparent;color:inherit;border-radius:var(--ax-sys-border-radius);opacity:0;pointer-events:none;cursor:pointer;transition:opacity .15s ease,width .15s ease,background-color .15s ease}axp-route-tab-bar .axp-route-tab-bar__close ax-icon{font-size:.75rem}axp-route-tab-bar .axp-route-tab-bar__tab:hover .axp-route-tab-bar__close,axp-route-tab-bar .axp-route-tab-bar__close:focus-visible{width:1.25rem;opacity:.72;pointer-events:auto}axp-route-tab-bar .axp-route-tab-bar__close:hover{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-route-tab-bar:not(.axp-route-tab-bar--in-header){border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface))}axp-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__strip{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));padding-inline:.5rem}axp-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__tab{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-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__tab:hover:not(.axp-route-tab-bar__tab--active){background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}axp-route-tab-bar:not(.axp-route-tab-bar--in-header) .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active{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-route-tab-bar.axp-route-tab-bar--in-header{align-self:stretch;height:100%;--axp-route-tab-bar-fade: var(--ax-sys-color-primary-surface);--axp-route-tab-bar-tab-row-height: 2.25rem}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__strip{display:flex;align-self:stretch;height:100%;align-items:stretch;background:transparent;color:rgb(var(--ax-sys-color-on-primary-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__viewport{align-items:flex-end}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll-rail{align-self:flex-end;margin-bottom:0}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll-wrap--overflow-start:before,axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll-wrap--overflow-end:after{inset-block-end:0;inset-block-start:auto;height:var(--axp-route-tab-bar-tab-row-height)}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__scroll{cursor:default}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab-list{align-self:stretch;align-items:flex-end;min-height:0;padding-top:1rem}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab{align-self:center;padding:0;border-top-left-radius:.5rem;border-top-right-radius:.5rem;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:rgb(var(--ax-sys-color-primary-dark-surface));color:rgb(var(--ax-sys-color-on-primary-dark-surface));border-color:rgb(var(--ax-sys-color-border-primary-dark-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab ax-icon{color:inherit}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab:hover:not(.axp-route-tab-bar__tab--active){background-color:rgb(var(--ax-sys-color-primary-light-surface));color:rgb(var(--ax-sys-color-on-primary-light-surface));border-color:rgb(var(--ax-sys-color-border-primary-light-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active{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-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-primary-darkest-surface));color:rgb(var(--ax-sys-color-on-primary-darkest-surface));border-color:rgb(var(--ax-sys-color-border-primary-darkest-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab .axp-route-tab-bar__close:hover{background-color:rgb(var(--ax-sys-color-primary-light-surface));color:rgb(var(--ax-sys-color-on-primary-light-surface));border-color:rgb(var(--ax-sys-color-border-primary-light-surface))}axp-route-tab-bar.axp-route-tab-bar--in-header .axp-route-tab-bar__tab.axp-route-tab-bar__tab--active .axp-route-tab-bar__close:hover{background-color:rgb(var(--ax-sys-color-primary-light-surface));color:rgb(var(--ax-sys-color-on-primary-light-surface));border-color:rgb(var(--ax-sys-color-border-primary-light-surface))}.cdk-drag-preview.axp-route-tab-bar__drag-preview{display:flex;align-items:center;box-sizing:border-box;height:var(--axp-route-tab-bar-tab-row-height, 2.25rem);opacity:.96;cursor:grabbing;box-shadow:0 4px 12px rgb(var(--ax-sys-color-dark)/.16),0 1px 3px rgb(var(--ax-sys-color-dark)/.12)}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__drag-preview-inner{display:flex;align-items:center;gap:.5rem;width:100%;min-width:0;height:100%;padding-inline:.625rem}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__tab-icon{display:inline-flex;flex-shrink:0}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__tab-icon ax-icon{font-size:.875rem}.cdk-drag-preview.axp-route-tab-bar__drag-preview .axp-route-tab-bar__tab-title{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem}.cdk-drag-preview.axp-route-tab-bar__drag-preview.axp-route-tab-bar__drag-preview--in-header{border-top-left-radius:.5rem;border-top-right-radius:.5rem;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:rgb(var(--ax-sys-color-primary-dark-surface));color:rgb(var(--ax-sys-color-on-primary-dark-surface));border-color:rgb(var(--ax-sys-color-border-primary-dark-surface))}.cdk-drag-preview.axp-route-tab-bar__drag-preview.axp-route-tab-bar__drag-preview--in-header.axp-route-tab-bar__drag-preview--active{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))}.cdk-drag-preview.axp-route-tab-bar__drag-preview.axp-route-tab-bar__drag-preview--in-header.axp-route-tab-bar__drag-preview--active:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-primary-darkest-surface));color:rgb(var(--ax-sys-color-on-primary-darkest-surface));border-color:rgb(var(--ax-sys-color-border-primary-darkest-surface))}.cdk-drag-preview.axp-route-tab-bar__drag-preview:not(.axp-route-tab-bar__drag-preview--in-header){border-radius:.375rem;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))}.cdk-drag-preview.axp-route-tab-bar__drag-preview:not(.axp-route-tab-bar__drag-preview--in-header).axp-route-tab-bar__drag-preview--active{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))}\n"] }]
2817
+ }], propDecorators: { tabStrip: [{ type: i0.ViewChild, args: ['tabStrip', { isSignal: true }] }], tabsScroll: [{ type: i0.ViewChild, args: ['tabsScroll', { isSignal: true }] }], contextMenu: [{ type: i0.ViewChild, args: ['tabContextMenu', { isSignal: true }] }] } });
2818
+
2372
2819
  class AXPRootLayoutHeaderComponent {
2373
2820
  //#endregion
2374
2821
  //#region ---- Lifecycle Methods ----
@@ -2379,6 +2826,7 @@ class AXPRootLayoutHeaderComponent {
2379
2826
  this.destroyRef = inject(DestroyRef);
2380
2827
  this.shortcutRegistry = inject(AXPKeyboardShortcutRegistry);
2381
2828
  this.store = inject(AXPLayoutThemeService);
2829
+ this.tabNavigation = inject(AXPTabNavigationService);
2382
2830
  this.logo = this.config.logo;
2383
2831
  this.shortcutRegistry.register({
2384
2832
  owner: this.destroyRef,
@@ -2406,15 +2854,13 @@ class AXPRootLayoutHeaderComponent {
2406
2854
  this.router.navigate(['/']);
2407
2855
  }
2408
2856
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRootLayoutHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2409
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPRootLayoutHeaderComponent, isStandalone: true, selector: "axp-dashboard-admin-header", host: { classAttribute: "ax-w-full ax-flex ax-items-center ax-justify-between ax-bg-primary-surface ax-text-primary-on-surface ax-h-14 ax-px-2 ax-light" }, ngImport: i0, template: "<ax-button id=\"axp-menu-toggle\" (onClick)=\"toggleSideMenu()\" color=\"primary\">\n <ax-icon class=\"rtl:ax-rotate-180\">\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 30 30\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n @if (store.isSideMenuOpen()) {\n <defs>\n <clipPath id=\"clip1382_20239\">\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1382_20239)\">\n <rect\n id=\"rect\"\n x=\"17.420410\"\n y=\"12.316406\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(137.159 17.420410 12.316406)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"12.959473\"\n y=\"13.728516\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(40.853 12.959473 13.728516)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.1 25.5L9.9 25.51C9.48 25.51 9.06 25.47 8.65 25.39C8.24 25.3 7.84 25.18 7.45 25.02C7.06 24.86 6.69 24.66 6.34 24.43C5.99 24.19 5.67 23.92 5.37 23.63C5.07 23.33 4.81 23 4.58 22.65C4.34 22.3 4.15 21.93 3.98 21.54C3.82 21.15 3.7 20.75 3.62 20.34C3.54 19.93 3.5 19.51 3.5 19.09L3.5 10.93C3.5 10.51 3.54 10.1 3.62 9.68C3.7 9.27 3.82 8.87 3.98 8.48C4.15 8.09 4.34 7.72 4.58 7.37C4.81 7.02 5.07 6.69 5.37 6.39C5.67 6.1 5.99 5.83 6.34 5.6C6.69 5.36 7.06 5.16 7.45 5C7.84 4.84 8.24 4.72 8.65 4.64C9.06 4.55 9.48 4.51 9.9 4.51L20.1 4.5C20.52 4.5 20.94 4.54 21.35 4.62C21.76 4.7 22.16 4.83 22.55 4.99C22.94 5.15 23.31 5.35 23.66 5.58C24 5.82 24.33 6.08 24.62 6.38C24.92 6.68 25.19 7 25.42 7.35C25.65 7.7 25.85 8.07 26.01 8.46C26.17 8.85 26.3 9.25 26.38 9.67C26.46 10.08 26.5 10.5 26.5 10.92L26.5 19.07C26.5 19.5 26.46 19.91 26.38 20.32C26.3 20.74 26.17 21.14 26.01 21.53C25.85 21.92 25.65 22.29 25.42 22.64C25.19 22.99 24.92 23.31 24.62 23.61C24.33 23.91 24 24.17 23.66 24.41C23.31 24.64 22.94 24.84 22.55 25C22.16 25.16 21.76 25.29 21.35 25.37C20.94 25.45 20.52 25.5 20.1 25.5ZM9.9 6.6C9.61 6.6 9.33 6.63 9.05 6.69C8.78 6.74 8.51 6.82 8.24 6.93C7.98 7.04 7.73 7.18 7.5 7.33C7.26 7.49 7.04 7.67 6.84 7.87C6.64 8.07 6.46 8.29 6.31 8.53C6.15 8.77 6.02 9.01 5.91 9.28C5.8 9.54 5.72 9.81 5.66 10.09C5.61 10.37 5.58 10.65 5.58 10.93L5.58 19.09C5.58 19.37 5.61 19.65 5.66 19.93C5.72 20.21 5.8 20.48 5.91 20.74C6.02 21.01 6.15 21.26 6.31 21.49C6.46 21.73 6.64 21.95 6.84 22.15C7.04 22.35 7.26 22.53 7.5 22.69C7.73 22.85 7.98 22.98 8.24 23.09C8.51 23.2 8.78 23.28 9.05 23.33C9.33 23.39 9.61 23.42 9.9 23.42L20.1 23.41C20.38 23.41 20.67 23.37 20.94 23.32C21.22 23.26 21.49 23.18 21.75 23.07C22.01 22.96 22.26 22.83 22.5 22.67C22.73 22.51 22.95 22.33 23.15 22.13C23.35 21.93 23.53 21.71 23.69 21.48C23.85 21.24 23.98 20.99 24.09 20.73C24.2 20.47 24.28 20.2 24.33 19.92C24.39 19.64 24.42 19.36 24.42 19.07L24.42 10.92C24.42 10.64 24.39 10.35 24.33 10.07C24.28 9.79 24.2 9.52 24.09 9.26C23.98 9 23.85 8.75 23.69 8.51C23.53 8.28 23.35 8.06 23.15 7.86C22.95 7.66 22.73 7.48 22.5 7.32C22.26 7.16 22.01 7.03 21.75 6.92C21.49 6.81 21.22 6.73 20.94 6.67C20.67 6.62 20.38 6.59 20.1 6.59L9.9 6.6Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.5 5.51L10.54 5.51L10.6 24.43L8.55 24.43L8.5 5.51Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n } @else {\n <defs>\n <clipPath id=\"clip1381_20236\">\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1381_20236)\">\n <rect\n id=\"rect\"\n x=\"11.572754\"\n y=\"17.683594\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(-42.841 11.572754 17.683594)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"16.033691\"\n y=\"16.271484\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(-139.147 16.033691 16.271484)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.09 25.48L9.89 25.5C9.47 25.5 9.05 25.45 8.64 25.37C8.23 25.29 7.83 25.17 7.44 25C7.05 24.84 6.68 24.64 6.33 24.41C5.98 24.18 5.66 23.91 5.36 23.61C5.07 23.31 4.8 22.99 4.57 22.64C4.34 22.29 4.14 21.92 3.98 21.53C3.82 21.14 3.69 20.74 3.61 20.32C3.53 19.91 3.49 19.49 3.49 19.07L3.49 10.92C3.49 10.5 3.53 10.08 3.61 9.67C3.69 9.25 3.82 8.85 3.98 8.46C4.14 8.07 4.34 7.7 4.57 7.35C4.8 7 5.07 6.68 5.36 6.38C5.66 6.08 5.98 5.81 6.33 5.58C6.68 5.35 7.05 5.15 7.44 4.99C7.83 4.82 8.23 4.7 8.64 4.62C9.05 4.54 9.47 4.5 9.89 4.5L20.09 4.48C20.51 4.48 20.93 4.52 21.34 4.6C21.75 4.69 22.15 4.81 22.54 4.97C22.93 5.13 23.3 5.33 23.65 5.57C24 5.8 24.32 6.06 24.62 6.36C24.92 6.66 25.18 6.98 25.41 7.33C25.65 7.69 25.84 8.06 26.01 8.45C26.17 8.84 26.29 9.24 26.37 9.65C26.45 10.06 26.49 10.48 26.5 10.91L26.5 19.06C26.49 19.48 26.45 19.89 26.37 20.31C26.29 20.72 26.17 21.12 26.01 21.51C25.84 21.9 25.65 22.27 25.41 22.62C25.18 22.97 24.92 23.3 24.62 23.6C24.32 23.89 24 24.16 23.65 24.39C23.3 24.63 22.93 24.83 22.54 24.99C22.15 25.15 21.75 25.27 21.34 25.35C20.93 25.44 20.51 25.48 20.09 25.48ZM9.89 6.59C9.61 6.59 9.32 6.62 9.05 6.67C8.77 6.73 8.5 6.81 8.24 6.92C7.98 7.03 7.73 7.16 7.49 7.32C7.26 7.48 7.04 7.66 6.84 7.86C6.64 8.06 6.46 8.28 6.3 8.51C6.14 8.75 6.01 9 5.9 9.26C5.79 9.52 5.71 9.8 5.66 10.07C5.6 10.35 5.57 10.63 5.57 10.92L5.57 19.07C5.57 19.36 5.6 19.64 5.66 19.92C5.71 20.19 5.79 20.47 5.9 20.73C6.01 20.99 6.14 21.24 6.3 21.48C6.46 21.71 6.64 21.93 6.84 22.13C7.04 22.33 7.26 22.51 7.49 22.67C7.73 22.83 7.98 22.96 8.24 23.07C8.5 23.18 8.77 23.26 9.05 23.32C9.32 23.37 9.61 23.4 9.89 23.4L20.09 23.39C20.38 23.39 20.66 23.36 20.94 23.3C21.21 23.25 21.48 23.17 21.75 23.06C22.01 22.95 22.26 22.81 22.49 22.66C22.73 22.5 22.95 22.32 23.15 22.12C23.35 21.91 23.52 21.7 23.68 21.46C23.84 21.22 23.97 20.98 24.08 20.71C24.19 20.45 24.27 20.18 24.33 19.9C24.38 19.62 24.41 19.34 24.41 19.06L24.41 10.91C24.41 10.62 24.38 10.34 24.33 10.06C24.27 9.78 24.19 9.51 24.08 9.25C23.97 8.98 23.84 8.74 23.68 8.5C23.52 8.26 23.35 8.04 23.15 7.84C22.95 7.64 22.73 7.46 22.49 7.3C22.26 7.15 22.01 7.01 21.75 6.9C21.48 6.79 21.21 6.71 20.94 6.66C20.66 6.6 20.38 6.57 20.09 6.57L9.89 6.59Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.49 5.5L10.53 5.5L10.59 24.41L8.54 24.41L8.49 5.5Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n }\n </svg>\n </ax-icon>\n</ax-button>\n<div class=\"ax-flex ax-items-center ax-gap-1 ax-justify-between ax-w-full\">\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <axp-component-slot name=\"root-header-start\"></axp-component-slot>\n </div>\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <axp-component-slot name=\"root-header-end\"></axp-component-slot>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "directive", type: i1$5.AXPComponentSlotDirective, selector: "axp-component-slot", inputs: ["name", "host", "context"], exportAs: ["slot"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2857
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPRootLayoutHeaderComponent, isStandalone: true, selector: "axp-dashboard-admin-header", host: { classAttribute: "ax-w-full ax-flex ax-min-w-0 ax-items-center ax-gap-2 ax-bg-primary-surface ax-text-primary-on-surface ax-h-14 ax-px-2 ax-light" }, ngImport: i0, template: "<ax-button id=\"axp-menu-toggle\" (onClick)=\"toggleSideMenu()\" color=\"primary\">\n <ax-icon class=\"rtl:ax-rotate-180\">\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 30 30\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n @if (store.isSideMenuOpen()) {\n <defs>\n <clipPath id=\"clip1382_20239\">\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1382_20239)\">\n <rect\n id=\"rect\"\n x=\"17.420410\"\n y=\"12.316406\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(137.159 17.420410 12.316406)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"12.959473\"\n y=\"13.728516\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(40.853 12.959473 13.728516)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.1 25.5L9.9 25.51C9.48 25.51 9.06 25.47 8.65 25.39C8.24 25.3 7.84 25.18 7.45 25.02C7.06 24.86 6.69 24.66 6.34 24.43C5.99 24.19 5.67 23.92 5.37 23.63C5.07 23.33 4.81 23 4.58 22.65C4.34 22.3 4.15 21.93 3.98 21.54C3.82 21.15 3.7 20.75 3.62 20.34C3.54 19.93 3.5 19.51 3.5 19.09L3.5 10.93C3.5 10.51 3.54 10.1 3.62 9.68C3.7 9.27 3.82 8.87 3.98 8.48C4.15 8.09 4.34 7.72 4.58 7.37C4.81 7.02 5.07 6.69 5.37 6.39C5.67 6.1 5.99 5.83 6.34 5.6C6.69 5.36 7.06 5.16 7.45 5C7.84 4.84 8.24 4.72 8.65 4.64C9.06 4.55 9.48 4.51 9.9 4.51L20.1 4.5C20.52 4.5 20.94 4.54 21.35 4.62C21.76 4.7 22.16 4.83 22.55 4.99C22.94 5.15 23.31 5.35 23.66 5.58C24 5.82 24.33 6.08 24.62 6.38C24.92 6.68 25.19 7 25.42 7.35C25.65 7.7 25.85 8.07 26.01 8.46C26.17 8.85 26.3 9.25 26.38 9.67C26.46 10.08 26.5 10.5 26.5 10.92L26.5 19.07C26.5 19.5 26.46 19.91 26.38 20.32C26.3 20.74 26.17 21.14 26.01 21.53C25.85 21.92 25.65 22.29 25.42 22.64C25.19 22.99 24.92 23.31 24.62 23.61C24.33 23.91 24 24.17 23.66 24.41C23.31 24.64 22.94 24.84 22.55 25C22.16 25.16 21.76 25.29 21.35 25.37C20.94 25.45 20.52 25.5 20.1 25.5ZM9.9 6.6C9.61 6.6 9.33 6.63 9.05 6.69C8.78 6.74 8.51 6.82 8.24 6.93C7.98 7.04 7.73 7.18 7.5 7.33C7.26 7.49 7.04 7.67 6.84 7.87C6.64 8.07 6.46 8.29 6.31 8.53C6.15 8.77 6.02 9.01 5.91 9.28C5.8 9.54 5.72 9.81 5.66 10.09C5.61 10.37 5.58 10.65 5.58 10.93L5.58 19.09C5.58 19.37 5.61 19.65 5.66 19.93C5.72 20.21 5.8 20.48 5.91 20.74C6.02 21.01 6.15 21.26 6.31 21.49C6.46 21.73 6.64 21.95 6.84 22.15C7.04 22.35 7.26 22.53 7.5 22.69C7.73 22.85 7.98 22.98 8.24 23.09C8.51 23.2 8.78 23.28 9.05 23.33C9.33 23.39 9.61 23.42 9.9 23.42L20.1 23.41C20.38 23.41 20.67 23.37 20.94 23.32C21.22 23.26 21.49 23.18 21.75 23.07C22.01 22.96 22.26 22.83 22.5 22.67C22.73 22.51 22.95 22.33 23.15 22.13C23.35 21.93 23.53 21.71 23.69 21.48C23.85 21.24 23.98 20.99 24.09 20.73C24.2 20.47 24.28 20.2 24.33 19.92C24.39 19.64 24.42 19.36 24.42 19.07L24.42 10.92C24.42 10.64 24.39 10.35 24.33 10.07C24.28 9.79 24.2 9.52 24.09 9.26C23.98 9 23.85 8.75 23.69 8.51C23.53 8.28 23.35 8.06 23.15 7.86C22.95 7.66 22.73 7.48 22.5 7.32C22.26 7.16 22.01 7.03 21.75 6.92C21.49 6.81 21.22 6.73 20.94 6.67C20.67 6.62 20.38 6.59 20.1 6.59L9.9 6.6Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.5 5.51L10.54 5.51L10.6 24.43L8.55 24.43L8.5 5.51Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n } @else {\n <defs>\n <clipPath id=\"clip1381_20236\">\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1381_20236)\">\n <rect\n id=\"rect\"\n x=\"11.572754\"\n y=\"17.683594\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(-42.841 11.572754 17.683594)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"16.033691\"\n y=\"16.271484\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(-139.147 16.033691 16.271484)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.09 25.48L9.89 25.5C9.47 25.5 9.05 25.45 8.64 25.37C8.23 25.29 7.83 25.17 7.44 25C7.05 24.84 6.68 24.64 6.33 24.41C5.98 24.18 5.66 23.91 5.36 23.61C5.07 23.31 4.8 22.99 4.57 22.64C4.34 22.29 4.14 21.92 3.98 21.53C3.82 21.14 3.69 20.74 3.61 20.32C3.53 19.91 3.49 19.49 3.49 19.07L3.49 10.92C3.49 10.5 3.53 10.08 3.61 9.67C3.69 9.25 3.82 8.85 3.98 8.46C4.14 8.07 4.34 7.7 4.57 7.35C4.8 7 5.07 6.68 5.36 6.38C5.66 6.08 5.98 5.81 6.33 5.58C6.68 5.35 7.05 5.15 7.44 4.99C7.83 4.82 8.23 4.7 8.64 4.62C9.05 4.54 9.47 4.5 9.89 4.5L20.09 4.48C20.51 4.48 20.93 4.52 21.34 4.6C21.75 4.69 22.15 4.81 22.54 4.97C22.93 5.13 23.3 5.33 23.65 5.57C24 5.8 24.32 6.06 24.62 6.36C24.92 6.66 25.18 6.98 25.41 7.33C25.65 7.69 25.84 8.06 26.01 8.45C26.17 8.84 26.29 9.24 26.37 9.65C26.45 10.06 26.49 10.48 26.5 10.91L26.5 19.06C26.49 19.48 26.45 19.89 26.37 20.31C26.29 20.72 26.17 21.12 26.01 21.51C25.84 21.9 25.65 22.27 25.41 22.62C25.18 22.97 24.92 23.3 24.62 23.6C24.32 23.89 24 24.16 23.65 24.39C23.3 24.63 22.93 24.83 22.54 24.99C22.15 25.15 21.75 25.27 21.34 25.35C20.93 25.44 20.51 25.48 20.09 25.48ZM9.89 6.59C9.61 6.59 9.32 6.62 9.05 6.67C8.77 6.73 8.5 6.81 8.24 6.92C7.98 7.03 7.73 7.16 7.49 7.32C7.26 7.48 7.04 7.66 6.84 7.86C6.64 8.06 6.46 8.28 6.3 8.51C6.14 8.75 6.01 9 5.9 9.26C5.79 9.52 5.71 9.8 5.66 10.07C5.6 10.35 5.57 10.63 5.57 10.92L5.57 19.07C5.57 19.36 5.6 19.64 5.66 19.92C5.71 20.19 5.79 20.47 5.9 20.73C6.01 20.99 6.14 21.24 6.3 21.48C6.46 21.71 6.64 21.93 6.84 22.13C7.04 22.33 7.26 22.51 7.49 22.67C7.73 22.83 7.98 22.96 8.24 23.07C8.5 23.18 8.77 23.26 9.05 23.32C9.32 23.37 9.61 23.4 9.89 23.4L20.09 23.39C20.38 23.39 20.66 23.36 20.94 23.3C21.21 23.25 21.48 23.17 21.75 23.06C22.01 22.95 22.26 22.81 22.49 22.66C22.73 22.5 22.95 22.32 23.15 22.12C23.35 21.91 23.52 21.7 23.68 21.46C23.84 21.22 23.97 20.98 24.08 20.71C24.19 20.45 24.27 20.18 24.33 19.9C24.38 19.62 24.41 19.34 24.41 19.06L24.41 10.91C24.41 10.62 24.38 10.34 24.33 10.06C24.27 9.78 24.19 9.51 24.08 9.25C23.97 8.98 23.84 8.74 23.68 8.5C23.52 8.26 23.35 8.04 23.15 7.84C22.95 7.64 22.73 7.46 22.49 7.3C22.26 7.15 22.01 7.01 21.75 6.9C21.48 6.79 21.21 6.71 20.94 6.66C20.66 6.6 20.38 6.57 20.09 6.57L9.89 6.59Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.49 5.5L10.53 5.5L10.59 24.41L8.54 24.41L8.49 5.5Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n }\n </svg>\n </ax-icon>\n</ax-button>\n\n<div class=\"axp-root-header__main ax-h-full ax-flex ax-min-w-0 ax-flex-1 ax-items-center ax-gap-2\">\n @if (tabNavigation.isTabBarVisible()) {\n <axp-route-tab-bar class=\"axp-route-tab-bar--in-header ax-min-w-0 ax-flex-1 ax-self-stretch\"></axp-route-tab-bar>\n }\n <div class=\"ax-flex ax-min-w-0 ax-items-center ax-gap-1\" [class.ax-flex-1]=\"!tabNavigation.isTabBarVisible()\">\n <axp-component-slot name=\"root-header-start\"></axp-component-slot>\n </div>\n</div>\n\n<div class=\"ax-flex ax-shrink-0 ax-items-center ax-gap-1\">\n <axp-component-slot name=\"root-header-end\"></axp-component-slot>\n</div>\n", dependencies: [{ kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "directive", type: i1$5.AXPComponentSlotDirective, selector: "axp-component-slot", inputs: ["name", "host", "context"], exportAs: ["slot"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: AXPRouteTabBarComponent, selector: "axp-route-tab-bar" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2410
2858
  }
2411
2859
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRootLayoutHeaderComponent, decorators: [{
2412
2860
  type: Component,
2413
- args: [{ selector: 'axp-dashboard-admin-header', encapsulation: ViewEncapsulation.None, host: { class: 'ax-w-full ax-flex ax-items-center ax-justify-between ax-bg-primary-surface ax-text-primary-on-surface ax-h-14 ax-px-2 ax-light' }, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2414
- AXPComponentSlotModule,
2415
- AXButtonModule,
2416
- AXDecoratorModule
2417
- ], template: "<ax-button id=\"axp-menu-toggle\" (onClick)=\"toggleSideMenu()\" color=\"primary\">\n <ax-icon class=\"rtl:ax-rotate-180\">\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 30 30\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n @if (store.isSideMenuOpen()) {\n <defs>\n <clipPath id=\"clip1382_20239\">\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1382_20239)\">\n <rect\n id=\"rect\"\n x=\"17.420410\"\n y=\"12.316406\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(137.159 17.420410 12.316406)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"12.959473\"\n y=\"13.728516\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(40.853 12.959473 13.728516)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.1 25.5L9.9 25.51C9.48 25.51 9.06 25.47 8.65 25.39C8.24 25.3 7.84 25.18 7.45 25.02C7.06 24.86 6.69 24.66 6.34 24.43C5.99 24.19 5.67 23.92 5.37 23.63C5.07 23.33 4.81 23 4.58 22.65C4.34 22.3 4.15 21.93 3.98 21.54C3.82 21.15 3.7 20.75 3.62 20.34C3.54 19.93 3.5 19.51 3.5 19.09L3.5 10.93C3.5 10.51 3.54 10.1 3.62 9.68C3.7 9.27 3.82 8.87 3.98 8.48C4.15 8.09 4.34 7.72 4.58 7.37C4.81 7.02 5.07 6.69 5.37 6.39C5.67 6.1 5.99 5.83 6.34 5.6C6.69 5.36 7.06 5.16 7.45 5C7.84 4.84 8.24 4.72 8.65 4.64C9.06 4.55 9.48 4.51 9.9 4.51L20.1 4.5C20.52 4.5 20.94 4.54 21.35 4.62C21.76 4.7 22.16 4.83 22.55 4.99C22.94 5.15 23.31 5.35 23.66 5.58C24 5.82 24.33 6.08 24.62 6.38C24.92 6.68 25.19 7 25.42 7.35C25.65 7.7 25.85 8.07 26.01 8.46C26.17 8.85 26.3 9.25 26.38 9.67C26.46 10.08 26.5 10.5 26.5 10.92L26.5 19.07C26.5 19.5 26.46 19.91 26.38 20.32C26.3 20.74 26.17 21.14 26.01 21.53C25.85 21.92 25.65 22.29 25.42 22.64C25.19 22.99 24.92 23.31 24.62 23.61C24.33 23.91 24 24.17 23.66 24.41C23.31 24.64 22.94 24.84 22.55 25C22.16 25.16 21.76 25.29 21.35 25.37C20.94 25.45 20.52 25.5 20.1 25.5ZM9.9 6.6C9.61 6.6 9.33 6.63 9.05 6.69C8.78 6.74 8.51 6.82 8.24 6.93C7.98 7.04 7.73 7.18 7.5 7.33C7.26 7.49 7.04 7.67 6.84 7.87C6.64 8.07 6.46 8.29 6.31 8.53C6.15 8.77 6.02 9.01 5.91 9.28C5.8 9.54 5.72 9.81 5.66 10.09C5.61 10.37 5.58 10.65 5.58 10.93L5.58 19.09C5.58 19.37 5.61 19.65 5.66 19.93C5.72 20.21 5.8 20.48 5.91 20.74C6.02 21.01 6.15 21.26 6.31 21.49C6.46 21.73 6.64 21.95 6.84 22.15C7.04 22.35 7.26 22.53 7.5 22.69C7.73 22.85 7.98 22.98 8.24 23.09C8.51 23.2 8.78 23.28 9.05 23.33C9.33 23.39 9.61 23.42 9.9 23.42L20.1 23.41C20.38 23.41 20.67 23.37 20.94 23.32C21.22 23.26 21.49 23.18 21.75 23.07C22.01 22.96 22.26 22.83 22.5 22.67C22.73 22.51 22.95 22.33 23.15 22.13C23.35 21.93 23.53 21.71 23.69 21.48C23.85 21.24 23.98 20.99 24.09 20.73C24.2 20.47 24.28 20.2 24.33 19.92C24.39 19.64 24.42 19.36 24.42 19.07L24.42 10.92C24.42 10.64 24.39 10.35 24.33 10.07C24.28 9.79 24.2 9.52 24.09 9.26C23.98 9 23.85 8.75 23.69 8.51C23.53 8.28 23.35 8.06 23.15 7.86C22.95 7.66 22.73 7.48 22.5 7.32C22.26 7.16 22.01 7.03 21.75 6.92C21.49 6.81 21.22 6.73 20.94 6.67C20.67 6.62 20.38 6.59 20.1 6.59L9.9 6.6Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.5 5.51L10.54 5.51L10.6 24.43L8.55 24.43L8.5 5.51Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n } @else {\n <defs>\n <clipPath id=\"clip1381_20236\">\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1381_20236)\">\n <rect\n id=\"rect\"\n x=\"11.572754\"\n y=\"17.683594\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(-42.841 11.572754 17.683594)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"16.033691\"\n y=\"16.271484\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(-139.147 16.033691 16.271484)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.09 25.48L9.89 25.5C9.47 25.5 9.05 25.45 8.64 25.37C8.23 25.29 7.83 25.17 7.44 25C7.05 24.84 6.68 24.64 6.33 24.41C5.98 24.18 5.66 23.91 5.36 23.61C5.07 23.31 4.8 22.99 4.57 22.64C4.34 22.29 4.14 21.92 3.98 21.53C3.82 21.14 3.69 20.74 3.61 20.32C3.53 19.91 3.49 19.49 3.49 19.07L3.49 10.92C3.49 10.5 3.53 10.08 3.61 9.67C3.69 9.25 3.82 8.85 3.98 8.46C4.14 8.07 4.34 7.7 4.57 7.35C4.8 7 5.07 6.68 5.36 6.38C5.66 6.08 5.98 5.81 6.33 5.58C6.68 5.35 7.05 5.15 7.44 4.99C7.83 4.82 8.23 4.7 8.64 4.62C9.05 4.54 9.47 4.5 9.89 4.5L20.09 4.48C20.51 4.48 20.93 4.52 21.34 4.6C21.75 4.69 22.15 4.81 22.54 4.97C22.93 5.13 23.3 5.33 23.65 5.57C24 5.8 24.32 6.06 24.62 6.36C24.92 6.66 25.18 6.98 25.41 7.33C25.65 7.69 25.84 8.06 26.01 8.45C26.17 8.84 26.29 9.24 26.37 9.65C26.45 10.06 26.49 10.48 26.5 10.91L26.5 19.06C26.49 19.48 26.45 19.89 26.37 20.31C26.29 20.72 26.17 21.12 26.01 21.51C25.84 21.9 25.65 22.27 25.41 22.62C25.18 22.97 24.92 23.3 24.62 23.6C24.32 23.89 24 24.16 23.65 24.39C23.3 24.63 22.93 24.83 22.54 24.99C22.15 25.15 21.75 25.27 21.34 25.35C20.93 25.44 20.51 25.48 20.09 25.48ZM9.89 6.59C9.61 6.59 9.32 6.62 9.05 6.67C8.77 6.73 8.5 6.81 8.24 6.92C7.98 7.03 7.73 7.16 7.49 7.32C7.26 7.48 7.04 7.66 6.84 7.86C6.64 8.06 6.46 8.28 6.3 8.51C6.14 8.75 6.01 9 5.9 9.26C5.79 9.52 5.71 9.8 5.66 10.07C5.6 10.35 5.57 10.63 5.57 10.92L5.57 19.07C5.57 19.36 5.6 19.64 5.66 19.92C5.71 20.19 5.79 20.47 5.9 20.73C6.01 20.99 6.14 21.24 6.3 21.48C6.46 21.71 6.64 21.93 6.84 22.13C7.04 22.33 7.26 22.51 7.49 22.67C7.73 22.83 7.98 22.96 8.24 23.07C8.5 23.18 8.77 23.26 9.05 23.32C9.32 23.37 9.61 23.4 9.89 23.4L20.09 23.39C20.38 23.39 20.66 23.36 20.94 23.3C21.21 23.25 21.48 23.17 21.75 23.06C22.01 22.95 22.26 22.81 22.49 22.66C22.73 22.5 22.95 22.32 23.15 22.12C23.35 21.91 23.52 21.7 23.68 21.46C23.84 21.22 23.97 20.98 24.08 20.71C24.19 20.45 24.27 20.18 24.33 19.9C24.38 19.62 24.41 19.34 24.41 19.06L24.41 10.91C24.41 10.62 24.38 10.34 24.33 10.06C24.27 9.78 24.19 9.51 24.08 9.25C23.97 8.98 23.84 8.74 23.68 8.5C23.52 8.26 23.35 8.04 23.15 7.84C22.95 7.64 22.73 7.46 22.49 7.3C22.26 7.15 22.01 7.01 21.75 6.9C21.48 6.79 21.21 6.71 20.94 6.66C20.66 6.6 20.38 6.57 20.09 6.57L9.89 6.59Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.49 5.5L10.53 5.5L10.59 24.41L8.54 24.41L8.49 5.5Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n }\n </svg>\n </ax-icon>\n</ax-button>\n<div class=\"ax-flex ax-items-center ax-gap-1 ax-justify-between ax-w-full\">\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <axp-component-slot name=\"root-header-start\"></axp-component-slot>\n </div>\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <axp-component-slot name=\"root-header-end\"></axp-component-slot>\n </div>\n</div>\n" }]
2861
+ args: [{ selector: 'axp-dashboard-admin-header', encapsulation: ViewEncapsulation.None, host: {
2862
+ class: 'ax-w-full ax-flex ax-min-w-0 ax-items-center ax-gap-2 ax-bg-primary-surface ax-text-primary-on-surface ax-h-14 ax-px-2 ax-light',
2863
+ }, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [AXPComponentSlotModule, AXButtonModule, AXDecoratorModule, AXPRouteTabBarComponent], template: "<ax-button id=\"axp-menu-toggle\" (onClick)=\"toggleSideMenu()\" color=\"primary\">\n <ax-icon class=\"rtl:ax-rotate-180\">\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 30 30\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n @if (store.isSideMenuOpen()) {\n <defs>\n <clipPath id=\"clip1382_20239\">\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1382_20239)\">\n <rect\n id=\"rect\"\n x=\"17.420410\"\n y=\"12.316406\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(137.159 17.420410 12.316406)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"12.959473\"\n y=\"13.728516\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(40.853 12.959473 13.728516)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.1 25.5L9.9 25.51C9.48 25.51 9.06 25.47 8.65 25.39C8.24 25.3 7.84 25.18 7.45 25.02C7.06 24.86 6.69 24.66 6.34 24.43C5.99 24.19 5.67 23.92 5.37 23.63C5.07 23.33 4.81 23 4.58 22.65C4.34 22.3 4.15 21.93 3.98 21.54C3.82 21.15 3.7 20.75 3.62 20.34C3.54 19.93 3.5 19.51 3.5 19.09L3.5 10.93C3.5 10.51 3.54 10.1 3.62 9.68C3.7 9.27 3.82 8.87 3.98 8.48C4.15 8.09 4.34 7.72 4.58 7.37C4.81 7.02 5.07 6.69 5.37 6.39C5.67 6.1 5.99 5.83 6.34 5.6C6.69 5.36 7.06 5.16 7.45 5C7.84 4.84 8.24 4.72 8.65 4.64C9.06 4.55 9.48 4.51 9.9 4.51L20.1 4.5C20.52 4.5 20.94 4.54 21.35 4.62C21.76 4.7 22.16 4.83 22.55 4.99C22.94 5.15 23.31 5.35 23.66 5.58C24 5.82 24.33 6.08 24.62 6.38C24.92 6.68 25.19 7 25.42 7.35C25.65 7.7 25.85 8.07 26.01 8.46C26.17 8.85 26.3 9.25 26.38 9.67C26.46 10.08 26.5 10.5 26.5 10.92L26.5 19.07C26.5 19.5 26.46 19.91 26.38 20.32C26.3 20.74 26.17 21.14 26.01 21.53C25.85 21.92 25.65 22.29 25.42 22.64C25.19 22.99 24.92 23.31 24.62 23.61C24.33 23.91 24 24.17 23.66 24.41C23.31 24.64 22.94 24.84 22.55 25C22.16 25.16 21.76 25.29 21.35 25.37C20.94 25.45 20.52 25.5 20.1 25.5ZM9.9 6.6C9.61 6.6 9.33 6.63 9.05 6.69C8.78 6.74 8.51 6.82 8.24 6.93C7.98 7.04 7.73 7.18 7.5 7.33C7.26 7.49 7.04 7.67 6.84 7.87C6.64 8.07 6.46 8.29 6.31 8.53C6.15 8.77 6.02 9.01 5.91 9.28C5.8 9.54 5.72 9.81 5.66 10.09C5.61 10.37 5.58 10.65 5.58 10.93L5.58 19.09C5.58 19.37 5.61 19.65 5.66 19.93C5.72 20.21 5.8 20.48 5.91 20.74C6.02 21.01 6.15 21.26 6.31 21.49C6.46 21.73 6.64 21.95 6.84 22.15C7.04 22.35 7.26 22.53 7.5 22.69C7.73 22.85 7.98 22.98 8.24 23.09C8.51 23.2 8.78 23.28 9.05 23.33C9.33 23.39 9.61 23.42 9.9 23.42L20.1 23.41C20.38 23.41 20.67 23.37 20.94 23.32C21.22 23.26 21.49 23.18 21.75 23.07C22.01 22.96 22.26 22.83 22.5 22.67C22.73 22.51 22.95 22.33 23.15 22.13C23.35 21.93 23.53 21.71 23.69 21.48C23.85 21.24 23.98 20.99 24.09 20.73C24.2 20.47 24.28 20.2 24.33 19.92C24.39 19.64 24.42 19.36 24.42 19.07L24.42 10.92C24.42 10.64 24.39 10.35 24.33 10.07C24.28 9.79 24.2 9.52 24.09 9.26C23.98 9 23.85 8.75 23.69 8.51C23.53 8.28 23.35 8.06 23.15 7.86C22.95 7.66 22.73 7.48 22.5 7.32C22.26 7.16 22.01 7.03 21.75 6.92C21.49 6.81 21.22 6.73 20.94 6.67C20.67 6.62 20.38 6.59 20.1 6.59L9.9 6.6Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.5 5.51L10.54 5.51L10.6 24.43L8.55 24.43L8.5 5.51Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n } @else {\n <defs>\n <clipPath id=\"clip1381_20236\">\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"white\" fill-opacity=\"0\"></rect>\n </clipPath>\n </defs>\n <rect id=\"\u6253\u5F00\u8FB9\u680F0730\" width=\"30.000000\" height=\"30.000000\" fill=\"#FFFFFF\" fill-opacity=\"0\"></rect>\n <g clip-path=\"url(#clip1381_20236)\">\n <rect\n id=\"rect\"\n x=\"11.572754\"\n y=\"17.683594\"\n rx=\"1.000947\"\n width=\"5.995172\"\n height=\"2.001895\"\n transform=\"rotate(-42.841 11.572754 17.683594)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <rect\n id=\"rect\"\n x=\"16.033691\"\n y=\"16.271484\"\n rx=\"0.995190\"\n width=\"6.002943\"\n height=\"1.990380\"\n transform=\"rotate(-139.147 16.033691 16.271484)\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n ></rect>\n <path\n id=\"path\"\n d=\"M20.09 25.48L9.89 25.5C9.47 25.5 9.05 25.45 8.64 25.37C8.23 25.29 7.83 25.17 7.44 25C7.05 24.84 6.68 24.64 6.33 24.41C5.98 24.18 5.66 23.91 5.36 23.61C5.07 23.31 4.8 22.99 4.57 22.64C4.34 22.29 4.14 21.92 3.98 21.53C3.82 21.14 3.69 20.74 3.61 20.32C3.53 19.91 3.49 19.49 3.49 19.07L3.49 10.92C3.49 10.5 3.53 10.08 3.61 9.67C3.69 9.25 3.82 8.85 3.98 8.46C4.14 8.07 4.34 7.7 4.57 7.35C4.8 7 5.07 6.68 5.36 6.38C5.66 6.08 5.98 5.81 6.33 5.58C6.68 5.35 7.05 5.15 7.44 4.99C7.83 4.82 8.23 4.7 8.64 4.62C9.05 4.54 9.47 4.5 9.89 4.5L20.09 4.48C20.51 4.48 20.93 4.52 21.34 4.6C21.75 4.69 22.15 4.81 22.54 4.97C22.93 5.13 23.3 5.33 23.65 5.57C24 5.8 24.32 6.06 24.62 6.36C24.92 6.66 25.18 6.98 25.41 7.33C25.65 7.69 25.84 8.06 26.01 8.45C26.17 8.84 26.29 9.24 26.37 9.65C26.45 10.06 26.49 10.48 26.5 10.91L26.5 19.06C26.49 19.48 26.45 19.89 26.37 20.31C26.29 20.72 26.17 21.12 26.01 21.51C25.84 21.9 25.65 22.27 25.41 22.62C25.18 22.97 24.92 23.3 24.62 23.6C24.32 23.89 24 24.16 23.65 24.39C23.3 24.63 22.93 24.83 22.54 24.99C22.15 25.15 21.75 25.27 21.34 25.35C20.93 25.44 20.51 25.48 20.09 25.48ZM9.89 6.59C9.61 6.59 9.32 6.62 9.05 6.67C8.77 6.73 8.5 6.81 8.24 6.92C7.98 7.03 7.73 7.16 7.49 7.32C7.26 7.48 7.04 7.66 6.84 7.86C6.64 8.06 6.46 8.28 6.3 8.51C6.14 8.75 6.01 9 5.9 9.26C5.79 9.52 5.71 9.8 5.66 10.07C5.6 10.35 5.57 10.63 5.57 10.92L5.57 19.07C5.57 19.36 5.6 19.64 5.66 19.92C5.71 20.19 5.79 20.47 5.9 20.73C6.01 20.99 6.14 21.24 6.3 21.48C6.46 21.71 6.64 21.93 6.84 22.13C7.04 22.33 7.26 22.51 7.49 22.67C7.73 22.83 7.98 22.96 8.24 23.07C8.5 23.18 8.77 23.26 9.05 23.32C9.32 23.37 9.61 23.4 9.89 23.4L20.09 23.39C20.38 23.39 20.66 23.36 20.94 23.3C21.21 23.25 21.48 23.17 21.75 23.06C22.01 22.95 22.26 22.81 22.49 22.66C22.73 22.5 22.95 22.32 23.15 22.12C23.35 21.91 23.52 21.7 23.68 21.46C23.84 21.22 23.97 20.98 24.08 20.71C24.19 20.45 24.27 20.18 24.33 19.9C24.38 19.62 24.41 19.34 24.41 19.06L24.41 10.91C24.41 10.62 24.38 10.34 24.33 10.06C24.27 9.78 24.19 9.51 24.08 9.25C23.97 8.98 23.84 8.74 23.68 8.5C23.52 8.26 23.35 8.04 23.15 7.84C22.95 7.64 22.73 7.46 22.49 7.3C22.26 7.15 22.01 7.01 21.75 6.9C21.48 6.79 21.21 6.71 20.94 6.66C20.66 6.6 20.38 6.57 20.09 6.57L9.89 6.59Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n id=\"rect\"\n d=\"M8.49 5.5L10.53 5.5L10.59 24.41L8.54 24.41L8.49 5.5Z\"\n fill=\"currentColor\"\n fill-opacity=\"1.000000\"\n fill-rule=\"evenodd\"\n ></path>\n </g>\n }\n </svg>\n </ax-icon>\n</ax-button>\n\n<div class=\"axp-root-header__main ax-h-full ax-flex ax-min-w-0 ax-flex-1 ax-items-center ax-gap-2\">\n @if (tabNavigation.isTabBarVisible()) {\n <axp-route-tab-bar class=\"axp-route-tab-bar--in-header ax-min-w-0 ax-flex-1 ax-self-stretch\"></axp-route-tab-bar>\n }\n <div class=\"ax-flex ax-min-w-0 ax-items-center ax-gap-1\" [class.ax-flex-1]=\"!tabNavigation.isTabBarVisible()\">\n <axp-component-slot name=\"root-header-start\"></axp-component-slot>\n </div>\n</div>\n\n<div class=\"ax-flex ax-shrink-0 ax-items-center ax-gap-1\">\n <axp-component-slot name=\"root-header-end\"></axp-component-slot>\n</div>\n" }]
2418
2864
  }], ctorParameters: () => [] });
2419
2865
 
2420
2866
  class AXPRootLayoutMenuComponent {
@@ -2440,12 +2886,41 @@ class AXPRootLayoutMenuComponent {
2440
2886
  }
2441
2887
  });
2442
2888
  }
2443
- onMenuItemClick(item, hasRouterLink) {
2444
- if (hasRouterLink || item.children?.length) {
2889
+ onMenuItemClick(item) {
2890
+ if (item.children?.length) {
2445
2891
  return;
2446
2892
  }
2447
2893
  this.menuStore.executeCommand(item);
2448
2894
  }
2895
+ /**
2896
+ * Determines whether a menu item should render as active.
2897
+ * Do not bind `routerLink` on `ax-side-menu-item`: that component ignores the `active` input
2898
+ * and only uses `RouterLinkActive`, which cannot match entity detail routes to list menu paths.
2899
+ */
2900
+ isMenuItemActive(item) {
2901
+ const selected = this.menuStore.selectedMenuItem().item;
2902
+ if (selected && this.isSameMenuItem(selected, item)) {
2903
+ return true;
2904
+ }
2905
+ const routePath = this.getMenuItemRoutePath(item);
2906
+ if (!routePath) {
2907
+ return false;
2908
+ }
2909
+ return axpMenuPathsMatch(routePath, this.router.url).isMatch;
2910
+ }
2911
+ isSameMenuItem(left, right) {
2912
+ if (left === right) {
2913
+ return true;
2914
+ }
2915
+ return !!left.name && left.name === right.name;
2916
+ }
2917
+ getMenuItemRoutePath(item) {
2918
+ const navigation = this.extractRouterNavigation(item);
2919
+ if (!navigation?.path) {
2920
+ return null;
2921
+ }
2922
+ return this.normalizeRouterPath(navigation.path);
2923
+ }
2449
2924
  sort(items) {
2450
2925
  return sortBy(items, [(c) => c.priority ?? 0, (c) => c.text]);
2451
2926
  }
@@ -2501,16 +2976,16 @@ class AXPRootLayoutMenuComponent {
2501
2976
  * command execution pipeline remains responsible for navigation.
2502
2977
  */
2503
2978
  getRouterLink(item) {
2504
- const navigation = this.extractRouterNavigation(item);
2505
- if (!navigation) {
2979
+ const routePath = this.getMenuItemRoutePath(item);
2980
+ if (!routePath) {
2506
2981
  return null;
2507
2982
  }
2508
- if (!this.isRouterLinkCompatible(navigation)) {
2983
+ const navigation = this.extractRouterNavigation(item);
2984
+ if (!navigation || !this.isRouterLinkCompatible(navigation)) {
2509
2985
  return null;
2510
2986
  }
2511
- const normalizedPath = this.normalizeRouterPath(navigation.path);
2512
2987
  try {
2513
- return this.router.parseUrl(normalizedPath);
2988
+ return this.router.parseUrl(routePath);
2514
2989
  }
2515
2990
  catch (error) {
2516
2991
  console.warn('Failed to create router link for menu item.', { item, error });
@@ -2595,7 +3070,7 @@ class AXPRootLayoutMenuComponent {
2595
3070
  return lowerPath.startsWith('http://') || lowerPath.startsWith('https://');
2596
3071
  }
2597
3072
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRootLayoutMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2598
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPRootLayoutMenuComponent, isStandalone: true, selector: "axp-side-menu", ngImport: i0, template: "<ax-side-menu look=\"pills\" [mode]=\"menuMode()\">\n @let sortedItems = sort(menuStore.items());\n @for (item of sortedItems; track item; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: item, items: sortedItems, index: i }\"\n >\n </ng-container>\n }\n</ax-side-menu>\n<ng-template #recursiveMenu let-item=\"item\" let-items=\"items\" let-index=\"index\">\n @if (item.type == 'group' && menuMode() === 'full') {\n @if (isItemVisible(item)) {\n <ax-title>{{ item.text | translate | async }}</ax-title>\n }\n } @else if (item.type == 'break') {\n @if (shouldShowDivider(item, items, index)) {\n <ax-divider></ax-divider>\n }\n } @else {\n @if (shouldRenderMenuItem(item)) {\n @let routerLinkValue = getRouterLink(item);\n @if (routerLinkValue) {\n <ax-side-menu-item\n [attr.id]=\"'axp-menu-item-' + (item.name || item.text)\"\n (onClick)=\"onMenuItemClick(item, true)\"\n [routerLink]=\"routerLinkValue\"\n [active]=\"item === menuStore.selectedMenuItem().item\"\n [isCollapsed]=\"!menuStore.isItemOpen(item)\"\n >\n <ax-prefix>\n <ax-icon [class]=\"item.icon\" class=\"fa-fw\"></ax-icon>\n </ax-prefix>\n <span>{{ item.text | translate | async }}</span>\n @if (item.children?.length) {\n <ng-container>\n @let sortedChildren = sort(item.children);\n @for (child of sortedChildren; track child; let childIndex = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: child, items: sortedChildren, index: childIndex }\"\n >\n </ng-container>\n }\n </ng-container>\n }\n <ax-suffix>\n @if (badgeVisible()) {\n <ax-badge [axp-task-badge]=\"getMenuBadge(item)()\" color=\"secondary\"></ax-badge>\n }\n </ax-suffix>\n </ax-side-menu-item>\n } @else {\n <ax-side-menu-item\n [attr.id]=\"'axp-menu-item-' + (item.name || item.text)\"\n (onClick)=\"onMenuItemClick(item)\"\n [active]=\"item === menuStore.selectedMenuItem().item\"\n [isCollapsed]=\"!menuStore.isItemOpen(item)\"\n >\n <ax-prefix>\n <ax-icon [class]=\"item.icon\" class=\"fa-fw\"></ax-icon>\n </ax-prefix>\n <span>{{ item.text | translate | async }}</span>\n @if (item.children?.length) {\n <ng-container>\n @let sortedChildren = sort(item.children);\n @for (child of sortedChildren; track child; let childIndex = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: child, items: sortedChildren, index: childIndex }\"\n >\n </ng-container>\n }\n </ng-container>\n }\n <ax-suffix>\n @if (badgeVisible()) {\n <ax-badge [axp-task-badge]=\"getMenuBadge(item)()\" color=\"secondary\"></ax-badge>\n }\n </ax-suffix>\n </ax-side-menu-item>\n }\n }\n }\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXSideMenuModule }, { kind: "component", type: i2$3.AXSideMenuComponent, selector: "ax-side-menu", inputs: ["items", "look", "location", "mode"], outputs: ["itemsChange"] }, { kind: "component", type: i2$3.AXSideMenuItemComponent, selector: "ax-side-menu-item", inputs: ["disabled", "text", "active", "isLoading", "isCollapsed", "toggleOnClick", "href", "routerLink", "routerLinkActive", "routerLinkActiveOptions", "target"], outputs: ["textChange", "activeChange", "isLoadingChange", "isCollapsedChange", "onClick"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: AXPTaskBadgeDirective, selector: "[axp-task-badge]", inputs: ["badgeKey", "axp-task-badge"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
3073
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPRootLayoutMenuComponent, isStandalone: true, selector: "axp-side-menu", ngImport: i0, template: "<ax-side-menu look=\"pills\" [mode]=\"menuMode()\">\n @let sortedItems = sort(menuStore.items());\n @for (item of sortedItems; track item; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: item, items: sortedItems, index: i }\"\n >\n </ng-container>\n }\n</ax-side-menu>\n<ng-template #recursiveMenu let-item=\"item\" let-items=\"items\" let-index=\"index\">\n @if (item.type == 'group' && menuMode() === 'full') {\n @if (isItemVisible(item)) {\n <ax-title>{{ item.text | translate | async }}</ax-title>\n }\n } @else if (item.type == 'break') {\n @if (shouldShowDivider(item, items, index)) {\n <ax-divider></ax-divider>\n }\n } @else {\n @if (shouldRenderMenuItem(item)) {\n <ax-side-menu-item\n [attr.id]=\"'axp-menu-item-' + (item.name || item.text)\"\n (onClick)=\"onMenuItemClick(item)\"\n [active]=\"isMenuItemActive(item)\"\n [isCollapsed]=\"!menuStore.isItemOpen(item)\"\n >\n <ax-prefix>\n <ax-icon [class]=\"item.icon\" class=\"fa-fw\"></ax-icon>\n </ax-prefix>\n <span>{{ item.text | translate | async }}</span>\n @if (item.children?.length) {\n <ng-container>\n @let sortedChildren = sort(item.children);\n @for (child of sortedChildren; track child; let childIndex = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: child, items: sortedChildren, index: childIndex }\"\n >\n </ng-container>\n }\n </ng-container>\n }\n <ax-suffix>\n @if (badgeVisible()) {\n <ax-badge [axp-task-badge]=\"getMenuBadge(item)()\" color=\"secondary\"></ax-badge>\n }\n </ax-suffix>\n </ax-side-menu-item>\n }\n }\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXSideMenuModule }, { kind: "component", type: i2$3.AXSideMenuComponent, selector: "ax-side-menu", inputs: ["items", "look", "location", "mode"], outputs: ["itemsChange"] }, { kind: "component", type: i2$3.AXSideMenuItemComponent, selector: "ax-side-menu-item", inputs: ["disabled", "text", "active", "isLoading", "isCollapsed", "toggleOnClick", "href", "routerLink", "routerLinkActive", "routerLinkActiveOptions", "target"], outputs: ["textChange", "activeChange", "isLoadingChange", "isCollapsedChange", "onClick"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: AXPTaskBadgeDirective, selector: "[axp-task-badge]", inputs: ["badgeKey", "axp-task-badge"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2599
3074
  }
2600
3075
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRootLayoutMenuComponent, decorators: [{
2601
3076
  type: Component,
@@ -2606,7 +3081,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2606
3081
  AXPTaskBadgeDirective,
2607
3082
  AXDecoratorModule,
2608
3083
  AXBadgeModule,
2609
- ], template: "<ax-side-menu look=\"pills\" [mode]=\"menuMode()\">\n @let sortedItems = sort(menuStore.items());\n @for (item of sortedItems; track item; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: item, items: sortedItems, index: i }\"\n >\n </ng-container>\n }\n</ax-side-menu>\n<ng-template #recursiveMenu let-item=\"item\" let-items=\"items\" let-index=\"index\">\n @if (item.type == 'group' && menuMode() === 'full') {\n @if (isItemVisible(item)) {\n <ax-title>{{ item.text | translate | async }}</ax-title>\n }\n } @else if (item.type == 'break') {\n @if (shouldShowDivider(item, items, index)) {\n <ax-divider></ax-divider>\n }\n } @else {\n @if (shouldRenderMenuItem(item)) {\n @let routerLinkValue = getRouterLink(item);\n @if (routerLinkValue) {\n <ax-side-menu-item\n [attr.id]=\"'axp-menu-item-' + (item.name || item.text)\"\n (onClick)=\"onMenuItemClick(item, true)\"\n [routerLink]=\"routerLinkValue\"\n [active]=\"item === menuStore.selectedMenuItem().item\"\n [isCollapsed]=\"!menuStore.isItemOpen(item)\"\n >\n <ax-prefix>\n <ax-icon [class]=\"item.icon\" class=\"fa-fw\"></ax-icon>\n </ax-prefix>\n <span>{{ item.text | translate | async }}</span>\n @if (item.children?.length) {\n <ng-container>\n @let sortedChildren = sort(item.children);\n @for (child of sortedChildren; track child; let childIndex = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: child, items: sortedChildren, index: childIndex }\"\n >\n </ng-container>\n }\n </ng-container>\n }\n <ax-suffix>\n @if (badgeVisible()) {\n <ax-badge [axp-task-badge]=\"getMenuBadge(item)()\" color=\"secondary\"></ax-badge>\n }\n </ax-suffix>\n </ax-side-menu-item>\n } @else {\n <ax-side-menu-item\n [attr.id]=\"'axp-menu-item-' + (item.name || item.text)\"\n (onClick)=\"onMenuItemClick(item)\"\n [active]=\"item === menuStore.selectedMenuItem().item\"\n [isCollapsed]=\"!menuStore.isItemOpen(item)\"\n >\n <ax-prefix>\n <ax-icon [class]=\"item.icon\" class=\"fa-fw\"></ax-icon>\n </ax-prefix>\n <span>{{ item.text | translate | async }}</span>\n @if (item.children?.length) {\n <ng-container>\n @let sortedChildren = sort(item.children);\n @for (child of sortedChildren; track child; let childIndex = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: child, items: sortedChildren, index: childIndex }\"\n >\n </ng-container>\n }\n </ng-container>\n }\n <ax-suffix>\n @if (badgeVisible()) {\n <ax-badge [axp-task-badge]=\"getMenuBadge(item)()\" color=\"secondary\"></ax-badge>\n }\n </ax-suffix>\n </ax-side-menu-item>\n }\n }\n }\n</ng-template>\n" }]
3084
+ ], template: "<ax-side-menu look=\"pills\" [mode]=\"menuMode()\">\n @let sortedItems = sort(menuStore.items());\n @for (item of sortedItems; track item; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: item, items: sortedItems, index: i }\"\n >\n </ng-container>\n }\n</ax-side-menu>\n<ng-template #recursiveMenu let-item=\"item\" let-items=\"items\" let-index=\"index\">\n @if (item.type == 'group' && menuMode() === 'full') {\n @if (isItemVisible(item)) {\n <ax-title>{{ item.text | translate | async }}</ax-title>\n }\n } @else if (item.type == 'break') {\n @if (shouldShowDivider(item, items, index)) {\n <ax-divider></ax-divider>\n }\n } @else {\n @if (shouldRenderMenuItem(item)) {\n <ax-side-menu-item\n [attr.id]=\"'axp-menu-item-' + (item.name || item.text)\"\n (onClick)=\"onMenuItemClick(item)\"\n [active]=\"isMenuItemActive(item)\"\n [isCollapsed]=\"!menuStore.isItemOpen(item)\"\n >\n <ax-prefix>\n <ax-icon [class]=\"item.icon\" class=\"fa-fw\"></ax-icon>\n </ax-prefix>\n <span>{{ item.text | translate | async }}</span>\n @if (item.children?.length) {\n <ng-container>\n @let sortedChildren = sort(item.children);\n @for (child of sortedChildren; track child; let childIndex = $index) {\n <ng-container\n [ngTemplateOutlet]=\"recursiveMenu\"\n [ngTemplateOutletContext]=\"{ item: child, items: sortedChildren, index: childIndex }\"\n >\n </ng-container>\n }\n </ng-container>\n }\n <ax-suffix>\n @if (badgeVisible()) {\n <ax-badge [axp-task-badge]=\"getMenuBadge(item)()\" color=\"secondary\"></ax-badge>\n }\n </ax-suffix>\n </ax-side-menu-item>\n }\n }\n</ng-template>\n" }]
2610
3085
  }] });
2611
3086
 
2612
3087
  class AXPHorizontalMenuComponent {
@@ -2907,12 +3382,11 @@ class AXPRootLayoutComponent {
2907
3382
  this.contextStore = inject(AXPContextStore);
2908
3383
  }
2909
3384
  ngOnInit() {
2910
- // Select the menu item based on the current route when the page loads
2911
- this.menuStore.selectMenuItemByRoute(this.router.url);
2912
- this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe((event) => {
2913
- // Update the selected menu item whenever the route changes
2914
- this.menuStore.selectMenuItemByRoute(event.urlAfterRedirects);
2915
- // Reset the context store
3385
+ this.#syncMenuSelectionByRoute(this.router.url);
3386
+ this.router.events
3387
+ .pipe(filter((event) => event instanceof NavigationEnd), this.unsubscriber.takeUntilDestroy)
3388
+ .subscribe((event) => {
3389
+ this.#syncMenuSelectionByRoute(event.urlAfterRedirects);
2916
3390
  this.contextStore.reset();
2917
3391
  });
2918
3392
  this.eventService.listen(AXPSessionStatus.SignedOut).subscribe(() => {
@@ -2934,12 +3408,15 @@ class AXPRootLayoutComponent {
2934
3408
  }
2935
3409
  });
2936
3410
  }
3411
+ #syncMenuSelectionByRoute(url) {
3412
+ this.menuStore.selectMenuItemByRoute(url);
3413
+ }
2937
3414
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPRootLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2938
3415
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPRootLayoutComponent, isStandalone: true, selector: "ng-component", providers: [AXUnsubscriber, AXPContextStore], ngImport: i0, template: `
2939
- @if(layout.isMenuHorizontal()){
2940
- <axp-root-horizontal-layout></axp-root-horizontal-layout>
2941
- }@else{
2942
- <axp-root-vertical-layout></axp-root-vertical-layout>
3416
+ @if (layout.isMenuHorizontal()) {
3417
+ <axp-root-horizontal-layout></axp-root-horizontal-layout>
3418
+ } @else {
3419
+ <axp-root-vertical-layout></axp-root-vertical-layout>
2943
3420
  }
2944
3421
  `, isInline: true, dependencies: [{ kind: "component", type: AXPRootHorizontalLayoutComponent, selector: "axp-root-horizontal-layout" }, { kind: "component", type: AXPRootVerticalLayoutComponent, selector: "axp-root-vertical-layout" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2945
3422
  }
@@ -2947,10 +3424,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
2947
3424
  type: Component,
2948
3425
  args: [{
2949
3426
  template: `
2950
- @if(layout.isMenuHorizontal()){
2951
- <axp-root-horizontal-layout></axp-root-horizontal-layout>
2952
- }@else{
2953
- <axp-root-vertical-layout></axp-root-vertical-layout>
3427
+ @if (layout.isMenuHorizontal()) {
3428
+ <axp-root-horizontal-layout></axp-root-horizontal-layout>
3429
+ } @else {
3430
+ <axp-root-vertical-layout></axp-root-vertical-layout>
2954
3431
  }
2955
3432
  `,
2956
3433
  encapsulation: ViewEncapsulation.None,
@@ -2966,57 +3443,226 @@ var rootLayout_component = /*#__PURE__*/Object.freeze({
2966
3443
  AXPRootLayoutComponent: AXPRootLayoutComponent
2967
3444
  });
2968
3445
 
3446
+ /**
3447
+ * Route reuse strategy that powers both same-route reuse (`reuse` route data) and tabular
3448
+ * navigation. In tabular mode it detaches the leaf page component of an open tab when the user
3449
+ * switches away, caches the live component instance, and reattaches it on return so state such as
3450
+ * data-table selection, scroll position, and unsaved form values is preserved — like browser tabs.
3451
+ */
2969
3452
  class AXPEntityReuseStrategy {
3453
+ constructor() {
3454
+ //#region ---- Services & Dependencies ----
3455
+ this.routeCache = inject(AXPTabRouteCacheRegistry);
3456
+ /** Lazy lookup avoids Router ↔ RouteReuseStrategy construction cycle (NG0200). */
3457
+ this.injector = inject(Injector);
3458
+ //#endregion
3459
+ }
3460
+ //#endregion
3461
+ //#region ---- Detach / Attach ----
2970
3462
  shouldDetach(route) {
2971
- return false;
3463
+ if (!this.routeCache.isEnabled() || !this.isTabCacheRoute(route)) {
3464
+ return false;
3465
+ }
3466
+ const scopedKey = this.scopedTabKeyFor(route);
3467
+ const cacheKey = this.routeCacheKeyFor(route);
3468
+ if (!scopedKey || !cacheKey || !this.routeCache.isOpen(scopedKey)) {
3469
+ return false;
3470
+ }
3471
+ // Keep the live component when navigating within the same scoped tab (e.g. chat → chat/:id).
3472
+ return this.isLeavingScopedTab(route);
3473
+ }
3474
+ store(route, handle) {
3475
+ if (!this.routeCache.isEnabled()) {
3476
+ return;
3477
+ }
3478
+ const key = this.routeCacheKeyFor(route);
3479
+ if (!key) {
3480
+ return;
3481
+ }
3482
+ // A null handle is Angular releasing a just-reattached view; drop it without destroying.
3483
+ if (handle) {
3484
+ this.routeCache.store(key, handle);
3485
+ }
3486
+ else {
3487
+ this.routeCache.release(key);
3488
+ }
2972
3489
  }
2973
- store(route, detachedTree) { }
2974
3490
  shouldAttach(route) {
2975
- return false;
3491
+ if (!this.routeCache.isEnabled() || !this.isTabCacheRoute(route)) {
3492
+ return false;
3493
+ }
3494
+ const key = this.routeCacheKeyFor(route);
3495
+ return !!key && this.routeCache.has(key);
2976
3496
  }
2977
3497
  retrieve(route) {
2978
- return null;
3498
+ if (!this.routeCache.isEnabled() || !this.isTabCacheRoute(route)) {
3499
+ return null;
3500
+ }
3501
+ const key = this.routeCacheKeyFor(route);
3502
+ return key ? this.routeCache.retrieve(key) : null;
2979
3503
  }
3504
+ //#endregion
3505
+ //#region ---- Reuse Decision ----
2980
3506
  shouldReuseRoute(future, curr) {
2981
- // If paths are different, never reuse
2982
- if (future.routeConfig?.path !== curr.routeConfig?.path) {
2983
- return false;
3507
+ // Reuse the single root-layout shell across module navigations so the heavy shell (menus,
3508
+ // header, session subscriptions, theme) is not destroyed and recreated on every route switch.
3509
+ // Uses `routeConfig.data` (the node's own data) so inherited child data does not leak this flag.
3510
+ if (future.routeConfig?.data?.['rootLayout'] === true && curr.routeConfig?.data?.['rootLayout'] === true) {
3511
+ return true;
2984
3512
  }
2985
3513
  const reuseConfig = future.data?.['reuse'];
2986
- // If reuse is explicitly false, don't reuse
2987
3514
  if (reuseConfig === false) {
2988
3515
  return false;
2989
3516
  }
2990
- // If reuse is explicitly true, always reuse (same path)
3517
+ // `reuse: true` on sibling routes under the same scoped tab (e.g. chat '' ↔ :id).
2991
3518
  if (reuseConfig === true) {
2992
- return true;
3519
+ // Same route node re-activated (e.g. settings `:scope` change reusing its `setting-page`).
3520
+ // Use config reference equality, not path strings: different tabs can share a path (e.g. the
3521
+ // empty-path child of both settings and chat), and once the root-layout shell is reused those
3522
+ // siblings get compared directly — a path-only match would wrongly keep the previous content.
3523
+ if (future.routeConfig && future.routeConfig === curr.routeConfig) {
3524
+ return true;
3525
+ }
3526
+ if (curr.data?.['reuse'] === true) {
3527
+ return axpResolveTabKeyFromSnapshot(future) === axpResolveTabKeyFromSnapshot(curr);
3528
+ }
3529
+ return false;
3530
+ }
3531
+ // Baseline "same route node" check. Reference equality (not path strings) so same-path children
3532
+ // of different reused shells (e.g. the empty-path child of notifications vs comments) are treated
3533
+ // as distinct and their content swaps correctly.
3534
+ if (future.routeConfig !== curr.routeConfig) {
3535
+ return false;
2993
3536
  }
2994
- // Handle string-based reuse strategies
2995
3537
  if (typeof reuseConfig === 'string') {
2996
3538
  const paramsChanged = this.haveParamsChanged(future, curr);
2997
3539
  const queryParamsChanged = this.haveQueryParamsChanged(future, curr);
2998
3540
  switch (reuseConfig) {
2999
3541
  case 'paramsChange':
3000
- // Reuse when params change, but destroy if queryParams change
3001
3542
  return !queryParamsChanged;
3002
3543
  case 'queryParamsChange':
3003
- // Reuse when queryParams change, but destroy if params change
3004
3544
  return !paramsChanged;
3005
3545
  case 'paramsOrQueryParamsChange':
3006
- // Reuse when either params or queryParams change
3007
3546
  return true;
3008
3547
  default:
3009
- // Unknown strategy, use default behavior
3010
3548
  return true;
3011
3549
  }
3012
3550
  }
3013
- // Default behavior: reuse if paths are the same
3014
3551
  return true;
3015
3552
  }
3016
- //#region ---- Helper Methods ----
3553
+ //#endregion
3554
+ //#region ---- Helper Methods ----
3555
+ /**
3556
+ * True when this route is the detach/attach target: a routable leaf, or a scoped tab shell
3557
+ * (`data.tab = true`) that owns a nested outlet (e.g. settings page).
3558
+ */
3559
+ isTabCacheRoute(route) {
3560
+ return this.resolveTabCacheTarget(route) === route;
3561
+ }
3017
3562
  /**
3018
- * Check if route params have changed between current and future routes
3563
+ * Under a scoped tab, cache the `reuse: true` page shell (settings page) instead of nested outlet
3564
+ * children (setting-view). Otherwise cache the routable leaf (entity pages, chat).
3019
3565
  */
3566
+ resolveTabCacheTarget(route) {
3567
+ const shell = this.findScopedShellRoute(route);
3568
+ if (shell) {
3569
+ // A scoped shell that owns a nested routed outlet (e.g. the settings page, whose `:group`
3570
+ // child renders `setting-view`) cannot be safely detached and reattached: Angular does not
3571
+ // resume the nested child's `effect()`s / change detection after reattach, so dirty tracking
3572
+ // and child content swaps silently stop working. Skip caching these shells — they recreate
3573
+ // fresh on tab return (the active child is preserved via the URL). Flat leaf shells (e.g. the
3574
+ // chat component) have no nested outlet and reattach correctly, so they stay cached.
3575
+ if (this.shellOwnsNestedOutlet(shell)) {
3576
+ return null;
3577
+ }
3578
+ return shell;
3579
+ }
3580
+ if (this.isRoutableLeaf(route)) {
3581
+ return route;
3582
+ }
3583
+ return null;
3584
+ }
3585
+ /** True when the scoped shell route declares child routes (i.e. it hosts a nested outlet). */
3586
+ shellOwnsNestedOutlet(shell) {
3587
+ const config = shell.routeConfig;
3588
+ return !!(config?.children?.length || config?.loadChildren);
3589
+ }
3590
+ /** Nearest ancestor route that declares `data.tab = true`. */
3591
+ findScopedAncestor(route) {
3592
+ for (let index = route.pathFromRoot.length - 1; index >= 0; index--) {
3593
+ const snapshot = route.pathFromRoot[index];
3594
+ if (axpHasTabScope(snapshot.data)) {
3595
+ return snapshot;
3596
+ }
3597
+ }
3598
+ return null;
3599
+ }
3600
+ /**
3601
+ * The innermost `reuse: true` component route between a scoped ancestor and the active route.
3602
+ * Settings: `setting-page` (not `setting-view`). Chat: the active chat child route.
3603
+ */
3604
+ findScopedShellRoute(route) {
3605
+ const scope = this.findScopedAncestor(route);
3606
+ if (!scope) {
3607
+ return null;
3608
+ }
3609
+ const chain = route.pathFromRoot;
3610
+ const scopeIndex = chain.indexOf(scope);
3611
+ if (scopeIndex < 0) {
3612
+ return null;
3613
+ }
3614
+ let shell = null;
3615
+ for (let index = scopeIndex + 1; index < chain.length; index++) {
3616
+ const snapshot = chain[index];
3617
+ if (snapshot.data?.['reuse'] === true && this.hasRoutableComponent(snapshot)) {
3618
+ shell = snapshot;
3619
+ }
3620
+ }
3621
+ return shell;
3622
+ }
3623
+ isRoutableLeaf(route) {
3624
+ if (route.firstChild) {
3625
+ return false;
3626
+ }
3627
+ return this.hasRoutableComponent(route);
3628
+ }
3629
+ hasRoutableComponent(route) {
3630
+ const config = route.routeConfig;
3631
+ return !!(route.component || config?.component || config?.loadComponent);
3632
+ }
3633
+ /** Cache key — scoped tab path for shells, full leaf path otherwise. */
3634
+ routeCacheKeyFor(route) {
3635
+ if (!this.isTabCacheRoute(route)) {
3636
+ return null;
3637
+ }
3638
+ const path = this.findScopedShellRoute(route) ? axpResolveTabKeyFromSnapshot(route) : axpPathFromSnapshot(route);
3639
+ return axpIsTabEligibleUrl(path) ? path : null;
3640
+ }
3641
+ /** Scoped tab key — matches open tab descriptors (`data.tab = true`). */
3642
+ scopedTabKeyFor(route) {
3643
+ const target = this.resolveTabCacheTarget(route);
3644
+ if (!target) {
3645
+ return null;
3646
+ }
3647
+ const path = axpResolveTabKeyFromSnapshot(target);
3648
+ return axpIsTabEligibleUrl(path) ? path : null;
3649
+ }
3650
+ /** True when the in-flight navigation leaves the scoped tab that owns this route. */
3651
+ isLeavingScopedTab(route) {
3652
+ const currentScoped = axpResolveTabKeyFromSnapshot(route);
3653
+ const router = this.injector.get(Router, null);
3654
+ if (!router) {
3655
+ return true;
3656
+ }
3657
+ const navigation = router.getCurrentNavigation();
3658
+ if (!navigation?.finalUrl) {
3659
+ return true;
3660
+ }
3661
+ const targetPath = router.serializeUrl(navigation.finalUrl).split('?')[0].split('#')[0];
3662
+ const futureScoped = axpResolveTabKeyFromRouteConfig(router.config, targetPath) ??
3663
+ (targetPath.startsWith('/') ? targetPath : `/${targetPath}`);
3664
+ return currentScoped !== futureScoped;
3665
+ }
3020
3666
  haveParamsChanged(future, curr) {
3021
3667
  const futureParams = future.params;
3022
3668
  const currParams = curr.params;
@@ -3032,9 +3678,6 @@ class AXPEntityReuseStrategy {
3032
3678
  }
3033
3679
  return false;
3034
3680
  }
3035
- /**
3036
- * Check if query params have changed between current and future routes
3037
- */
3038
3681
  haveQueryParamsChanged(future, curr) {
3039
3682
  const futureQueryParams = future.queryParams;
3040
3683
  const currQueryParams = curr.queryParams;
@@ -3058,6 +3701,7 @@ function routesFacory() {
3058
3701
  {
3059
3702
  path: ':app/modules/:module/:entity',
3060
3703
  canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
3704
+ data: { rootLayout: true },
3061
3705
  loadComponent: () => {
3062
3706
  return config.viewers.root();
3063
3707
  },
@@ -3113,7 +3757,7 @@ class AXPDefaultThemeModule {
3113
3757
  viewers: {
3114
3758
  root: () => Promise.resolve().then(function () { return rootLayout_component; }).then((c) => c.AXPRootLayoutComponent),
3115
3759
  master: {
3116
- single: () => import('./acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs').then((c) => c.AXPEntityMasterSingleViewComponent),
3760
+ single: () => import('./acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs').then((c) => c.AXPEntityMasterSingleViewComponent),
3117
3761
  details: () => import('@acorex/platform/layout/views').then((c) => c.AXPLayoutDetailsViewComponent),
3118
3762
  ///
3119
3763
  create: () => import('./acorex-platform-themes-default-entity-master-create-view.component-CWLfNqV0.mjs').then((c) => c.AXPEntityMasterCreateViewComponent),
@@ -3149,7 +3793,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3149
3793
  viewers: {
3150
3794
  root: () => Promise.resolve().then(function () { return rootLayout_component; }).then((c) => c.AXPRootLayoutComponent),
3151
3795
  master: {
3152
- single: () => import('./acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs').then((c) => c.AXPEntityMasterSingleViewComponent),
3796
+ single: () => import('./acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs').then((c) => c.AXPEntityMasterSingleViewComponent),
3153
3797
  details: () => import('@acorex/platform/layout/views').then((c) => c.AXPLayoutDetailsViewComponent),
3154
3798
  ///
3155
3799
  create: () => import('./acorex-platform-themes-default-entity-master-create-view.component-CWLfNqV0.mjs').then((c) => c.AXPEntityMasterCreateViewComponent),
@@ -3177,5 +3821,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3177
3821
  * Generated bundle index. Do not edit.
3178
3822
  */
3179
3823
 
3180
- export { AXPDefaultThemeModule, AXPEntityDetailListViewComponent, AXPEntityMasterListViewComponent, AXPRootHorizontalLayoutComponent, AXPRootLayoutComponent, AXPRootLayoutFooterComponent, AXPRootLayoutHeaderComponent, AXPRootLayoutMenuComponent, AXPRootVerticalLayoutComponent };
3824
+ export { AXPDefaultThemeModule, AXPEntityDetailListViewComponent, AXPEntityMasterListViewComponent, AXPRootHorizontalLayoutComponent, AXPRootLayoutComponent, AXPRootLayoutFooterComponent, AXPRootLayoutHeaderComponent, AXPRootLayoutMenuComponent, AXPRootVerticalLayoutComponent, AXPRouteTabBarComponent };
3181
3825
  //# sourceMappingURL=acorex-platform-themes-default.mjs.map