@acorex-platform/framework-client 1.0.1 → 1.0.2

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 (59) hide show
  1. package/fesm2022/acorex-platform-framework-client-auth.mjs +113 -45
  2. package/fesm2022/acorex-platform-framework-client-auth.mjs.map +1 -1
  3. package/fesm2022/{acorex-platform-framework-client-common-common-settings.provider-ChU2tvyt.mjs → acorex-platform-framework-client-common-common-settings.provider-Cyr1DaiD.mjs} +19 -2
  4. package/fesm2022/{acorex-platform-framework-client-common-common-settings.provider-ChU2tvyt.mjs.map → acorex-platform-framework-client-common-common-settings.provider-Cyr1DaiD.mjs.map} +1 -1
  5. package/fesm2022/acorex-platform-framework-client-common.mjs +445 -191
  6. package/fesm2022/acorex-platform-framework-client-common.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-framework-client-core.mjs +7 -2
  8. package/fesm2022/acorex-platform-framework-client-core.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-framework-client-layout-components.mjs +399 -132
  10. package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -1
  11. package/fesm2022/{acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-i9oZEXUR.mjs → acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D2kZxLOh.mjs} +616 -196
  12. package/fesm2022/acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D2kZxLOh.mjs.map +1 -0
  13. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-DyrvSBEY.mjs → acorex-platform-framework-client-layout-entity-attachments-page.component-BManmr01.mjs} +10 -5
  14. package/fesm2022/acorex-platform-framework-client-layout-entity-attachments-page.component-BManmr01.mjs.map +1 -0
  15. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-B8s_JEV8.mjs → acorex-platform-framework-client-layout-entity-bulk-entity.command-B8XsnrnO.mjs} +2 -2
  16. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-B8s_JEV8.mjs.map → acorex-platform-framework-client-layout-entity-bulk-entity.command-B8XsnrnO.mjs.map} +1 -1
  17. package/fesm2022/{acorex-platform-framework-client-layout-entity-file-list-popup.component-C0LgUzzv.mjs → acorex-platform-framework-client-layout-entity-file-list-popup.component-DGZVS11E.mjs} +28 -12
  18. package/fesm2022/acorex-platform-framework-client-layout-entity-file-list-popup.component-DGZVS11E.mjs.map +1 -0
  19. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-fATD9Uax.mjs → acorex-platform-framework-client-layout-entity-gallery-page.component-Be348QCj.mjs} +2 -2
  20. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-fATD9Uax.mjs.map → acorex-platform-framework-client-layout-entity-gallery-page.component-Be348QCj.mjs.map} +1 -1
  21. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs +1 -1
  22. package/fesm2022/acorex-platform-framework-client-layout-views.mjs +71 -10
  23. package/fesm2022/acorex-platform-framework-client-layout-views.mjs.map +1 -1
  24. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs +147 -171
  25. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs.map +1 -1
  26. package/fesm2022/{acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-Drmmu4HQ.mjs → acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-M8SZFPQx.mjs} +342 -60
  27. package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-M8SZFPQx.mjs.map +1 -0
  28. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BiuahYd8.mjs → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-DsLgZbZA.mjs} +3 -3
  29. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BiuahYd8.mjs.map → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-DsLgZbZA.mjs.map} +1 -1
  30. package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-CU_5b_te.mjs → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-Vpz3itLZ.mjs} +2 -2
  31. package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-CU_5b_te.mjs.map → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-Vpz3itLZ.mjs.map} +1 -1
  32. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +1 -1
  33. package/fesm2022/acorex-platform-framework-client-realtime.mjs +49 -7
  34. package/fesm2022/acorex-platform-framework-client-realtime.mjs.map +1 -1
  35. package/fesm2022/acorex-platform-framework-client-themes-default.mjs +40 -20
  36. package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -1
  37. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs +1 -1
  38. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs.map +1 -1
  39. package/i18n/en-AU/general.json +16 -4
  40. package/i18n/en-AU/layout.json +2 -1
  41. package/i18n/en-US/general.json +16 -4
  42. package/i18n/en-US/layout.json +2 -1
  43. package/i18n/fa-IR/general.json +16 -4
  44. package/i18n/fa-IR/layout.json +2 -1
  45. package/layout/widget-core/README.md +1 -1
  46. package/layout/widgets/README.md +2 -2
  47. package/package.json +2 -2
  48. package/types/acorex-platform-framework-client-auth.d.ts +15 -1
  49. package/types/acorex-platform-framework-client-common.d.ts +73 -7
  50. package/types/acorex-platform-framework-client-layout-components.d.ts +38 -7
  51. package/types/acorex-platform-framework-client-layout-entity.d.ts +86 -34
  52. package/types/acorex-platform-framework-client-layout-views.d.ts +15 -0
  53. package/types/acorex-platform-framework-client-layout-widget-core.d.ts +38 -13
  54. package/types/acorex-platform-framework-client-layout-widgets.d.ts +25 -7
  55. package/types/acorex-platform-framework-client-realtime.d.ts +5 -0
  56. package/fesm2022/acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-i9oZEXUR.mjs.map +0 -1
  57. package/fesm2022/acorex-platform-framework-client-layout-entity-attachments-page.component-DyrvSBEY.mjs.map +0 -1
  58. package/fesm2022/acorex-platform-framework-client-layout-entity-file-list-popup.component-C0LgUzzv.mjs.map +0 -1
  59. package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-Drmmu4HQ.mjs.map +0 -1
@@ -3,7 +3,7 @@ import { AXLocaleService } from '@acorex/core/locale';
3
3
  import * as i1$2 from '@acorex/components/button';
4
4
  import { AXButtonModule } from '@acorex/components/button';
5
5
  import * as i1$6 from '@acorex/cdk/common';
6
- import { AXCommonModule } from '@acorex/cdk/common';
6
+ import { AXCommonModule, AXDataSource } from '@acorex/cdk/common';
7
7
  import * as i2$1 from '@acorex/components/decorators';
8
8
  import { AXDecoratorModule } from '@acorex/components/decorators';
9
9
  import * as i3 from '@acorex/core/translation';
@@ -14,12 +14,12 @@ import * as i4$3 from '@acorex/core/format';
14
14
  import { AXFormatService, AXFormatModule } from '@acorex/core/format';
15
15
  import { AXPLayoutRendererComponent, AXPDialogOpener, AXPLayoutBuilderService, resolveLayoutBuilderDialogResult } from '@acorex-platform/framework-client/layout/builder';
16
16
  import * as i1 from '@angular/common';
17
- import { CommonModule, NgTemplateOutlet, AsyncPipe, isPlatformBrowser, NgComponentOutlet, DOCUMENT } from '@angular/common';
17
+ import { CommonModule, NgTemplateOutlet, AsyncPipe, isPlatformBrowser, DOCUMENT, NgComponentOutlet } from '@angular/common';
18
18
  import * as i0 from '@angular/core';
19
19
  import { inject, input, signal, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, output, computed, linkedSignal, InjectionToken, Injector, Injectable, Directive, viewChild, contentChild, ElementRef, afterNextRender, model, EventEmitter, forwardRef, ViewChild, Output, Input, untracked, DestroyRef, PLATFORM_ID, createComponent, EnvironmentInjector, runInInjectionContext, ApplicationRef, makeEnvironmentProviders, viewChildren, ViewChildren, TemplateRef, contentChildren } from '@angular/core';
20
20
  import { AXAccordionCdkModule } from '@acorex/cdk/accordion';
21
21
  import { AXTagModule } from '@acorex/components/tag';
22
- import { AXPSettingsService, AXPStateMessageComponent, AXPFileChooserSettings, normalizeStoredImageRef, extractFileExtension, AXPFileStorageService, AXPFileTypeProviderService, resolveFileTypeDisplay, AXPCommonSettings, coerceAXPSettingRawValueByKind, AXPFilterOperatorMiddlewareService, ALL_DEFAULT_OPERATORS, withDefaultMultiLanguageOnWidgetProperty, AXPDefaultMultiLanguageConfigService, resolveSearchableText, isStoredImageFileId, resolveStoredImageDisplayUrl } from '@acorex-platform/framework-client/common';
22
+ import { AXPSettingsService, AXPStateMessageComponent, openSystemFileDialog, AXPFileChooserSettings, normalizeStoredImageRef, extractFileExtension, AXPFileStorageService, AXPFileTypeProviderService, resolveFileTypeDisplay, AXPCommonSettings, coerceAXPSettingRawValueByKind, AXPFilterOperatorMiddlewareService, ALL_DEFAULT_OPERATORS, withDefaultMultiLanguageOnWidgetProperty, AXPDefaultMultiLanguageConfigService, resolveSearchableText, isStoredImageFileId, resolveStoredImageDisplayUrl, AXPUserStatusFeatureService } from '@acorex-platform/framework-client/common';
23
23
  export { AXPFileChooserSettings, AXPStateMessageComponent } from '@acorex-platform/framework-client/common';
24
24
  import * as i1$1 from '@acorex/components/avatar';
25
25
  import { AXAvatarModule } from '@acorex/components/avatar';
@@ -65,8 +65,8 @@ import { AXPopupService } from '@acorex/components/popup';
65
65
  import { moveItemInArray as moveItemInArray$1, AXDragDirective, AXDragHandleDirective, AXDropListDirective } from '@acorex/cdk/drag-drop';
66
66
  import { normalizeEntityListUserStylingRules, AXP_ENTITY_LIST_RECORD_STYLING_TARGET, createEntityListStylingCondition, isEntityListRecordStylingTarget, resolveEntityListFilterQueryField, resolveEntityListFilterContextField, isCustomQueryView } from '@acorex-platform/framework-shared/entity';
67
67
  import { AXLookupComponent } from '@acorex/components/lookup';
68
- import { DomSanitizer } from '@angular/platform-browser';
69
68
  import { AXToastService } from '@acorex/components/toast';
69
+ import { DomSanitizer } from '@angular/platform-browser';
70
70
  import { getFileExtension, AXFileService } from '@acorex/core/file';
71
71
  import { AXDialogService } from '@acorex/components/dialog';
72
72
  import { resolveFileViewerFileType, AXFileViewerContainerComponent, AXFileViewerService, AXFileViewerGalleryService } from '@acorex/components/file-viewer';
@@ -1490,7 +1490,7 @@ class AXPColorChooserComponent {
1490
1490
  this.dropdownWidth.set(`${Math.max(hostWidth, POPOVER_MIN_WIDTH_PX)}px`);
1491
1491
  }
1492
1492
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPColorChooserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1493
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPColorChooserComponent, isStandalone: true, selector: "axp-color-chooser", inputs: { groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, selectedClass: { classPropertyName: "selectedClass", publicName: "selectedClass", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, allowClear: { classPropertyName: "allowClear", publicName: "allowClear", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { classSelected: "classSelected" }, host: { listeners: { "click": "hostClickListener()" }, classAttribute: "axp-color-chooser" }, viewQueries: [{ propertyName: "paletteDropdown", first: true, predicate: ["paletteDropdown"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"__root\" [class.__disabled]=\"disabled()\" [class.__readonly]=\"readonly()\">\n @if (usePopover()) {\n <!-- ----- Same shell as ax-select-box: dropdown-box + input slot + panel ----- -->\n <ax-dropdown-box\n #paletteDropdown\n [disabled]=\"disabled()\"\n [popoverWidth]=\"dropdownWidth()\"\n (onOpened)=\"handleDropdownOpened()\"\n (onClosed)=\"handleDropdownClosed()\"\n >\n <ng-container input>\n <div class=\"ax-editor ax-content ax-input\">\n <ng-container *ngTemplateOutlet=\"selectedItem\"></ng-container>\n </div>\n @if (allowClear() && hasSelection() && isInteractive()) {\n <button\n type=\"button\"\n class=\"ax-general-button-icon\"\n tabindex=\"-1\"\n (click)=\"handleClear($event)\"\n >\n <span class=\"ax-icon ax-icon-close\"></span>\n </button>\n }\n <button type=\"button\" class=\"ax-general-button-icon\" [disabled]=\"!isInteractive()\" tabindex=\"-1\">\n <span\n class=\"ax-icon\"\n [class.ax-icon-chevron-down]=\"!dropdownOpen()\"\n [class.ax-icon-chevron-up]=\"dropdownOpen()\"\n ></span>\n </button>\n </ng-container>\n <ng-container panel>\n <div class=\"__popover\" [style.min-width]=\"dropdownWidth()\">\n <ng-container *ngTemplateOutlet=\"paletteGroups; context: { showTitles: true }\"></ng-container>\n </div>\n </ng-container>\n </ax-dropdown-box>\n }\n <!-- ----- Single named row stays inline at select height ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"paletteGroups; context: { showTitles: false }\"></ng-container>\n <!-- ----- Clear under the single inline strip ----- -->\n @if (allowClear()) {\n <button\n type=\"button\"\n class=\"__clear\"\n [class.__selected]=\"selectedClass() == null\"\n [disabled]=\"!isInteractive()\"\n (click)=\"handleClear($event)\"\n >\n <span class=\"ax-icon ax-icon-close\"></span>\n </button>\n }\n }\n</div>\n\n<ng-template #selectedItem>\n @if (selectedSwatch(); as swatch) {\n <!-- ----- Selected value as a surface-colored pill ----- -->\n <div class=\"__selected-item {{ swatch.className }}\">\n <span class=\"__selected-text\">\n <!-- ----- Group title before the selected variant ----- -->\n @if (selectedGroup()?.title; as groupTitle) {\n {{ groupTitle | translate | async }}\n <span class=\"__trigger-sep\">\u00B7</span>\n }\n {{ displayLabel(swatch.label) | translate | async }}\n </span>\n </div>\n }\n <!-- ----- Empty state uses the same control height as a select ----- -->\n @else {\n <div class=\"ax-placeholder\">\n {{ '@platform-layout-widgets:widgets.color-chooser.placeholder' | translate | async }}\n </div>\n }\n</ng-template>\n\n<ng-template #paletteGroups let-showTitles=\"showTitles\">\n <div class=\"__groups\" [class.__look-strip]=\"look() === 'strip'\" [class.__look-swatches]=\"look() === 'swatches'\">\n @for (group of resolvedGroups(); track group.id) {\n <div class=\"__group\">\n <!-- ----- Named row title inside the dropdown list ----- -->\n @if (showTitles && group.title) {\n <div class=\"__group-title\">{{ group.title | translate | async }}</div>\n }\n <!-- ----- Coolors bar: thin columns, hover expands and shows the label ----- -->\n <div class=\"__strip\" role=\"listbox\">\n @for (swatch of group.swatches; track swatch.className) {\n <button\n type=\"button\"\n class=\"__column {{ swatch.className }}\"\n [class.__selected]=\"isSelected(swatch.className)\"\n [disabled]=\"!isInteractive()\"\n [attr.aria-label]=\"displayLabel(swatch.label)\"\n [attr.aria-selected]=\"isSelected(swatch.className)\"\n (click)=\"handleSelect(swatch)\"\n >\n <span class=\"__label\">{{ displayLabel(swatch.label) | translate | async }}</span>\n </button>\n }\n </div>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;min-height:var(--ax-sys-size-base, 2.5rem);width:100%}:host ax-dropdown-box{width:100%}:host .ax-editor-container{padding-block:0}:host .ax-content{display:flex;min-height:var(--ax-sys-size-base, 2.5rem);min-width:0;flex:1;cursor:pointer;align-items:center;outline:none;-webkit-user-select:none;user-select:none}.__root{display:flex;flex-direction:column;gap:.5rem}.__selected-item{display:inline-flex;align-items:center;max-width:100%;min-height:1.5rem;padding-inline:.5rem;border-radius:.375rem}.__selected-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__placeholder{opacity:.65}.__trigger-sep{margin-inline:.25rem}.__popover{box-sizing:border-box;width:100%;max-height:min(24rem,70vh);overflow:auto;padding:.75rem}.__groups{display:flex;flex-direction:column;gap:.75rem;min-width:0}.__group-title{font-size:.75rem;font-weight:500;color:rgb(var(--ax-sys-color-on-lighter-surface))}.__strip{display:flex;flex-wrap:nowrap;align-items:stretch;width:100%;height:var(--ax-sys-size-base, 2.5rem);overflow:hidden;border-radius:.5rem}.__column{position:relative;flex:1 1 0;min-width:0;margin:0;padding:0;border:0;border-radius:0;appearance:none;cursor:pointer;transition:flex .22s ease}.__label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;font-size:var(--ax-sys-text-xs-base, .75rem);font-weight:600;letter-spacing:.04em;white-space:nowrap;opacity:0;transition:opacity .16s ease}.__look-strip .__column.__selected,.__look-strip .__column:hover:not(:disabled),.__look-strip .__column:focus-visible:not(:disabled){flex:4 1 0}.__look-strip .__column.__selected .__label,.__look-strip .__column:hover:not(:disabled) .__label,.__look-strip .__column:focus-visible:not(:disabled) .__label{opacity:1}.__look-strip .__strip:has(.__column:hover:not(.__selected)) .__column.__selected:not(:hover),.__look-strip .__strip:has(.__column:focus-visible:not(.__selected)) .__column.__selected:not(:focus-visible){flex:1 1 0}.__look-strip .__strip:has(.__column:hover:not(.__selected)) .__column.__selected:not(:hover) .__label,.__look-strip .__strip:has(.__column:focus-visible:not(.__selected)) .__column.__selected:not(:focus-visible) .__label{opacity:0}.__column.__selected{box-shadow:inset 0 0 0 2px rgb(var(--ax-sys-color-on-lighter-surface) / .4)}.__column:disabled{cursor:not-allowed}.__clear{align-self:flex-start;display:inline-flex;height:1.75rem;width:1.75rem;align-items:center;justify-content:center;border-radius:999px;border:1px dashed rgb(var(--ax-sys-color-border-lighter-surface));background:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));font-size:.75rem}.__clear.__selected,.__clear:focus-visible:not(:disabled){outline:2px solid rgb(var(--ax-sys-color-primary));outline-offset:2px}.__clear:disabled{cursor:not-allowed;opacity:.5}.__look-swatches .__strip{height:auto;flex-wrap:wrap;gap:.25rem;overflow:visible;border-radius:0}.__look-swatches .__column{flex:0 0 2rem;width:2rem;height:2rem;min-width:2rem;border-radius:.375rem;transition:transform .16s ease}.__look-swatches .__label{display:none}.__look-swatches .__column:hover:not(:disabled),.__look-swatches .__column:focus-visible:not(:disabled){flex:0 0 2rem;transform:scale(1.08)}.__disabled .__column,.__readonly .__column,.__disabled .__clear,.__readonly .__clear,.__disabled .ax-content,.__readonly .ax-content{cursor:default}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownBoxComponent, selector: "ax-dropdown-box", inputs: ["disabled", "look", "hasInput", "popoverWidth"], outputs: ["disabledChange", "onBlur", "onFocus", "onClick", "onOpened", "onClosed"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1493
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPColorChooserComponent, isStandalone: true, selector: "axp-color-chooser", inputs: { groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, selectedClass: { classPropertyName: "selectedClass", publicName: "selectedClass", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, allowClear: { classPropertyName: "allowClear", publicName: "allowClear", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { classSelected: "classSelected" }, host: { listeners: { "click": "hostClickListener()" }, classAttribute: "axp-color-chooser" }, viewQueries: [{ propertyName: "paletteDropdown", first: true, predicate: ["paletteDropdown"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"__root\" [class.__disabled]=\"disabled()\" [class.__readonly]=\"readonly()\">\n @if (usePopover()) {\n <!-- ----- Same shell as ax-select-box: dropdown-box + input slot + panel ----- -->\n <ax-dropdown-box\n #paletteDropdown\n [disabled]=\"disabled()\"\n [popoverWidth]=\"dropdownWidth()\"\n (onOpened)=\"handleDropdownOpened()\"\n (onClosed)=\"handleDropdownClosed()\"\n >\n <ng-container input>\n <div class=\"ax-editor ax-content ax-input\">\n <ng-container *ngTemplateOutlet=\"selectedItem\"></ng-container>\n </div>\n @if (allowClear() && hasSelection() && isInteractive()) {\n <button\n type=\"button\"\n class=\"ax-general-button-icon\"\n tabindex=\"-1\"\n (click)=\"handleClear($event)\"\n >\n <span class=\"ax-icon ax-icon-close\"></span>\n </button>\n }\n <button type=\"button\" class=\"ax-general-button-icon\" [disabled]=\"!isInteractive()\" tabindex=\"-1\">\n <span\n class=\"ax-icon\"\n [class.ax-icon-chevron-down]=\"!dropdownOpen()\"\n [class.ax-icon-chevron-up]=\"dropdownOpen()\"\n ></span>\n </button>\n </ng-container>\n <ng-container panel>\n <div class=\"__popover\" [style.min-width]=\"dropdownWidth()\">\n <ng-container *ngTemplateOutlet=\"paletteGroups; context: { showTitles: true }\"></ng-container>\n </div>\n </ng-container>\n </ax-dropdown-box>\n }\n <!-- ----- Single named row stays inline at select height ----- -->\n @else {\n <ng-container *ngTemplateOutlet=\"paletteGroups; context: { showTitles: false }\"></ng-container>\n <!-- ----- Clear under the single inline strip ----- -->\n @if (allowClear()) {\n <button\n type=\"button\"\n class=\"__clear\"\n [class.__selected]=\"selectedClass() == null\"\n [disabled]=\"!isInteractive()\"\n (click)=\"handleClear($event)\"\n >\n <span class=\"ax-icon ax-icon-close\"></span>\n </button>\n }\n }\n</div>\n\n<ng-template #selectedItem>\n @if (selectedSwatch(); as swatch) {\n <!-- ----- Selected value as a surface-colored pill ----- -->\n <div class=\"__selected-item {{ swatch.className }}\">\n <span class=\"__selected-text\">\n <!-- ----- Group title before the selected variant ----- -->\n @if (selectedGroup()?.title; as groupTitle) {\n {{ groupTitle | translate | async }}\n <span class=\"__trigger-sep\">\u00B7</span>\n }\n {{ displayLabel(swatch.label) | translate | async }}\n </span>\n </div>\n }\n <!-- ----- Empty state uses the same control height as a select ----- -->\n @else {\n <div class=\"ax-placeholder\">\n {{ '@platform-layout-widgets:widgets.color-chooser.placeholder' | translate | async }}\n </div>\n }\n</ng-template>\n\n<ng-template #paletteGroups let-showTitles=\"showTitles\">\n <div class=\"__groups\" [class.__look-strip]=\"look() === 'strip'\" [class.__look-swatches]=\"look() === 'swatches'\">\n @for (group of resolvedGroups(); track group.id) {\n <div class=\"__group\">\n <!-- ----- Named row title inside the dropdown list ----- -->\n @if (showTitles && group.title) {\n <div class=\"__group-title\">{{ group.title | translate | async }}</div>\n }\n <!-- ----- Coolors bar: thin columns, hover expands and shows the label ----- -->\n <div class=\"__strip\" role=\"listbox\">\n @for (swatch of group.swatches; track swatch.className) {\n <button\n type=\"button\"\n class=\"__column {{ swatch.className }}\"\n [class.__selected]=\"isSelected(swatch.className)\"\n [disabled]=\"!isInteractive()\"\n [attr.aria-label]=\"displayLabel(swatch.label)\"\n [attr.aria-selected]=\"isSelected(swatch.className)\"\n (click)=\"handleSelect(swatch)\"\n >\n <span class=\"__label\">{{ displayLabel(swatch.label) | translate | async }}</span>\n </button>\n }\n </div>\n </div>\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;min-height:var(--ax-sys-size-base, 2.5rem);width:100%}:host ax-dropdown-box{width:100%}:host .ax-editor-container{padding-block:0}:host .ax-content{display:flex;min-height:var(--ax-sys-size-base, 2.5rem);min-width:0;flex:1;cursor:pointer;align-items:center;outline:none;-webkit-user-select:none;user-select:none}.__root{display:flex;flex-direction:column;gap:.5rem}.__selected-item{display:inline-flex;align-items:center;max-width:100%;min-height:1.5rem;padding-inline:.5rem;border-radius:.375rem}.__selected-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.__placeholder{opacity:.65}.__trigger-sep{margin-inline:.25rem}.__popover{box-sizing:border-box;width:100%;max-height:min(24rem,70vh);overflow:auto;padding:.75rem}.__groups{display:flex;flex-direction:column;gap:.75rem;min-width:0}.__group-title{font-size:.75rem;font-weight:500;color:rgb(var(--ax-sys-color-on-lighter-surface))}.__strip{display:flex;flex-wrap:nowrap;align-items:stretch;width:100%;height:var(--ax-sys-size-base, 2.5rem);overflow:hidden;border-radius:.5rem}.__column{position:relative;flex:1 1 0;min-width:0;margin:0;padding:0;border:0;border-radius:0;appearance:none;cursor:pointer;transition:flex .22s ease}.__label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;font-size:var(--ax-sys-text-xs-base, .75rem);font-weight:600;letter-spacing:.04em;white-space:nowrap;opacity:0;transition:opacity .16s ease}.__look-strip .__column.__selected,.__look-strip .__column:hover:not(:disabled),.__look-strip .__column:focus-visible:not(:disabled){flex:4 1 0}.__look-strip .__column.__selected .__label,.__look-strip .__column:hover:not(:disabled) .__label,.__look-strip .__column:focus-visible:not(:disabled) .__label{opacity:1}.__look-strip .__strip:has(.__column:hover:not(.__selected)) .__column.__selected:not(:hover),.__look-strip .__strip:has(.__column:focus-visible:not(.__selected)) .__column.__selected:not(:focus-visible){flex:1 1 0}.__look-strip .__strip:has(.__column:hover:not(.__selected)) .__column.__selected:not(:hover) .__label,.__look-strip .__strip:has(.__column:focus-visible:not(.__selected)) .__column.__selected:not(:focus-visible) .__label{opacity:0}.__column.__selected{box-shadow:inset 0 0 0 2px rgb(var(--ax-sys-color-on-lighter-surface) / .4)}.__column:disabled{cursor:not-allowed}.__clear{align-self:flex-start;display:inline-flex;height:1.75rem;width:1.75rem;align-items:center;justify-content:center;border-radius:999px;border:1px dashed rgb(var(--ax-sys-color-border-lighter-surface));background:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));font-size:.75rem}.__clear.__selected,.__clear:focus-visible:not(:disabled){outline:2px solid rgb(var(--ax-sys-color-primary));outline-offset:2px}.__clear:disabled{cursor:not-allowed;opacity:.5}.__look-swatches .__strip{height:auto;flex-wrap:wrap;gap:.25rem;overflow:visible;border-radius:0}.__look-swatches .__column{flex:0 0 2rem;width:2rem;height:2rem;min-width:2rem;border-radius:.375rem;transition:transform .16s ease}.__look-swatches .__label{display:none}.__look-swatches .__column:hover:not(:disabled),.__look-swatches .__column:focus-visible:not(:disabled){flex:0 0 2rem;transform:scale(1.08)}.__disabled .__column,.__readonly .__column,.__disabled .__clear,.__readonly .__clear,.__disabled .ax-content,.__readonly .ax-content{cursor:default}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownBoxComponent, selector: "ax-dropdown-box", inputs: ["disabled", "look", "hasInput", "popoverWidth", "popoverAnchor"], outputs: ["disabledChange", "onBlur", "onFocus", "onClick", "onOpened", "onClosed"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1494
1494
  }
1495
1495
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPColorChooserComponent, decorators: [{
1496
1496
  type: Component,
@@ -1696,7 +1696,7 @@ class AXPColumnItemListComponent {
1696
1696
  </div>
1697
1697
  </div>
1698
1698
  </ax-popover>
1699
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "closeOnNavigation", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1699
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "restoreFocusOnClose", "openAfter", "closeAfter", "closeOnScroll", "closeOnNavigation", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1700
1700
  }
1701
1701
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPColumnItemListComponent, decorators: [{
1702
1702
  type: Component,
@@ -3486,7 +3486,7 @@ class AXPConditionBuilderConditionComponent {
3486
3486
  }
3487
3487
  }
3488
3488
  onContextChange(event) {
3489
- if (event.state !== 'changed' || event.origin === 'system') {
3489
+ if (event.state !== 'changed' || event.origin === 'system' || event.origin === 'hydrate') {
3490
3490
  return;
3491
3491
  }
3492
3492
  const filterData = event.data?.filter;
@@ -3511,7 +3511,7 @@ class AXPConditionBuilderConditionComponent {
3511
3511
  this.removeItem.emit(this.item().id ?? '');
3512
3512
  }
3513
3513
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPConditionBuilderConditionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3514
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPConditionBuilderConditionComponent, isStandalone: true, selector: "axp-condition-builder-condition", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, filterDefinitions: { classPropertyName: "filterDefinitions", publicName: "filterDefinitions", isSignal: true, isRequired: false, transformFunction: null }, onResolveWidget: { classPropertyName: "onResolveWidget", publicName: "onResolveWidget", isSignal: true, isRequired: false, transformFunction: null }, showFillByUser: { classPropertyName: "showFillByUser", publicName: "showFillByUser", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, operationsLook: { classPropertyName: "operationsLook", publicName: "operationsLook", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChange: "itemChange", removeItem: "removeItem" }, ngImport: i0, template: "<div class=\"__condition-row\" [class.__condition-row--comfortable]=\"!compact()\">\n <div class=\"__item-content\">\n <!-- Field Selector -->\n <div class=\"__field-selector\">\n <ax-lookup\n mode=\"drop-down-list\"\n [class.ax-sm]=\"compact()\"\n [dataSource]=\"availableFields()\"\n [ngModel]=\"selectedFieldValue()\"\n (onValueChanged)=\"onFieldChange($event)\"\n valueField=\"value\"\n textField=\"text\"\n [searchable]=\"false\"\n [placeholder]=\"('@data-management:metadata-definitions.components.query-builder.condition.select-field' | translate | async) || 'Select a field'\"\n [look]=\"'outline'\">\n </ax-lookup>\n </div>\n\n <!-- Filter Widget (Operator + Value) -->\n <div class=\"__operator-selector\">\n @if (filterHostKeys().length) {\n <!-- ----- Operator and value for the selected field ----- -->\n @for (hostKey of filterHostKeys(); track hostKey) {\n <axp-widgets-container\n class=\"__filter-widget-container\"\n [context]=\"context()\"\n (onContextChanged)=\"onContextChange($event)\">\n <ng-container axp-widget-renderer [node]=\"filterNode()\" [mode]=\"'edit'\">\n </ng-container>\n </axp-widgets-container>\n }\n }\n <!-- ----- Prompt until a field is chosen ----- -->\n @else {\n <div class=\"__filter-placeholder\">\n <span class=\"__placeholder-text\">{{\n ('@data-management:metadata-definitions.components.query-builder.condition.select-field-first' | translate | async) || 'Select a field first'\n }}</span>\n </div>\n }\n </div>\n\n <!-- Fill By User (optional) -->\n @if (showFillByUser()) {\n <div class=\"__fill-by-user\">\n <ax-check-box\n class=\"text-xs\"\n [ngModel]=\"$safeNavigationMigration(selectedField()?.isParametric)\"\n (ngModelChange)=\"onFillByUserChange($event)\">\n <ax-label>\n {{ '@data-management:metadata-definitions.components.query-builder.condition.fill-by-user' | translate | async }}\n </ax-label>\n </ax-check-box>\n </div>\n }\n </div>\n</div>\n", styles: ["@layer properties;.__condition-row{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 3)}.__condition-row .__item-content{display:flex;flex:1;align-items:center;gap:calc(var(--spacing, .25rem) * 3);display:grid;grid-template-columns:1fr 1fr;gap:.75rem}.__condition-row .__item-content .__field-selector{min-width:0px}.__condition-row .__item-content .__field-selector ax-lookup{width:100%}.__condition-row .__item-content .__operator-selector{min-width:0px}.__condition-row .__item-content .__operator-selector .__filter-widget-container{width:100%}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep .axp-widgets-container{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 3)}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-lookup{min-width:140px}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep axp-filter-operations.axp-filter-operations--select{min-width:9rem}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-text-box,.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-number-box,.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-date-time-box{flex:1}.__condition-row .__item-content .__operator-selector .__filter-placeholder{display:flex;align-items:center;justify-content:center;border-radius:.25rem;border-style:var(--tw-border-style);--tw-border-style: dashed;border-style:dashed;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding:calc(var(--spacing, .25rem) * 3);border-color:rgba(var(--ax-sys-color-border-lighter-surface),1);border-width:1px}.__condition-row .__item-content .__operator-selector .__filter-placeholder .__placeholder-text{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-neutral-500, oklch(55.6% 0 none));font-style:italic}.__condition-row .__item-content .__fill-by-user{grid-column:1 / -1}.__condition-row.__condition-row--comfortable .__field-selector ax-lookup,.__condition-row.__condition-row--comfortable .__filter-placeholder{min-height:var(--ax-sys-size-base, 2.5rem)}.__condition-row.__condition-row--comfortable .__filter-placeholder{justify-content:flex-start;padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:0px}.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-text-box,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-number-box,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-date-time-box,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-lookup,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep .ax-editor-container{min-height:var(--ax-sys-size-base, 2.5rem)}@media(max-width:768px){.__condition-row{flex-direction:column;align-items:stretch}.__condition-row .__item-content{grid-template-columns:1fr}}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXLookupComponent, selector: "ax-lookup", inputs: ["name", "mode", "dataSource", "treeDataSource", "valueField", "textField", "disabledField", "columns", "treeParentField", "hasChildrenField", "searchable", "adaptivityEnabled", "caption", "alternate", "searchPlaceholder", "placeholder", "disabled", "readonly", "look", "itemHeight", "maxVisibleItems", "treeSelectionBehavior", "highlightSearch", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "value", "valueItems"], outputs: ["lookChange", "valueChange", "onValueChanged", "onSelectionChanged", "onFocus", "onBlur", "onItemClick", "onItemSelected", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i2$3.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i3$4.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1$5.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1$5.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3514
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPConditionBuilderConditionComponent, isStandalone: true, selector: "axp-condition-builder-condition", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, filterDefinitions: { classPropertyName: "filterDefinitions", publicName: "filterDefinitions", isSignal: true, isRequired: false, transformFunction: null }, onResolveWidget: { classPropertyName: "onResolveWidget", publicName: "onResolveWidget", isSignal: true, isRequired: false, transformFunction: null }, showFillByUser: { classPropertyName: "showFillByUser", publicName: "showFillByUser", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, operationsLook: { classPropertyName: "operationsLook", publicName: "operationsLook", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChange: "itemChange", removeItem: "removeItem" }, ngImport: i0, template: "<div class=\"__condition-row\" [class.__condition-row--comfortable]=\"!compact()\">\n <div class=\"__item-content\">\n <!-- Field Selector -->\n <div class=\"__field-selector\">\n <ax-lookup\n mode=\"drop-down-list\"\n [class.ax-sm]=\"compact()\"\n [dataSource]=\"availableFields()\"\n [ngModel]=\"selectedFieldValue()\"\n (onValueChanged)=\"onFieldChange($event)\"\n valueField=\"value\"\n textField=\"text\"\n [searchable]=\"false\"\n [placeholder]=\"('@data-management:metadata-definitions.components.query-builder.condition.select-field' | translate | async) || 'Select a field'\"\n [look]=\"'outline'\">\n </ax-lookup>\n </div>\n\n <!-- Filter Widget (Operator + Value) -->\n <div class=\"__operator-selector\">\n @if (filterHostKeys().length) {\n <!-- ----- Operator and value for the selected field ----- -->\n @for (hostKey of filterHostKeys(); track hostKey) {\n <axp-widgets-container\n class=\"__filter-widget-container\"\n [context]=\"context()\"\n (onContextChanged)=\"onContextChange($event)\">\n <ng-container axp-widget-renderer [node]=\"filterNode()\" [mode]=\"'edit'\">\n </ng-container>\n </axp-widgets-container>\n }\n }\n <!-- ----- Prompt until a field is chosen ----- -->\n @else {\n <div class=\"__filter-placeholder\">\n <span class=\"__placeholder-text\">{{\n ('@data-management:metadata-definitions.components.query-builder.condition.select-field-first' | translate | async) || 'Select a field first'\n }}</span>\n </div>\n }\n </div>\n\n <!-- Fill By User (optional) -->\n @if (showFillByUser()) {\n <div class=\"__fill-by-user\">\n <ax-check-box\n class=\"text-xs\"\n [ngModel]=\"$safeNavigationMigration(selectedField()?.isParametric)\"\n (ngModelChange)=\"onFillByUserChange($event)\">\n <ax-label>\n {{ '@data-management:metadata-definitions.components.query-builder.condition.fill-by-user' | translate | async }}\n </ax-label>\n </ax-check-box>\n </div>\n }\n </div>\n</div>\n", styles: ["@layer properties;.__condition-row{display:flex;width:100%;align-items:center;gap:calc(var(--spacing, .25rem) * 3)}.__condition-row .__item-content{display:flex;flex:1;align-items:center;gap:calc(var(--spacing, .25rem) * 3);display:grid;grid-template-columns:1fr 1fr;gap:.75rem}.__condition-row .__item-content .__field-selector{min-width:0px}.__condition-row .__item-content .__field-selector ax-lookup{width:100%}.__condition-row .__item-content .__operator-selector{min-width:0px}.__condition-row .__item-content .__operator-selector .__filter-widget-container{width:100%}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep .axp-widgets-container{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 3)}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-lookup{min-width:140px}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep axp-filter-operations.axp-filter-operations--select{min-width:9rem}.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-text-box,.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-number-box,.__condition-row .__item-content .__operator-selector .__filter-widget-container ::ng-deep ax-date-time-box{flex:1}.__condition-row .__item-content .__operator-selector .__filter-placeholder{display:flex;align-items:center;justify-content:center;border-radius:.25rem;border-style:var(--tw-border-style);--tw-border-style: dashed;border-style:dashed;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding:calc(var(--spacing, .25rem) * 3);border-color:rgba(var(--ax-sys-color-border-lighter-surface),1);border-width:1px}.__condition-row .__item-content .__operator-selector .__filter-placeholder .__placeholder-text{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-neutral-500, oklch(55.6% 0 none));font-style:italic}.__condition-row .__item-content .__fill-by-user{grid-column:1 / -1}.__condition-row.__condition-row--comfortable .__field-selector ax-lookup,.__condition-row.__condition-row--comfortable .__filter-placeholder{min-height:var(--ax-sys-size-base, 2.5rem)}.__condition-row.__condition-row--comfortable .__filter-placeholder{justify-content:flex-start;padding-inline:calc(var(--spacing, .25rem) * 3);padding-block:0px}.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-text-box,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-number-box,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-date-time-box,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep ax-lookup,.__condition-row.__condition-row--comfortable .__operator-selector ::ng-deep .ax-editor-container{min-height:var(--ax-sys-size-base, 2.5rem)}@media(max-width:768px){.__condition-row{flex-direction:column;align-items:stretch}.__condition-row .__item-content{grid-template-columns:1fr}}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXLookupComponent, selector: "ax-lookup", inputs: ["name", "mode", "dataSource", "treeDataSource", "valueField", "textField", "disabledField", "columns", "treeParentField", "hasChildrenField", "searchable", "adaptivityEnabled", "caption", "alternate", "searchPlaceholder", "placeholder", "disabled", "readonly", "look", "itemHeight", "maxVisibleItems", "treeSelectionBehavior", "highlightSearch", "allowSelectAll", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "value", "valueItems", "prefetch"], outputs: ["lookChange", "valueChange", "onValueChanged", "onSelectionChanged", "onFocus", "onBlur", "onItemClick", "onItemSelected", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i2$3.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i3$4.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1$5.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1$5.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3515
3515
  }
3516
3516
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPConditionBuilderConditionComponent, decorators: [{
3517
3517
  type: Component,
@@ -4066,7 +4066,7 @@ class AXPFileProviderMenuComponent {
4066
4066
  </ax-button-item-list>
4067
4067
  </div>
4068
4068
  </ax-popover>
4069
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "closeOnNavigation", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$2.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { 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: AXTranslationModule }, { kind: "component", type: AXPFileProviderIconComponent, selector: "axp-file-provider-icon", inputs: ["icon"] }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
4069
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "restoreFocusOnClose", "openAfter", "closeAfter", "closeOnScroll", "closeOnNavigation", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$2.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { 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: AXTranslationModule }, { kind: "component", type: AXPFileProviderIconComponent, selector: "axp-file-provider-icon", inputs: ["icon"] }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
4070
4070
  }
4071
4071
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPFileProviderMenuComponent, decorators: [{
4072
4072
  type: Component,
@@ -4264,36 +4264,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
4264
4264
  args: [{ providedIn: 'root' }]
4265
4265
  }] });
4266
4266
 
4267
- //#region ---- Rejection notifications ----
4268
- async function notifyFileAcceptRejections(rejected, deps) {
4269
- if (rejected.length === 0) {
4270
- return;
4271
- }
4272
- const { translateService, toastService, maxFileSize } = deps;
4273
- const errorTitle = await translateService.translateAsync('@general:messages.error.title');
4274
- const typeRejections = rejected.filter((entry) => entry.reason === 'type');
4275
- const sizeRejections = rejected.filter((entry) => entry.reason === 'size');
4276
- if (typeRejections.length === 1) {
4277
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed', { params: { fileName: typeRejections[0].file.name } });
4278
- toastService.show({ color: 'danger', title: errorTitle, content });
4279
- return;
4280
- }
4281
- if (typeRejections.length > 1) {
4282
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed-summary', { params: { count: typeRejections.length } });
4283
- toastService.show({ color: 'danger', title: errorTitle, content });
4284
- return;
4285
- }
4286
- if (sizeRejections.length === 1) {
4287
- const maxMb = Math.round((maxFileSize / (1024 * 1024)) * 10) / 10;
4288
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-size-exceeds-limit', { params: { fileName: sizeRejections[0].file.name, maxSizeMb: maxMb } });
4289
- toastService.show({ color: 'danger', title: errorTitle, content });
4290
- return;
4291
- }
4292
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.files-rejected-summary', { params: { count: rejected.length } });
4293
- toastService.show({ color: 'danger', title: errorTitle, content });
4294
- }
4295
- //#endregion
4296
-
4297
4267
  //#endregion
4298
4268
  //#region ---- Validation ----
4299
4269
  function isUnrestrictedFileAccept(accept) {
@@ -4478,6 +4448,36 @@ function matchesCategoryByExtension(fileName, category) {
4478
4448
  }
4479
4449
  //#endregion
4480
4450
 
4451
+ //#region ---- Rejection notifications ----
4452
+ async function notifyFileAcceptRejections(rejected, deps) {
4453
+ if (rejected.length === 0) {
4454
+ return;
4455
+ }
4456
+ const { translateService, toastService, maxFileSize } = deps;
4457
+ const errorTitle = await translateService.translateAsync('@general:messages.generic.error.title');
4458
+ const typeRejections = rejected.filter((entry) => entry.reason === 'type');
4459
+ const sizeRejections = rejected.filter((entry) => entry.reason === 'size');
4460
+ if (typeRejections.length === 1) {
4461
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed', { params: { fileName: typeRejections[0].file.name } });
4462
+ toastService.show({ color: 'danger', title: errorTitle, content });
4463
+ }
4464
+ else if (typeRejections.length > 1) {
4465
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed-summary', { params: { count: typeRejections.length } });
4466
+ toastService.show({ color: 'danger', title: errorTitle, content });
4467
+ }
4468
+ if (sizeRejections.length === 1) {
4469
+ const maxSize = formatMaxFileSizeForDisplay(maxFileSize);
4470
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-size-exceeds-limit', { params: { fileName: sizeRejections[0].file.name, maxSize } });
4471
+ toastService.show({ color: 'danger', title: errorTitle, content });
4472
+ return;
4473
+ }
4474
+ if (sizeRejections.length > 1) {
4475
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.files-rejected-summary', { params: { count: sizeRejections.length } });
4476
+ toastService.show({ color: 'danger', title: errorTitle, content });
4477
+ }
4478
+ }
4479
+ //#endregion
4480
+
4481
4481
  //#region ---- Accept resolution ----
4482
4482
  const ZIP_ACCEPT_TOKENS = '.zip,application/zip';
4483
4483
  /**
@@ -4503,7 +4503,8 @@ function resolveFileChooserAccept(accept, promptZipOnMultiple) {
4503
4503
  //#endregion
4504
4504
 
4505
4505
  //#region ---- Chooser result validation ----
4506
- function fileFromListItem(item) {
4506
+ /** Blob-backed chooser item as a {@link File}. Drive and file-id items return undefined. */
4507
+ function resolveChooserItemFile(item) {
4507
4508
  const source = item.source;
4508
4509
  if (source?.kind !== 'blob' || source.value == null) {
4509
4510
  return undefined;
@@ -4512,7 +4513,8 @@ function fileFromListItem(item) {
4512
4513
  return source.value;
4513
4514
  }
4514
4515
  if (source.value instanceof Blob) {
4515
- return new File([source.value], item.name, {
4516
+ const name = item.name?.trim() || 'file';
4517
+ return new File([source.value], name, {
4516
4518
  type: source.value.type ?? '',
4517
4519
  });
4518
4520
  }
@@ -4525,30 +4527,38 @@ function validateFileChooserItems(items, options) {
4525
4527
  const accept = options['accept'];
4526
4528
  const maxFileSize = defaultTo(options['maxFileSize'], 0);
4527
4529
  const passthrough = [];
4528
- const blobItems = [];
4529
- const blobFiles = [];
4530
+ const blobEntries = [];
4530
4531
  for (const item of items) {
4531
- const file = fileFromListItem(item);
4532
+ const file = resolveChooserItemFile(item);
4532
4533
  if (file) {
4533
- blobItems.push(item);
4534
- blobFiles.push(file);
4534
+ blobEntries.push({ item, file });
4535
4535
  continue;
4536
4536
  }
4537
4537
  passthrough.push(item);
4538
4538
  }
4539
- const namedAccepted = passthrough.filter((item) => isUnrestrictedFileAccept(accept) || fileNameMatchesAccept(item.name ?? '', accept));
4540
- const namedRejected = passthrough
4541
- .filter((item) => !namedAccepted.includes(item))
4542
- .map((item) => ({
4543
- file: new File([], item.name ?? 'file', { type: '' }),
4544
- reason: 'type',
4545
- }));
4546
- if (!blobFiles.length) {
4539
+ const namedAccepted = [];
4540
+ const namedRejected = [];
4541
+ for (const item of passthrough) {
4542
+ const placeholder = new File([], item.name ?? 'file', { type: '' });
4543
+ const typeOk = isUnrestrictedFileAccept(accept) || fileNameMatchesAccept(item.name ?? '', accept);
4544
+ if (!typeOk) {
4545
+ namedRejected.push({ file: placeholder, reason: 'type' });
4546
+ continue;
4547
+ }
4548
+ if (maxFileSize > 0 && (item.size ?? 0) > maxFileSize) {
4549
+ namedRejected.push({ file: placeholder, reason: 'size' });
4550
+ continue;
4551
+ }
4552
+ namedAccepted.push(item);
4553
+ }
4554
+ if (!blobEntries.length) {
4547
4555
  return { accepted: namedAccepted, rejected: namedRejected };
4548
4556
  }
4549
- const { accepted, rejected } = filterFilesByAcceptAndMaxSize(blobFiles, accept, maxFileSize);
4557
+ const { accepted, rejected } = filterFilesByAcceptAndMaxSize(blobEntries.map((entry) => entry.file), accept, maxFileSize);
4550
4558
  const acceptedSet = new Set(accepted);
4551
- const acceptedItems = blobItems.filter((item) => acceptedSet.has(fileFromListItem(item)));
4559
+ const acceptedItems = blobEntries
4560
+ .filter((entry) => acceptedSet.has(entry.file))
4561
+ .map((entry) => entry.item);
4552
4562
  return {
4553
4563
  accepted: [...namedAccepted, ...acceptedItems],
4554
4564
  rejected: [...namedRejected, ...rejected],
@@ -4564,9 +4574,7 @@ const AXPFileChooserHookKeys = {
4564
4574
 
4565
4575
  //#region ---- File chooser tokens ----
4566
4576
  /**
4567
-
4568
4577
  * Multi token for file chooser providers (system disk, drive, external systems).
4569
-
4570
4578
  */
4571
4579
  const AXP_FILE_CHOOSER_PROVIDERS = new InjectionToken('AXP_FILE_CHOOSER_PROVIDERS');
4572
4580
  //#endregion
@@ -4578,14 +4586,37 @@ const AXP_SYSTEM_FILE_CHOOSER_PROVIDER = {
4578
4586
  order: 1,
4579
4587
  choose: async (context) => {
4580
4588
  const fileService = inject(AXFileService);
4589
+ const documentRef = inject(DOCUMENT);
4590
+ const translateService = inject(AXTranslationService);
4591
+ const toastService = inject(AXToastService);
4581
4592
  const multiple = Boolean(context.options['multiple']);
4582
4593
  const fileType = context.options['fileType'];
4583
- const accept = context.options['accept'];
4584
- const files = await fileService.choose({
4585
- fileType,
4586
- accept,
4587
- multiple,
4588
- });
4594
+ const acceptOption = context.options['accept'];
4595
+ const maxFileSizeOption = context.options['maxFileSize'];
4596
+ const maxFileSize = typeof maxFileSizeOption === 'number' ? maxFileSizeOption : 0;
4597
+ const accept = fileType
4598
+ ? (acceptOption ?? (await fileService.getAcceptAttribute(fileType)))
4599
+ : (acceptOption ?? '');
4600
+ const picked = await openSystemFileDialog(documentRef, { accept, multiple });
4601
+ if (!picked.length) {
4602
+ return undefined;
4603
+ }
4604
+ let files = picked;
4605
+ if (fileType) {
4606
+ const validation = await fileService.validateMany(picked, fileType);
4607
+ files = validation.accepted;
4608
+ if (validation.rejected.length > 0) {
4609
+ const rejected = validation.rejected.map((entry) => ({
4610
+ file: entry.file,
4611
+ reason: catalogRejectionReason(entry.errors, maxFileSize),
4612
+ }));
4613
+ await notifyFileAcceptRejections(rejected, {
4614
+ translateService,
4615
+ toastService,
4616
+ maxFileSize,
4617
+ });
4618
+ }
4619
+ }
4589
4620
  if (!files.length) {
4590
4621
  return undefined;
4591
4622
  }
@@ -4602,9 +4633,13 @@ const AXP_SYSTEM_FILE_CHOOSER_PROVIDER = {
4602
4633
  if (!multiple) {
4603
4634
  return next.slice(0, 1);
4604
4635
  }
4605
- return [...context.items, ...next];
4636
+ return [...(context.items ?? []), ...next];
4606
4637
  },
4607
4638
  };
4639
+ function catalogRejectionReason(errors, maxFileSize) {
4640
+ const failedForSize = errors.some((error) => (error.rule ?? '').toLowerCase().includes('size'));
4641
+ return failedForSize && maxFileSize > 0 ? 'size' : 'type';
4642
+ }
4608
4643
  //#endregion
4609
4644
 
4610
4645
  //#region ---- File chooser platform settings ----
@@ -4960,13 +4995,18 @@ class AXPFileChooserService {
4960
4995
  if (!items?.length) {
4961
4996
  return items;
4962
4997
  }
4998
+ const previousItems = new Set(context.items ?? []);
4999
+ const incoming = items.filter((item) => !previousItems.has(item));
5000
+ if (incoming.length === 0) {
5001
+ return items;
5002
+ }
4963
5003
  const maxFileSize = defaultTo(context.options['maxFileSize'], 0);
4964
5004
  const promptZipOnMultiple = (await this.settingsService.get(AXPFileChooserSettings.PromptZipOnMultiple)) ?? false;
4965
5005
  const validationOptions = {
4966
5006
  ...context.options,
4967
5007
  accept: resolveFileChooserAccept(context.options['accept'], promptZipOnMultiple),
4968
5008
  };
4969
- const { accepted, rejected } = validateFileChooserItems(items, validationOptions);
5009
+ const { accepted, rejected } = validateFileChooserItems(incoming, validationOptions);
4970
5010
  if (rejected.length > 0) {
4971
5011
  await notifyFileAcceptRejections(rejected, {
4972
5012
  translateService: this.translateService,
@@ -4974,7 +5014,14 @@ class AXPFileChooserService {
4974
5014
  maxFileSize,
4975
5015
  });
4976
5016
  }
4977
- return accepted.length > 0 ? accepted : undefined;
5017
+ if (accepted.length === 0) {
5018
+ return undefined;
5019
+ }
5020
+ if (previousItems.size === 0) {
5021
+ return accepted;
5022
+ }
5023
+ const acceptedIncoming = new Set(accepted);
5024
+ return items.filter((item) => previousItems.has(item) || acceptedIncoming.has(item));
4978
5025
  }
4979
5026
  async runAfterChosenHook(providerKey, context, items) {
4980
5027
  if (!items?.length) {
@@ -5004,6 +5051,8 @@ class AXPFileChooserDirective {
5004
5051
  constructor() {
5005
5052
  //#region ---- Services & Dependencies ----
5006
5053
  this.chooserService = inject(AXPFileChooserService);
5054
+ this.toastService = inject(AXToastService);
5055
+ this.translateService = inject(AXTranslationService);
5007
5056
  this.elementRef = inject(ElementRef);
5008
5057
  this.envInjector = inject(EnvironmentInjector);
5009
5058
  this.appRef = inject(ApplicationRef);
@@ -5064,10 +5113,16 @@ class AXPFileChooserDirective {
5064
5113
  ...this.context(),
5065
5114
  items: this.items(),
5066
5115
  });
5067
- if (result) {
5116
+ if (result?.length) {
5068
5117
  this.items.set(result);
5069
5118
  }
5070
5119
  }
5120
+ catch (error) {
5121
+ console.error('[AXPFileChooserDirective] choose failed', error);
5122
+ const title = await this.translateService.translateAsync('@general:messages.generic.error.title');
5123
+ const content = await this.translateService.translateAsync('@layout:components.file-chooser.messages.choose-failed');
5124
+ this.toastService.show({ color: 'danger', title, content });
5125
+ }
5071
5126
  finally {
5072
5127
  this.busy.set(false);
5073
5128
  }
@@ -5101,30 +5156,38 @@ async function compressImageFile(file, quality = 0.7, maxDimension = 1920) {
5101
5156
  if (!file.type.startsWith('image/') || file.type === 'image/svg+xml') {
5102
5157
  return file;
5103
5158
  }
5104
- const bitmap = await createImageBitmap(file);
5105
- const scale = Math.min(1, maxDimension / Math.max(bitmap.width, bitmap.height));
5106
- const width = Math.max(1, Math.round(bitmap.width * scale));
5107
- const height = Math.max(1, Math.round(bitmap.height * scale));
5108
- const canvas = document.createElement('canvas');
5109
- canvas.width = width;
5110
- canvas.height = height;
5111
- const context = canvas.getContext('2d');
5112
- if (!context) {
5113
- bitmap.close();
5114
- return file;
5159
+ let bitmap;
5160
+ try {
5161
+ bitmap = await createImageBitmap(file);
5162
+ const longestSide = Math.max(bitmap.width, bitmap.height);
5163
+ const scale = longestSide > 0 ? Math.min(1, maxDimension / longestSide) : 1;
5164
+ const width = Math.max(1, Math.round(bitmap.width * scale));
5165
+ const height = Math.max(1, Math.round(bitmap.height * scale));
5166
+ const canvas = document.createElement('canvas');
5167
+ canvas.width = width;
5168
+ canvas.height = height;
5169
+ const context = canvas.getContext('2d');
5170
+ if (!context) {
5171
+ return file;
5172
+ }
5173
+ context.drawImage(bitmap, 0, 0, width, height);
5174
+ const mimeType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
5175
+ const blob = await new Promise((resolve) => {
5176
+ canvas.toBlob(resolve, mimeType, quality);
5177
+ });
5178
+ if (!blob || blob.size >= file.size) {
5179
+ return file;
5180
+ }
5181
+ const extension = mimeType === 'image/png' ? 'png' : 'jpg';
5182
+ const baseName = file.name.includes('.') ? file.name.slice(0, file.name.lastIndexOf('.')) : file.name;
5183
+ return new File([blob], `${baseName}.${extension}`, { type: mimeType, lastModified: Date.now() });
5115
5184
  }
5116
- context.drawImage(bitmap, 0, 0, width, height);
5117
- bitmap.close();
5118
- const mimeType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
5119
- const blob = await new Promise((resolve) => {
5120
- canvas.toBlob(resolve, mimeType, quality);
5121
- });
5122
- if (!blob || blob.size >= file.size) {
5185
+ catch {
5123
5186
  return file;
5124
5187
  }
5125
- const extension = mimeType === 'image/png' ? 'png' : 'jpg';
5126
- const baseName = file.name.includes('.') ? file.name.slice(0, file.name.lastIndexOf('.')) : file.name;
5127
- return new File([blob], `${baseName}.${extension}`, { type: mimeType, lastModified: Date.now() });
5188
+ finally {
5189
+ bitmap?.close();
5190
+ }
5128
5191
  }
5129
5192
  /**
5130
5193
  * Builds a store-only ZIP archive (no compression) from the given files.
@@ -5136,9 +5199,10 @@ async function createZipArchive(files, archiveName = 'archive.zip') {
5136
5199
  })));
5137
5200
  const chunks = [];
5138
5201
  const centralDirectory = [];
5202
+ const usedNames = new Set();
5139
5203
  let offset = 0;
5140
5204
  for (const entry of entries) {
5141
- const nameBytes = new TextEncoder().encode(entry.name);
5205
+ const nameBytes = new TextEncoder().encode(uniqueZipEntryName(entry.name, usedNames));
5142
5206
  const crc = crc32(entry.data);
5143
5207
  const localHeader = buildLocalFileHeader(nameBytes, entry.data.length, crc);
5144
5208
  chunks.push(localHeader, nameBytes, entry.data);
@@ -5157,10 +5221,32 @@ async function createZipArchive(files, archiveName = 'archive.zip') {
5157
5221
  }
5158
5222
  return new File([archive], archiveName, { type: 'application/zip', lastModified: Date.now() });
5159
5223
  }
5224
+ const ZIP_VERSION_NEEDED = 20;
5225
+ const ZIP_UTF8_FLAG = 0x0800;
5226
+ function uniqueZipEntryName(name, used) {
5227
+ const baseName = name || 'file';
5228
+ if (!used.has(baseName)) {
5229
+ used.add(baseName);
5230
+ return baseName;
5231
+ }
5232
+ const dot = baseName.lastIndexOf('.');
5233
+ const stem = dot > 0 ? baseName.slice(0, dot) : baseName;
5234
+ const extension = dot > 0 ? baseName.slice(dot) : '';
5235
+ let index = 2;
5236
+ let candidate = `${stem} (${index})${extension}`;
5237
+ while (used.has(candidate)) {
5238
+ index += 1;
5239
+ candidate = `${stem} (${index})${extension}`;
5240
+ }
5241
+ used.add(candidate);
5242
+ return candidate;
5243
+ }
5160
5244
  function buildLocalFileHeader(nameBytes, size, crc) {
5161
5245
  const header = new Uint8Array(30);
5162
5246
  const view = new DataView(header.buffer);
5163
5247
  view.setUint32(0, 0x04034b50, true);
5248
+ view.setUint16(4, ZIP_VERSION_NEEDED, true);
5249
+ view.setUint16(6, ZIP_UTF8_FLAG, true);
5164
5250
  view.setUint16(8, 0, true);
5165
5251
  view.setUint16(10, 0, true);
5166
5252
  view.setUint32(14, crc, true);
@@ -5174,6 +5260,9 @@ function buildCentralDirectoryHeader(nameBytes, size, crc, offset) {
5174
5260
  const header = new Uint8Array(46);
5175
5261
  const view = new DataView(header.buffer);
5176
5262
  view.setUint32(0, 0x02014b50, true);
5263
+ view.setUint16(4, ZIP_VERSION_NEEDED, true);
5264
+ view.setUint16(6, ZIP_VERSION_NEEDED, true);
5265
+ view.setUint16(8, ZIP_UTF8_FLAG, true);
5177
5266
  view.setUint16(10, 0, true);
5178
5267
  view.setUint16(12, 0, true);
5179
5268
  view.setUint32(16, crc, true);
@@ -5375,17 +5464,43 @@ function resolveFileChooserExtension(name) {
5375
5464
  //#region ----- Imports -----
5376
5465
  //#endregion
5377
5466
  //#region ----- URL resolution -----
5467
+ /**
5468
+ * Loads stored bytes through {@link AXPFileStorageService.download} and returns a `blob:` URL.
5469
+ * `<img>`, `<video>`, and PDF viewers do not send `Authorization`, so a raw download URL 401s
5470
+ * when the host authenticates with a bearer token instead of a cookie.
5471
+ */
5472
+ async function resolveStoredFileBlobUrl(fileId, fileStorageService, track, blobUrlCache) {
5473
+ const cached = blobUrlCache?.get(fileId);
5474
+ if (cached) {
5475
+ return cached;
5476
+ }
5477
+ const pending = fileStorageService
5478
+ .download(fileId)
5479
+ .then((blob) => {
5480
+ if (!(blob instanceof Blob)) {
5481
+ blobUrlCache?.delete(fileId);
5482
+ return '';
5483
+ }
5484
+ return track(URL.createObjectURL(blob));
5485
+ })
5486
+ .catch(() => {
5487
+ blobUrlCache?.delete(fileId);
5488
+ return '';
5489
+ });
5490
+ blobUrlCache?.set(fileId, pending);
5491
+ return pending;
5492
+ }
5378
5493
  /** Resolve a file list item to a display/download URL. */
5379
- async function resolveFileListItemUrl(file, fileStorageService, trackObjectUrl) {
5494
+ async function resolveFileListItemUrl(file, fileStorageService, trackObjectUrl, blobUrlCache) {
5380
5495
  const track = (url) => (trackObjectUrl ? trackObjectUrl(url) : url);
5381
5496
  if (file.source?.kind === 'blob' && file.source.value instanceof Blob) {
5382
5497
  return track(URL.createObjectURL(file.source.value));
5383
5498
  }
5384
5499
  if (file.source?.kind === 'fileId' && typeof file.source.value === 'string') {
5385
5500
  const fileId = normalizeStoredImageRef(file.source.value) ?? file.source.value;
5386
- // Preview uses the authenticated download URL (cookie session) — do not call getInfo(),
5387
- // which downloads the full binary and forces a network round-trip per slide.
5388
- return fileId ? fileStorageService.getDownloadUrl(fileId) : '';
5501
+ return fileId
5502
+ ? resolveStoredFileBlobUrl(fileId, fileStorageService, track, blobUrlCache)
5503
+ : '';
5389
5504
  }
5390
5505
  if (file.source?.kind === 'url' && typeof file.source.value === 'string') {
5391
5506
  return file.source.value;
@@ -5396,7 +5511,9 @@ async function resolveFileListItemUrl(file, fileStorageService, trackObjectUrl)
5396
5511
  return value;
5397
5512
  }
5398
5513
  const fileId = normalizeStoredImageRef(value) ?? value;
5399
- return fileId ? fileStorageService.getDownloadUrl(fileId) : '';
5514
+ return fileId
5515
+ ? resolveStoredFileBlobUrl(fileId, fileStorageService, track, blobUrlCache)
5516
+ : '';
5400
5517
  }
5401
5518
  return '';
5402
5519
  }
@@ -5438,8 +5555,9 @@ function normalizeFileViewerBoundValue(value) {
5438
5555
  return [value];
5439
5556
  }
5440
5557
  /** Maps platform files to viewer items using file storage resolution. */
5441
- function mapFileListToViewerItems(files, fileStorageService, trackObjectUrl) {
5442
- return files.map((file) => fileListItemToFileViewerItem(file, (item) => resolveFileListItemUrl(item, fileStorageService, trackObjectUrl)));
5558
+ function mapFileListToViewerItems(files, fileStorageService, trackObjectUrl, blobUrlCache) {
5559
+ const cache = blobUrlCache ?? new Map();
5560
+ return files.map((file) => fileListItemToFileViewerItem(file, (item) => resolveFileListItemUrl(item, fileStorageService, trackObjectUrl, cache)));
5443
5561
  }
5444
5562
  //#endregion
5445
5563
 
@@ -5521,6 +5639,7 @@ class AXPFileViewerComponent {
5521
5639
  //#endregion
5522
5640
  //#region ----- Lifecycle -----
5523
5641
  this.objectUrls = new Set();
5642
+ this.storedFileBlobUrls = new Map();
5524
5643
  }
5525
5644
  //#endregion
5526
5645
  //#region ----- Container API -----
@@ -5549,6 +5668,7 @@ class AXPFileViewerComponent {
5549
5668
  await this.container()?.downloadCurrent();
5550
5669
  }
5551
5670
  ngOnDestroy() {
5671
+ this.storedFileBlobUrls.clear();
5552
5672
  for (const url of this.objectUrls) {
5553
5673
  URL.revokeObjectURL(url);
5554
5674
  }
@@ -5567,7 +5687,7 @@ class AXPFileViewerComponent {
5567
5687
  if (typeof directUrl === 'string' && directUrl.length > 0) {
5568
5688
  return Promise.resolve(directUrl);
5569
5689
  }
5570
- return resolveFileListItemUrl(file, this.fileStorageService, (url) => this.trackObjectUrl(url));
5690
+ return resolveFileListItemUrl(file, this.fileStorageService, (url) => this.trackObjectUrl(url), this.storedFileBlobUrls);
5571
5691
  }
5572
5692
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPFileViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5573
5693
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.8", type: AXPFileViewerComponent, isStandalone: true, selector: "axp-file-viewer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null }, thumbnail: { classPropertyName: "thumbnail", publicName: "thumbnail", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null }, download: { classPropertyName: "download", publicName: "download", isSignal: true, isRequired: false, transformFunction: null }, fullscreen: { classPropertyName: "fullscreen", publicName: "fullscreen", isSignal: true, isRequired: false, transformFunction: null }, galleryMode: { classPropertyName: "galleryMode", publicName: "galleryMode", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, headerContent: { classPropertyName: "headerContent", publicName: "headerContent", isSignal: true, isRequired: false, transformFunction: null }, headerContentInputs: { classPropertyName: "headerContentInputs", publicName: "headerContentInputs", isSignal: true, isRequired: false, transformFunction: null }, fallbackContent: { classPropertyName: "fallbackContent", publicName: "fallbackContent", isSignal: true, isRequired: false, transformFunction: null }, fallbackContentInputs: { classPropertyName: "fallbackContentInputs", publicName: "fallbackContentInputs", isSignal: true, isRequired: false, transformFunction: null }, emptyContent: { classPropertyName: "emptyContent", publicName: "emptyContent", isSignal: true, isRequired: false, transformFunction: null }, emptyContentInputs: { classPropertyName: "emptyContentInputs", publicName: "emptyContentInputs", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { headerActionClick: "headerActionClick", fullscreenClosed: "fullscreenClosed" }, host: { properties: { "style.height": "height()" }, classAttribute: "block" }, viewQueries: [{ propertyName: "container", first: true, predicate: AXFileViewerContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ax-file-viewer-container\n class=\"axp-file-viewer h-full w-full\"\n [items]=\"resolvedItems()\"\n [startIndex]=\"startIndex()\"\n [thumbnail]=\"thumbnail()\"\n [pagination]=\"pagination()\"\n [download]=\"download()\"\n [fullscreen]=\"fullscreen()\"\n [galleryMode]=\"galleryMode()\"\n [headerContent]=\"boundHeaderContent()\"\n [headerContentInputs]=\"boundHeaderContentInputs()\"\n [fallbackContent]=\"boundFallbackContent()\"\n [fallbackContentInputs]=\"boundFallbackContentInputs()\"\n [emptyContent]=\"boundEmptyContent()\"\n [emptyContentInputs]=\"boundEmptyContentInputs()\"\n [headerActions]=\"headerActions()\"\n [loading]=\"loading()\"\n (headerActionClick)=\"headerActionClick.emit($event)\"\n (fullscreenClosed)=\"fullscreenClosed.emit()\"\n/>\n", dependencies: [{ kind: "component", type: AXFileViewerContainerComponent, selector: "ax-file-viewer-container", inputs: ["items", "startIndex", "thumbnail", "pagination", "download", "fullscreen", "headerActions", "galleryMode", "headerContent", "headerContentInputs", "fallbackContent", "fallbackContentInputs", "emptyContent", "emptyContentInputs", "loading"], outputs: ["headerActionClick", "fullscreenClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
@@ -5666,11 +5786,36 @@ class AXPFileViewerService {
5666
5786
  */
5667
5787
  open(config) {
5668
5788
  const { files, items, ...rest } = config;
5669
- const resolvedItems = items ?? (files?.length ? this.mapFiles(files) : []);
5670
- return this.galleryService.open({
5789
+ let closed = false;
5790
+ const sessionUrls = new Set();
5791
+ const blobUrlCache = new Map();
5792
+ const track = (url) => {
5793
+ if (!url.startsWith('blob:')) {
5794
+ return url;
5795
+ }
5796
+ if (closed) {
5797
+ URL.revokeObjectURL(url);
5798
+ return url;
5799
+ }
5800
+ sessionUrls.add(url);
5801
+ this.objectUrls.add(url);
5802
+ return url;
5803
+ };
5804
+ const resolvedItems = items ?? (files?.length ? this.mapFiles(files, track, blobUrlCache) : []);
5805
+ const closedPromise = this.galleryService.open({
5671
5806
  ...rest,
5672
5807
  items: resolvedItems,
5673
5808
  });
5809
+ void closedPromise.then(() => {
5810
+ closed = true;
5811
+ blobUrlCache.clear();
5812
+ for (const url of sessionUrls) {
5813
+ URL.revokeObjectURL(url);
5814
+ this.objectUrls.delete(url);
5815
+ }
5816
+ sessionUrls.clear();
5817
+ });
5818
+ return closedPromise;
5674
5819
  }
5675
5820
  /**
5676
5821
  * Opens a gallery from platform file list items.
@@ -5688,14 +5833,8 @@ class AXPFileViewerService {
5688
5833
  }
5689
5834
  //#endregion
5690
5835
  //#region ----- Mapping -----
5691
- mapFiles(files) {
5692
- return mapFileListToViewerItems(files, this.fileStorageService, (url) => this.trackObjectUrl(url));
5693
- }
5694
- trackObjectUrl(url) {
5695
- if (url.startsWith('blob:')) {
5696
- this.objectUrls.add(url);
5697
- }
5698
- return url;
5836
+ mapFiles(files, trackObjectUrl, blobUrlCache) {
5837
+ return mapFileListToViewerItems(files, this.fileStorageService, trackObjectUrl, blobUrlCache);
5699
5838
  }
5700
5839
  revokeTrackedUrls() {
5701
5840
  for (const url of this.objectUrls) {
@@ -5733,21 +5872,44 @@ const AXP_SYSTEM_FILE_UPLOADER_PROVIDER = {
5733
5872
  icon: 'fa-light fa-file-arrow-up',
5734
5873
  order: 1,
5735
5874
  upload: async (context) => {
5875
+ const fileStorage = inject(AXPFileStorageService);
5876
+ const translateService = inject(AXTranslationService);
5877
+ const toastService = inject(AXToastService);
5736
5878
  const multiple = Boolean(context.options['multiple']);
5737
- const maxFileSize = defaultTo(context.options['maxFileSize'], 10 * 1024 * 1024);
5879
+ const maxFileSizeOption = context.options['maxFileSize'];
5880
+ // Omitted maxFileSize keeps the historical 10 MB cap. Zero or negative means no limit.
5881
+ const maxFileSize = typeof maxFileSizeOption === 'number' ? maxFileSizeOption : 10 * 1024 * 1024;
5738
5882
  const refId = defaultTo(context.options['refId'], 'temp');
5739
5883
  const refType = defaultTo(context.options['refType'], 'file-uploader');
5740
5884
  const category = defaultTo(context.options['category'], 'attachment');
5741
- const chosen = context.chosen.filter((item) => (item.size ?? 0) <= maxFileSize &&
5742
- item.source?.kind === 'blob' &&
5743
- item.source.value instanceof File);
5744
- if (isEmpty(chosen)) {
5885
+ const chosen = Array.isArray(context.chosen) ? context.chosen : [];
5886
+ const rejected = [];
5887
+ const uploadable = [];
5888
+ for (const item of chosen) {
5889
+ const file = resolveChooserItemFile(item);
5890
+ if (!file) {
5891
+ continue;
5892
+ }
5893
+ const comparableSize = Math.max(item.size ?? 0, file.size);
5894
+ if (maxFileSize > 0 && comparableSize > maxFileSize) {
5895
+ rejected.push({ file, reason: 'size' });
5896
+ continue;
5897
+ }
5898
+ uploadable.push({ item, file });
5899
+ }
5900
+ if (rejected.length > 0) {
5901
+ await notifyFileAcceptRejections(rejected, {
5902
+ translateService,
5903
+ toastService,
5904
+ maxFileSize,
5905
+ });
5906
+ }
5907
+ const queue = multiple ? uploadable : uploadable.slice(0, 1);
5908
+ if (queue.length === 0) {
5745
5909
  return undefined;
5746
5910
  }
5747
- const fileStorage = inject(AXPFileStorageService);
5748
5911
  const uploaded = [];
5749
- for (const item of chosen) {
5750
- const file = item.source.value;
5912
+ for (const { item, file } of queue) {
5751
5913
  const info = await fileStorage.save({
5752
5914
  file,
5753
5915
  name: item.name,
@@ -5770,7 +5932,7 @@ const AXP_SYSTEM_FILE_UPLOADER_PROVIDER = {
5770
5932
  if (!multiple) {
5771
5933
  return uploaded.slice(0, 1);
5772
5934
  }
5773
- return [...context.items, ...uploaded];
5935
+ return [...(context.items ?? []), ...uploaded];
5774
5936
  },
5775
5937
  };
5776
5938
  //#endregion
@@ -5848,6 +6010,8 @@ class AXPFileUploaderDirective {
5848
6010
  constructor() {
5849
6011
  //#region ---- Services & Dependencies ----
5850
6012
  this.uploaderService = inject(AXPFileUploaderService);
6013
+ this.toastService = inject(AXToastService);
6014
+ this.translateService = inject(AXTranslationService);
5851
6015
  this.elementRef = inject(ElementRef);
5852
6016
  this.envInjector = inject(EnvironmentInjector);
5853
6017
  this.appRef = inject(ApplicationRef);
@@ -5912,6 +6076,12 @@ class AXPFileUploaderDirective {
5912
6076
  this.uploaded.set(result);
5913
6077
  }
5914
6078
  }
6079
+ catch (error) {
6080
+ console.error('[AXPFileUploaderDirective] upload failed', error);
6081
+ const title = await this.translateService.translateAsync('@general:messages.generic.error.title');
6082
+ const content = await this.translateService.translateAsync('@general:widgets.file-uploader.messages.upload-failed');
6083
+ this.toastService.show({ color: 'danger', title, content });
6084
+ }
5915
6085
  finally {
5916
6086
  this.busy.set(false);
5917
6087
  }
@@ -7593,12 +7763,14 @@ class AXPQueryFiltersComponent {
7593
7763
  displayText: child.displayText,
7594
7764
  }));
7595
7765
  }
7766
+ const committed = this.getCommittedFilterEntry(filter, this.context());
7596
7767
  return [
7597
7768
  {
7598
7769
  id: createQueryFilterConditionId(),
7599
7770
  field: filter.field ?? '',
7600
7771
  operator: filter.operator,
7601
7772
  value: filter.value,
7773
+ displayText: coerceFilterDisplayText(committed?.displayText),
7602
7774
  },
7603
7775
  ];
7604
7776
  }
@@ -7835,7 +8007,7 @@ class AXPQueryFiltersComponent {
7835
8007
  */
7836
8008
  #focusEffect;
7837
8009
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPQueryFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7838
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPQueryFiltersComponent, isStandalone: true, selector: "axp-query-filters", inputs: { filtersDefinitions: { classPropertyName: "filtersDefinitions", publicName: "filtersDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialFilters: { classPropertyName: "initialFilters", publicName: "initialFilters", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, quickSearch: { classPropertyName: "quickSearch", publicName: "quickSearch", isSignal: true, isRequired: false, transformFunction: null }, sortPresets: { classPropertyName: "sortPresets", publicName: "sortPresets", isSignal: true, isRequired: false, transformFunction: null }, activeSortPresetName: { classPropertyName: "activeSortPresetName", publicName: "activeSortPresetName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onFiltersChanged: "onFiltersChanged", onSortPresetSelected: "onSortPresetSelected" }, viewQueries: [{ propertyName: "tagBox", first: true, predicate: ["tagBox"], descendants: true, isSignal: true }, { propertyName: "mobileFilterTrigger", first: true, predicate: ["mobileFilterTrigger"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "widgetsContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "widgetRenderers", predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }, { propertyName: "listItems", predicate: ["caseItem"], descendants: true }], ngImport: i0, template: "<div\n class=\"flex w-full min-w-0 items-center gap-2 px-1.5 py-1\"\n [class.axp-query-filters__bar--toggle-collapsed]=\"deviceService.isSmall() && mobileModeToggleCollapsed() && !mobileSearchOpen()\"\n (keydown.control.space)=\"openFilterPopover()\"\n>\n @if (deviceService.isSmall()) {\n <!-- ----- Inline search replaces the chip row ----- -->\n @if (mobileSearchOpen()) {\n <div id=\"axp-query-filters-mobile-search\" class=\"axp-query-filters__mobile-search\">\n <ax-search-box\n class=\"ax-sm\"\n [value]=\"mobileSearchText()\"\n [delayTime]=\"300\"\n [placeholder]=\"('@general:terms.interface.filter.search-placeholder' | translate | async) ?? ''\"\n (onValueChanged)=\"handleMobileSearchChanged($event)\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </div>\n }\n <!-- ----- Compact pill row instead of the desktop tag-box toolbar ----- -->\n @else {\n <div\n #mobileFilterTrigger\n class=\"axp-query-filters__mobile-row\"\n [class.axp-query-filters__chips--panning]=\"isChipsPanning()\"\n (wheel)=\"handleChipsWheel($event)\"\n (pointerdown)=\"handleChipsPointerDown($event)\"\n (scroll)=\"handleMobileChipsScroll($event)\"\n >\n @for (chip of mobileFilterChips(); track chip.id) {\n <!--->\n <!-- ----- Applied filter chip keeps the field title, with a primary border ----- -->\n @if (chip.kind === 'applied') {\n <div\n class=\"axp-query-filters__mobile-chip axp-query-filters__mobile-chip--applied\"\n [class.axp-query-filters__mobile-chip--search]=\"chip.tag.field === 'all'\"\n (click)=\"handleTagClick(chip.tag, $event)\"\n >\n <span class=\"axp-query-filters__mobile-chip-text\">{{ mobileChipLabel(chip.tag) }}</span>\n <!--->\n <!-- ----- Remove this applied filter ----- -->\n @if (!chip.tag.readOnly) {\n <button class=\"axp-query-filters__chip-remove\" (click)=\"handleRemoveTag($event, chip.tagIndex)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n }\n </div>\n }\n <!-- ----- Unused filter field as an outline chip ----- -->\n @else if (chip.kind === 'available') {\n <div\n class=\"axp-query-filters__mobile-chip axp-query-filters__mobile-chip--available\"\n [class.axp-query-filters__mobile-chip--disabled]=\"isFilterDisabled(chip.definition)\"\n [attr.aria-disabled]=\"isFilterDisabled(chip.definition) ? 'true' : null\"\n (click)=\"openMobileAvailableFilter(chip.definition, $event)\"\n >\n <span class=\"axp-query-filters__mobile-chip-text\">{{ chip.definition.title | translate | async }}</span>\n <ax-icon class=\"fa-light fa-angle-down axp-query-filters__mobile-chip-caret\"></ax-icon>\n </div>\n }\n }\n @for (preset of sortPresets(); track preset.name) {\n <!--------------------------------------------------------------->\n <!-- ----- Sort preset pill in the same row as advance filters ----- -->\n <div\n class=\"axp-query-filters__mobile-chip\"\n [class.axp-query-filters__mobile-chip--applied]=\"isMobileSortPresetActive(preset)\"\n [class.axp-query-filters__mobile-chip--available]=\"!isMobileSortPresetActive(preset)\"\n [attr.aria-pressed]=\"isMobileSortPresetActive(preset)\"\n (click)=\"applyMobileSortPreset(preset, $event)\"\n >\n <span class=\"axp-query-filters__mobile-chip-text\">{{ preset.title | translate | async }}</span>\n <!--------------------------------------------------------------->\n <!-- ----- Custom icon when the recipe does not use a direction arrow ----- -->\n @if (preset.icon) {\n <ax-icon [class]=\"preset.icon + ' axp-query-filters__mobile-chip-caret'\"></ax-icon>\n }\n <!--------------------------------------------------------------->\n <!-- ----- Descending hint when the first sort is descending ----- -->\n @else if (mobileSortPresetDir(preset) === 'desc') {\n <ax-icon class=\"fa-solid fa-arrow-down-long axp-query-filters__mobile-chip-caret\"></ax-icon>\n }\n <!--------------------------------------------------------------->\n <!-- ----- Ascending hint when the first sort is ascending ----- -->\n @else if (mobileSortPresetDir(preset) === 'asc') {\n <ax-icon class=\"fa-solid fa-arrow-up-long axp-query-filters__mobile-chip-caret\"></ax-icon>\n }\n </div>\n }\n </div>\n }\n <div\n class=\"axp-query-filters__mode-toggle\"\n [class.axp-query-filters__mode-toggle--collapsed]=\"mobileModeToggleCollapsed() && !mobileSearchOpen()\"\n [attr.aria-hidden]=\"mobileModeToggleCollapsed() && !mobileSearchOpen()\"\n [attr.inert]=\"mobileModeToggleCollapsed() && !mobileSearchOpen() ? true : null\"\n role=\"tablist\"\n [attr.aria-label]=\"('@general:terms.interface.filter.title' | translate | async) ?? ''\"\n >\n <div class=\"axp-query-filters__mode-toggle-inner\">\n <button\n type=\"button\"\n role=\"tab\"\n class=\"axp-query-filters__mode-toggle-btn\"\n [class.axp-query-filters__mode-toggle-btn--active]=\"!mobileSearchOpen()\"\n [disabled]=\"isMobileFilterModeLocked()\"\n [attr.aria-selected]=\"!mobileSearchOpen()\"\n [attr.aria-label]=\"('@general:terms.interface.filter.title' | translate | async) ?? ''\"\n (click)=\"setMobileSearchOpen(false)\"\n >\n <ax-icon class=\"fa-light fa-filter\"></ax-icon>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n class=\"axp-query-filters__mode-toggle-btn\"\n [class.axp-query-filters__mode-toggle-btn--active]=\"mobileSearchOpen()\"\n [disabled]=\"isMobileSearchModeLocked()\"\n [attr.aria-selected]=\"mobileSearchOpen()\"\n [attr.aria-label]=\"('@general:actions.search.title' | translate | async) ?? ''\"\n (click)=\"setMobileSearchOpen(true)\"\n >\n <ax-icon class=\"fa-light fa-magnifying-glass\"></ax-icon>\n </button>\n </div>\n </div>\n } @else {\n <!-- ----- Root AND/OR when more than one visible chip, including All ----- -->\n @if (isAdvanced() && hasMultipleFilterGroups()) {\n <ax-button-group\n class=\"axp-query-filters__logic-toggle ax-sm shrink-0\"\n [selection]=\"'single'\"\n [look]=\"'outline'\"\n [color]=\"'primary'\"\n >\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.chip-logic-and' | translate | async) ?? ''\" [selected]=\"rootLogic() === 'and'\" (onClick)=\"setRootLogic('and')\"></ax-button-group-item>\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.chip-logic-or' | translate | async) ?? ''\" [selected]=\"rootLogic() === 'or'\" (onClick)=\"setRootLogic('or')\"></ax-button-group-item>\n </ax-button-group>\n }\n <!-- ----- Filter picker when root AND/OR is hidden ----- -->\n @else {\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"isAdvanced() ? openNewFilterGroup() : openFilterPopover()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter cursor-pointer\"></ax-icon>\n </ax-button>\n }\n }\n <div\n class=\"axp-query-filters__chips min-w-0\"\n [class.flex-1]=\"!deviceService.isSmall()\"\n [class.hidden]=\"deviceService.isSmall()\"\n [class.axp-query-filters__chips--panning]=\"isChipsPanning()\"\n (click)=\"handleTagBoxClick($event)\"\n (wheel)=\"handleChipsWheel($event)\"\n (pointerdown)=\"handleChipsPointerDown($event)\"\n >\n <ax-tag-box\n #tagBoxComponent\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n [tagTemplate]=\"tagTemplate\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [allowDuplicateValues]=\"true\"\n [placeholder]=\"(filtersDefinitions().length === 0 ? '@general:terms.interface.filter.no-filter-definitions' : '@general:terms.interface.filter.placeholder') | translate | async\"\n #tagBox\n >\n <ax-suffix class=\"hidden shrink-0 whitespace-nowrap md:flex text-gray-500\">\n <ax-kbd look=\"blank\">\n <ax-kbd-item [keys]=\"filterFocusShortcutKeys\"></ax-kbd-item>\n </ax-kbd>\n </ax-suffix>\n </ax-tag-box>\n </div>\n\n <ng-template #tagTemplate let-item let-index=\"index\">\n <div class=\"axp-query-filters__chip\" [class.axp-query-filters__chip--active]=\"item.id === activeChipId()\" [class.axp-query-filters__chip--search]=\"item.field === 'all'\" (click)=\"handleTagClick(item, $event)\">\n <!-- ----- Quick search chip keeps a single text label ----- -->\n @if (item.chipMode === 'search') {\n <span class=\"axp-query-filters__chip-text\">{{ item.query }}</span>\n } @else if (item.chipMode === 'summary') {\n <!-- ----- Summary chip when more than two conditions ----- -->\n @if (item.titleLabel) {\n <span class=\"axp-query-filters__chip-title\">{{ item.titleLabel }}:</span>\n }\n <span class=\"axp-query-filters__chip-text\">{{ item.summaryText }}</span>\n } @else {\n <!-- ----- One or two conditions: field + operator + quoted value ----- -->\n @if (item.titleLabel && !item.mixed) {\n <span class=\"axp-query-filters__chip-title\">{{ item.titleLabel }}</span>\n }\n @for (cond of item.chipConditions; track $index) {\n <!--->\n <!-- ----- Logic connector between conditions ----- -->\n @if ($index > 0) {\n <span class=\"axp-query-filters__chip-logic\">{{ item.logicLabel }}</span>\n }\n <!--->\n <!-- ----- Field title on mixed-field chips ----- -->\n @if (item.mixed && cond.title) {\n <span class=\"axp-query-filters__chip-title\">{{ cond.title }}</span>\n }\n <span class=\"axp-query-filters__chip-operator\">{{ cond.operator }}</span>\n <!--->\n <!-- ----- Quoted value badge when the operator has a display value ----- -->\n @if (cond.value) {\n <span class=\"axp-query-filters__chip-value\">'{{ cond.value }}'</span>\n }\n }\n }\n @if (!item.readOnly) {\n <button class=\"axp-query-filters__chip-remove\" (click)=\"handleRemoveTag($event, index)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n }\n </div>\n </ng-template>\n</div>\n\n<ax-popover [offsetY]=\"activeFilter() ? -30 : 0\" [openOn]=\"'toggle'\" (onOpened)=\"onPopoverOpened($event)\" [closeOn]=\"'clickOut'\" (onClosed)=\"handlePopoverClosed($event)\" [adaptivityEnabled]=\"true\" #popover>\n <div class=\"axp-query-filters__popover md:min-w-72 w-full rounded-md md:max-h-[min(32rem,80vh)] lg:w-[520px] md:overflow-auto\">\n <axp-widgets-container #widgetsContainer [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"flex flex-col lightest-surface shadow-md\" (keydown.enter)=\"onEnterKeyPressed($event)\">\n <ax-header class=\"axp-query-filters__editor-header border-b border-border-light px-4 py-2\">\n <div class=\"flex min-w-0 items-center gap-2 font-semibold\">\n <!--->\n <!-- ----- Field icon when the group is a single field ----- -->\n @if (!isMixedEditingGroup() && activeFilter()?.icon) {\n <ax-icon class=\"w-5 shrink-0\" [class]=\"'fa-light ' + activeFilter()!.icon\"></ax-icon>\n }\n <span class=\"min-w-0 truncate\">\n {{ isMixedEditingGroup() ? ('@general:terms.interface.filter.filter-group' | translate | async) : ('@general:terms.interface.filter.filter-on' | translate: { params: { title: activeFilterTitle() } } | async) }}\n </span>\n </div>\n <!--->\n <!-- ----- Condition logic AND/OR stays on desktop ----- -->\n @if (!deviceService.isSmall()) {\n <ax-button-group class=\"axp-query-filters__logic-toggle ax-sm shrink-0\" [selection]=\"'single'\" [look]=\"'outline'\" [color]=\"'primary'\">\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.logic-and-all' | translate | async) ?? ''\" [selected]=\"editingLogic() === 'and'\" (onClick)=\"setEditingLogic('and')\"></ax-button-group-item>\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.logic-or-any' | translate | async) ?? ''\" [selected]=\"editingLogic() === 'or'\" (onClick)=\"setEditingLogic('or')\"></ax-button-group-item>\n </ax-button-group>\n }\n </ax-header>\n <ax-content class=\"p-4\">\n @for (condition of editingConditions(); track condition.id; let i = $index) {\n <!--->\n <!-- ----- Numbered condition row with the field widget ----- -->\n @if (i > 0 && !deviceService.isSmall()) {\n <div class=\"axp-query-filters__logic-split\">\n <span class=\"axp-query-filters__logic-split-label\">{{ (editingLogic() === 'or' ? '@general:terms.interface.filter.chip-logic-or' : '@general:terms.interface.filter.chip-logic-and') | translate | async }}</span>\n </div>\n }\n <div class=\"axp-query-filters__condition\">\n <div class=\"axp-query-filters__condition-head\">\n <div class=\"axp-query-filters__condition-heading\">\n <!--->\n <!-- ----- Field picker for mixed-field groups in advanced mode ----- -->\n @if (isAdvanced()) {\n <ax-dropdown-button class=\"ax-sm\" [text]=\"(getConditionDefinition(condition.field)?.title | translate | async) ?? ''\" [mode]=\"'dropdown'\" [look]=\"'outline'\">\n <ax-button-item-list>\n @for (def of advancedFieldOptions(); track def.field) {\n <ax-button-item [text]=\"(def.title | translate | async) ?? ''\" [selected]=\"condition.field === def.field\" [disabled]=\"isFilterDisabled(def)\" (onClick)=\"setConditionField(condition.id, def.field ?? '')\"></ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-button>\n }\n <!--->\n <!-- ----- Active operator for this condition ----- -->\n @if (getConditionOperatorKey(condition.id); as operatorKey) {\n <ax-badge [text]=\"(operatorKey | translate | async) || ''\"></ax-badge>\n }\n </div>\n <button type=\"button\" class=\"axp-query-filters__condition-remove\" (click)=\"handleRemoveCondition(condition.id)\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n </div>\n <ng-container\n axp-widget-renderer\n [node]=\"{\n type: getConditionWidget(condition)?.type || 'text-editor',\n path: resolveEditingConditionContextField(condition.id),\n options: $safeNavigationMigration(getConditionWidget(condition)?.options),\n }\"\n [mode]=\"'edit'\"\n ></ng-container>\n </div>\n }\n <!--->\n <!-- ----- Extra conditions stay on desktop ----- -->\n @if (!deviceService.isSmall()) {\n <button type=\"button\" class=\"axp-query-filters__add-condition\" (click)=\"handleAddCondition()\">\n <ax-icon class=\"fa-light fa-plus\"></ax-icon>\n <span>{{ (isAdvanced() ? '@general:terms.interface.filter.add-condition-generic' : '@general:terms.interface.filter.add-condition') | translate: { params: { title: activeFilterTitle() } } | async }}</span>\n </button>\n }\n </ax-content>\n <ax-footer class=\"border-t flex justify-end gap-2 border-border-light w-full px-4 py-2\">\n <ax-button class=\"ax-sm\" [look]=\"'blank'\" [text]=\"'@general:actions.cancel.title' | translate | async\" (onClick)=\"handleCancelFilter()\"></ax-button>\n <ax-button class=\"ax-sm\" [color]=\"'primary'\" [disabled]=\"!canApplyFilter()\" [text]=\"'@general:terms.interface.filter.apply-filter' | translate | async\" (onClick)=\"handleApplyFilter()\"></ax-button>\n </ax-footer>\n </div>\n } @else {\n <!-- ----- Field picker when no filter is being edited ----- -->\n <div class=\"flex flex-col lightest-surface\">\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items border-none\">\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive() && !isFilterDisabled(field)\"\n [class.axp-query-filters__advance-item--disabled]=\"isFilterDisabled(field)\"\n [attr.aria-disabled]=\"isFilterDisabled(field) ? 'true' : null\"\n [attr.tabindex]=\"isFilterDisabled(field) ? -1 : 0\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n >\n <div class=\"flex items-center gap-2\">\n <ax-icon class=\"axp-query-filters__field-icon\" [ngClass]=\"'fa-light ' + field.icon\"></ax-icon>\n <span class=\"leading-none\">{{ field.title | translate | async }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["@layer properties;axp-query-filters{display:block;width:100%;min-width:0px;overflow:hidden}axp-query-filters>.flex{min-width:0px;flex-wrap:nowrap}axp-query-filters ax-tag-box{width:100%;min-width:0px}axp-query-filters ax-tag-box .editor-container,axp-query-filters ax-tag-box .ax-editor-container{display:flex;width:100%;min-width:0px;flex-wrap:nowrap;align-items:center;background-color:transparent;min-height:2.25rem}axp-query-filters ax-tag-box .ax-tags-container{display:flex;flex:1 1 0%;min-width:0;flex-wrap:nowrap!important;overflow-x:auto;overflow-y:hidden}axp-query-filters ax-tag-box ax-suffix{flex-shrink:0;white-space:nowrap}axp-query-filters>.flex>ax-button button{min-height:var(--ax-sys-size-base);height:var(--ax-sys-size-base);padding-block:0}.axp-query-filters__chips,axp-query-filters ax-tag-box .ax-tags-container{scrollbar-width:none;-ms-overflow-style:none}:is(.axp-query-filters__chips,axp-query-filters ax-tag-box .ax-tags-container)::-webkit-scrollbar{display:none;width:0;height:0;background:transparent}.axp-query-filters__chips{min-width:0px;cursor:grab;overflow-x:auto;overflow-y:hidden}.axp-query-filters__chips.axp-query-filters__chips--panning,.axp-query-filters__chips.axp-query-filters__chips--panning *{cursor:grabbing;-webkit-user-select:none;user-select:none}.axp-query-filters__chip{display:inline-flex;flex-shrink:0;cursor:pointer;align-items:center;gap:var(--spacing, .25rem);border-radius:var(--radius-md, .375rem);background-color:var(--color-surface);color:var(--color-on-surface);border-color:var(--color-border-surface);padding-inline:calc(var(--spacing, .25rem) * 2.5);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));white-space:nowrap}.axp-query-filters__chip:hover{background-color:rgba(var(--ax-sys-color-darkest-surface))}.axp-query-filters__chip--search,.axp-query-filters__chip--active{background-color:rgba(var(--ax-sys-color-primary-surface));color:var(--color-white, #fff)}:is(.axp-query-filters__chip--search,.axp-query-filters__chip--active):hover{background-color:rgba(var(--ax-sys-color-primary-surface))}.axp-query-filters__chip-title{flex-shrink:0;--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}.axp-query-filters__chip-text,.axp-query-filters__chip-operator{min-width:0px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-query-filters__chip-logic{flex-shrink:0;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgba(var(--ax-sys-color-primary-surface));text-transform:uppercase}.axp-query-filters__chip--active .axp-query-filters__chip-logic,.axp-query-filters__chip--search .axp-query-filters__chip-logic{color:var(--color-white, #fff)}.axp-query-filters__chip-value{display:inline-flex;max-width:12rem;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}.axp-query-filters__chip--active .axp-query-filters__chip-value,.axp-query-filters__chip--search .axp-query-filters__chip-value{background-color:color-mix(in srgb,#fff 20%,transparent);color:var(--color-white, #fff)}@supports (color: color-mix(in lab,red,red)){.axp-query-filters__chip--active .axp-query-filters__chip-value,.axp-query-filters__chip--search .axp-query-filters__chip-value{background-color:color-mix(in oklab,var(--color-white, #fff) 20%,transparent)}}.axp-query-filters__chip-remove{display:inline-flex;flex-shrink:0;cursor:pointer;align-items:center;justify-content:center;opacity:70%}.axp-query-filters__chip-remove:hover{opacity:100%}.axp-query-filters__mode-toggle{flex:0 0 auto;max-width:6rem;overflow:visible;transition:max-width .32s cubic-bezier(.32,.72,0,1)}.axp-query-filters__mode-toggle--collapsed{max-width:0;pointer-events:none}.axp-query-filters__mode-toggle-inner{position:relative;z-index:10;margin-inline-start:var(--spacing, .25rem);display:inline-flex;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);border-color:rgba(var(--ax-sys-color-light-surface));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);width:max-content;transform:translate(0);transition:transform .32s cubic-bezier(.32,.72,0,1),margin .32s cubic-bezier(.32,.72,0,1)}.axp-query-filters__mode-toggle--collapsed .axp-query-filters__mode-toggle-inner{margin-inline-start:0;transform:translate(5rem)}[dir=rtl] .axp-query-filters__mode-toggle--collapsed .axp-query-filters__mode-toggle-inner{transform:translate(-5rem)}.axp-query-filters__mode-toggle-btn{display:inline-flex;align-items:center;justify-content:center;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));width:1.875rem;height:1.625rem}.axp-query-filters__mode-toggle-btn:first-child{border-start-start-radius:calc(infinity * 1px);border-end-start-radius:calc(infinity * 1px)}.axp-query-filters__mode-toggle-btn:last-child{border-start-end-radius:calc(infinity * 1px);border-end-end-radius:calc(infinity * 1px)}.axp-query-filters__mode-toggle-btn--active{background-color:rgba(var(--ax-sys-color-primary-surface));color:var(--color-white, #fff)}.axp-query-filters__mode-toggle-btn:disabled:not(.axp-query-filters__mode-toggle-btn--active){cursor:not-allowed;opacity:40%}.axp-query-filters__mobile-search{min-width:0px;flex:1}.axp-query-filters__mobile-search ax-search-box,.axp-query-filters__mobile-search ax-search-box .ax-editor,.axp-query-filters__mobile-search ax-search-box .ax-editor-container,.axp-query-filters__mobile-search ax-search-box .editor-container{min-height:1.875rem;height:1.875rem}.axp-query-filters__mobile-search ax-search-box input{min-height:1.875rem;height:1.875rem;font-size:.8125rem;line-height:1.125rem}.axp-query-filters__mobile-row{display:flex;min-width:0px;flex:1;flex-wrap:nowrap;align-items:center;gap:var(--spacing, .25rem);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.axp-query-filters__mobile-row::-webkit-scrollbar{display:none;width:0;height:0;background:transparent}.axp-query-filters__mobile-chip{display:inline-flex;flex-shrink:0;cursor:pointer;align-items:center;gap:var(--spacing, .25rem);border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;background-color:var(--color-surface);color:var(--color-on-surface);border-color:var(--color-border-surface);border-color:rgba(var(--ax-sys-color-light-surface));padding-inline:calc(var(--spacing, .25rem) * 2.5);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);white-space:nowrap}.axp-query-filters__mobile-chip--available{cursor:pointer;background-color:transparent}.axp-query-filters__mobile-chip--disabled{cursor:not-allowed;opacity:50%}.axp-query-filters__mobile-chip--applied{border-color:rgba(var(--ax-sys-color-primary-surface));background-color:transparent;color:rgba(var(--ax-sys-color-primary-surface))}.axp-query-filters__mobile-chip-text{max-width:10rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-query-filters__mobile-chip-caret{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));opacity:70%}.axp-query-filters__editor-header{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3)}.axp-query-filters__logic-toggle ax-button-group-item.ax-state-selected ax-button button,.axp-query-filters__logic-toggle ax-button button.ax-state-selected{background-image:none;box-shadow:none;background-color:rgba(var(--ax-sys-color-primary-surface));color:var(--color-white, #fff)}.axp-query-filters__logic-toggle ax-button>button{min-height:2rem;height:2rem;padding-inline:.5rem;padding-block:0;font-size:.8125rem;line-height:1.125rem;font-weight:600}@media(max-width:600px){axp-query-filters{overflow:hidden}axp-query-filters>.flex{gap:.5rem;padding-block:0;padding-inline:.125rem;overflow:hidden}axp-query-filters>.flex.axp-query-filters__bar--toggle-collapsed{gap:0}.axp-query-filters__logic-toggle{flex-wrap:nowrap}.axp-query-filters__chip{gap:.375rem;padding-inline:.625rem;padding-block:.25rem;font-size:.8125rem}.axp-query-filters__chip-value{max-width:none;font-size:.8125rem}}.axp-query-filters__condition{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2)}.axp-query-filters__condition-head{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 2)}.axp-query-filters__condition-heading{display:flex;min-width:0px;flex-wrap:wrap;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-query-filters__condition-title{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-query-filters__condition-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-query-filters__condition-remove{display:inline-flex;cursor:pointer;align-items:center;justify-content:center;color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-query-filters__condition-remove{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-query-filters__condition-remove:hover{color:rgba(var(--ax-sys-color-danger-surface))}.axp-query-filters__logic-split{position:relative;margin-block:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:center}.axp-query-filters__logic-split:before,.axp-query-filters__logic-split:after{content:\"\";height:1px;flex:1;background-color:rgba(var(--ax-sys-color-border-light-surface))}.axp-query-filters__logic-split-label{margin-inline:calc(var(--spacing, .25rem) * 3);border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-border-light-surface));padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * .5);font-size:10px;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-primary-surface));text-transform:uppercase}.axp-query-filters__add-condition{margin-top:calc(var(--spacing, .25rem) * 3);display:inline-flex;cursor:pointer;align-items:center;gap:calc(var(--spacing, .25rem) * 1.5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-primary-surface))}.axp-query-filters__add-condition:hover{text-decoration-line:underline}.axp-list-items{display:flex;min-width:calc(var(--spacing, .25rem) * 40);flex-direction:column;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding-block:calc(var(--spacing, .25rem) * 4);--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.axp-list-items>div{min-width:calc(var(--spacing, .25rem) * 28);cursor:pointer;padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 2);text-align:start}.axp-list-items>div:focus{outline:none}.axp-list-items>div.axp-state-focused,.axp-list-items>div:hover{background-color:var(--color-surface);color:var(--color-on-surface);border-color:var(--color-border-surface)}.axp-list-items>div.axp-query-filters__advance-item--disabled{cursor:not-allowed;opacity:50%}.axp-list-items>div.axp-query-filters__advance-item--disabled.axp-state-focused,.axp-list-items>div.axp-query-filters__advance-item--disabled:hover{background-color:transparent}.axp-query-filters__field-icon{display:inline-flex;height:calc(var(--spacing, .25rem) * 4);width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;align-items:center;justify-content:center;--tw-leading: 1;line-height:1}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-leading: initial;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-tracking: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1$2.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$2.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "component", type: i4$2.AXButtonGroupComponent, selector: "ax-button-group", inputs: ["disabled", "fitParent", "color", "look", "class", "selection"], outputs: ["onBlur", "onFocus", "disabledChange", "colorChange", "lookChange", "onClick", "selectionChange", "selectedButtonChange"] }, { kind: "component", type: i4$2.AXButtonGroupItemComponent, selector: "ax-button-group-item", inputs: ["disabled", "color", "text", "class", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange", "classChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", 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: AXDropdownButtonModule }, { kind: "component", type: i6.AXDropdownButtonComponent, selector: "ax-dropdown-button", inputs: ["disabled", "size", "text", "selected", "color", "look", "type", "mode", "iconOnly"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "lookChange", "colorChange", "disabledChange"] }, { kind: "component", type: AXKBDComponent, selector: "ax-kbd", inputs: ["look"] }, { kind: "component", type: AXKBDItemComponent, selector: "ax-kbd-item", inputs: ["keys", "join", "look"], outputs: ["lookChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "closeOnNavigation", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i3$2.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXSelectionListModule }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i9.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1$5.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1$5.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i11.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i11.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
8010
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPQueryFiltersComponent, isStandalone: true, selector: "axp-query-filters", inputs: { filtersDefinitions: { classPropertyName: "filtersDefinitions", publicName: "filtersDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialFilters: { classPropertyName: "initialFilters", publicName: "initialFilters", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, quickSearch: { classPropertyName: "quickSearch", publicName: "quickSearch", isSignal: true, isRequired: false, transformFunction: null }, sortPresets: { classPropertyName: "sortPresets", publicName: "sortPresets", isSignal: true, isRequired: false, transformFunction: null }, activeSortPresetName: { classPropertyName: "activeSortPresetName", publicName: "activeSortPresetName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onFiltersChanged: "onFiltersChanged", onSortPresetSelected: "onSortPresetSelected" }, viewQueries: [{ propertyName: "tagBox", first: true, predicate: ["tagBox"], descendants: true, isSignal: true }, { propertyName: "mobileFilterTrigger", first: true, predicate: ["mobileFilterTrigger"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "widgetsContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "widgetRenderers", predicate: AXPWidgetRendererDirective, descendants: true, isSignal: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }, { propertyName: "listItems", predicate: ["caseItem"], descendants: true }], ngImport: i0, template: "<div\n class=\"flex w-full min-w-0 items-center gap-2 px-1.5 py-1\"\n [class.axp-query-filters__bar--toggle-collapsed]=\"deviceService.isSmall() && mobileModeToggleCollapsed() && !mobileSearchOpen()\"\n (keydown.control.space)=\"openFilterPopover()\"\n>\n @if (deviceService.isSmall()) {\n <!-- ----- Inline search replaces the chip row ----- -->\n @if (mobileSearchOpen()) {\n <div id=\"axp-query-filters-mobile-search\" class=\"axp-query-filters__mobile-search\">\n <ax-search-box\n class=\"ax-sm\"\n [value]=\"mobileSearchText()\"\n [delayTime]=\"300\"\n [placeholder]=\"('@general:terms.interface.filter.search-placeholder' | translate | async) ?? ''\"\n (onValueChanged)=\"handleMobileSearchChanged($event)\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-search-box>\n </div>\n }\n <!-- ----- Compact pill row instead of the desktop tag-box toolbar ----- -->\n @else {\n <div\n #mobileFilterTrigger\n class=\"axp-query-filters__mobile-row\"\n [class.axp-query-filters__chips--panning]=\"isChipsPanning()\"\n (wheel)=\"handleChipsWheel($event)\"\n (pointerdown)=\"handleChipsPointerDown($event)\"\n (scroll)=\"handleMobileChipsScroll($event)\"\n >\n @for (chip of mobileFilterChips(); track chip.id) {\n <!--->\n <!-- ----- Applied filter chip keeps the field title, with a primary border ----- -->\n @if (chip.kind === 'applied') {\n <div\n class=\"axp-query-filters__mobile-chip axp-query-filters__mobile-chip--applied\"\n [class.axp-query-filters__mobile-chip--search]=\"chip.tag.field === 'all'\"\n (click)=\"handleTagClick(chip.tag, $event)\"\n >\n <span class=\"axp-query-filters__mobile-chip-text\">{{ mobileChipLabel(chip.tag) }}</span>\n <!--->\n <!-- ----- Remove this applied filter ----- -->\n @if (!chip.tag.readOnly) {\n <button class=\"axp-query-filters__chip-remove\" (click)=\"handleRemoveTag($event, chip.tagIndex)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n }\n </div>\n }\n <!-- ----- Unused filter field as an outline chip ----- -->\n @else if (chip.kind === 'available') {\n <div\n class=\"axp-query-filters__mobile-chip axp-query-filters__mobile-chip--available\"\n [class.axp-query-filters__mobile-chip--disabled]=\"isFilterDisabled(chip.definition)\"\n [attr.aria-disabled]=\"isFilterDisabled(chip.definition) ? 'true' : null\"\n (click)=\"openMobileAvailableFilter(chip.definition, $event)\"\n >\n <span class=\"axp-query-filters__mobile-chip-text\">{{ chip.definition.title | translate | async }}</span>\n <ax-icon class=\"fa-light fa-angle-down axp-query-filters__mobile-chip-caret\"></ax-icon>\n </div>\n }\n }\n @for (preset of sortPresets(); track preset.name) {\n <!--------------------------------------------------------------->\n <!-- ----- Sort preset pill in the same row as advance filters ----- -->\n <div\n class=\"axp-query-filters__mobile-chip\"\n [class.axp-query-filters__mobile-chip--applied]=\"isMobileSortPresetActive(preset)\"\n [class.axp-query-filters__mobile-chip--available]=\"!isMobileSortPresetActive(preset)\"\n [attr.aria-pressed]=\"isMobileSortPresetActive(preset)\"\n (click)=\"applyMobileSortPreset(preset, $event)\"\n >\n <span class=\"axp-query-filters__mobile-chip-text\">{{ preset.title | translate | async }}</span>\n <!--------------------------------------------------------------->\n <!-- ----- Custom icon when the recipe does not use a direction arrow ----- -->\n @if (preset.icon) {\n <ax-icon [class]=\"preset.icon + ' axp-query-filters__mobile-chip-caret'\"></ax-icon>\n }\n <!--------------------------------------------------------------->\n <!-- ----- Descending hint when the first sort is descending ----- -->\n @else if (mobileSortPresetDir(preset) === 'desc') {\n <ax-icon class=\"fa-solid fa-arrow-down-long axp-query-filters__mobile-chip-caret\"></ax-icon>\n }\n <!--------------------------------------------------------------->\n <!-- ----- Ascending hint when the first sort is ascending ----- -->\n @else if (mobileSortPresetDir(preset) === 'asc') {\n <ax-icon class=\"fa-solid fa-arrow-up-long axp-query-filters__mobile-chip-caret\"></ax-icon>\n }\n </div>\n }\n </div>\n }\n <div\n class=\"axp-query-filters__mode-toggle\"\n [class.axp-query-filters__mode-toggle--collapsed]=\"mobileModeToggleCollapsed() && !mobileSearchOpen()\"\n [attr.aria-hidden]=\"mobileModeToggleCollapsed() && !mobileSearchOpen()\"\n [attr.inert]=\"mobileModeToggleCollapsed() && !mobileSearchOpen() ? true : null\"\n role=\"tablist\"\n [attr.aria-label]=\"('@general:terms.interface.filter.title' | translate | async) ?? ''\"\n >\n <div class=\"axp-query-filters__mode-toggle-inner\">\n <button\n type=\"button\"\n role=\"tab\"\n class=\"axp-query-filters__mode-toggle-btn\"\n [class.axp-query-filters__mode-toggle-btn--active]=\"!mobileSearchOpen()\"\n [disabled]=\"isMobileFilterModeLocked()\"\n [attr.aria-selected]=\"!mobileSearchOpen()\"\n [attr.aria-label]=\"('@general:terms.interface.filter.title' | translate | async) ?? ''\"\n (click)=\"setMobileSearchOpen(false)\"\n >\n <ax-icon class=\"fa-light fa-filter\"></ax-icon>\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n class=\"axp-query-filters__mode-toggle-btn\"\n [class.axp-query-filters__mode-toggle-btn--active]=\"mobileSearchOpen()\"\n [disabled]=\"isMobileSearchModeLocked()\"\n [attr.aria-selected]=\"mobileSearchOpen()\"\n [attr.aria-label]=\"('@general:actions.search.title' | translate | async) ?? ''\"\n (click)=\"setMobileSearchOpen(true)\"\n >\n <ax-icon class=\"fa-light fa-magnifying-glass\"></ax-icon>\n </button>\n </div>\n </div>\n } @else {\n <!-- ----- Root AND/OR when more than one visible chip, including All ----- -->\n @if (isAdvanced() && hasMultipleFilterGroups()) {\n <ax-button-group\n class=\"axp-query-filters__logic-toggle ax-sm shrink-0\"\n [selection]=\"'single'\"\n [look]=\"'outline'\"\n [color]=\"'primary'\"\n >\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.chip-logic-and' | translate | async) ?? ''\" [selected]=\"rootLogic() === 'and'\" (onClick)=\"setRootLogic('and')\"></ax-button-group-item>\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.chip-logic-or' | translate | async) ?? ''\" [selected]=\"rootLogic() === 'or'\" (onClick)=\"setRootLogic('or')\"></ax-button-group-item>\n </ax-button-group>\n }\n <!-- ----- Filter picker when root AND/OR is hidden ----- -->\n @else {\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"isAdvanced() ? openNewFilterGroup() : openFilterPopover()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter cursor-pointer\"></ax-icon>\n </ax-button>\n }\n }\n <div\n class=\"axp-query-filters__chips min-w-0\"\n [class.flex-1]=\"!deviceService.isSmall()\"\n [class.hidden]=\"deviceService.isSmall()\"\n [class.axp-query-filters__chips--panning]=\"isChipsPanning()\"\n (click)=\"handleTagBoxClick($event)\"\n (wheel)=\"handleChipsWheel($event)\"\n (pointerdown)=\"handleChipsPointerDown($event)\"\n >\n <ax-tag-box\n #tagBoxComponent\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n [tagTemplate]=\"tagTemplate\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [allowDuplicateValues]=\"true\"\n [placeholder]=\"(filtersDefinitions().length === 0 ? '@general:terms.interface.filter.no-filter-definitions' : '@general:terms.interface.filter.placeholder') | translate | async\"\n #tagBox\n >\n <ax-suffix class=\"hidden shrink-0 whitespace-nowrap md:flex text-gray-500\">\n <ax-kbd look=\"blank\">\n <ax-kbd-item [keys]=\"filterFocusShortcutKeys\"></ax-kbd-item>\n </ax-kbd>\n </ax-suffix>\n </ax-tag-box>\n </div>\n\n <ng-template #tagTemplate let-item let-index=\"index\">\n <div class=\"axp-query-filters__chip\" [class.axp-query-filters__chip--active]=\"item.id === activeChipId()\" [class.axp-query-filters__chip--search]=\"item.field === 'all'\" (click)=\"handleTagClick(item, $event)\">\n <!-- ----- Quick search chip keeps a single text label ----- -->\n @if (item.chipMode === 'search') {\n <span class=\"axp-query-filters__chip-text\">{{ item.query }}</span>\n } @else if (item.chipMode === 'summary') {\n <!-- ----- Summary chip when more than two conditions ----- -->\n @if (item.titleLabel) {\n <span class=\"axp-query-filters__chip-title\">{{ item.titleLabel }}:</span>\n }\n <span class=\"axp-query-filters__chip-text\">{{ item.summaryText }}</span>\n } @else {\n <!-- ----- One or two conditions: field + operator + quoted value ----- -->\n @if (item.titleLabel && !item.mixed) {\n <span class=\"axp-query-filters__chip-title\">{{ item.titleLabel }}</span>\n }\n @for (cond of item.chipConditions; track $index) {\n <!--->\n <!-- ----- Logic connector between conditions ----- -->\n @if ($index > 0) {\n <span class=\"axp-query-filters__chip-logic\">{{ item.logicLabel }}</span>\n }\n <!--->\n <!-- ----- Field title on mixed-field chips ----- -->\n @if (item.mixed && cond.title) {\n <span class=\"axp-query-filters__chip-title\">{{ cond.title }}</span>\n }\n <span class=\"axp-query-filters__chip-operator\">{{ cond.operator }}</span>\n <!--->\n <!-- ----- Quoted value badge when the operator has a display value ----- -->\n @if (cond.value) {\n <span class=\"axp-query-filters__chip-value\">'{{ cond.value }}'</span>\n }\n }\n }\n @if (!item.readOnly) {\n <button class=\"axp-query-filters__chip-remove\" (click)=\"handleRemoveTag($event, index)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n }\n </div>\n </ng-template>\n</div>\n\n<ax-popover [offsetY]=\"activeFilter() ? -30 : 0\" [openOn]=\"'toggle'\" (onOpened)=\"onPopoverOpened($event)\" [closeOn]=\"'clickOut'\" (onClosed)=\"handlePopoverClosed($event)\" [adaptivityEnabled]=\"true\" #popover>\n <div class=\"axp-query-filters__popover md:min-w-72 w-full rounded-md md:max-h-[min(32rem,80vh)] lg:w-[520px] md:overflow-auto\">\n <axp-widgets-container #widgetsContainer [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"flex flex-col lightest-surface shadow-md\" (keydown.enter)=\"onEnterKeyPressed($event)\">\n <ax-header class=\"axp-query-filters__editor-header border-b border-border-light px-4 py-2\">\n <div class=\"flex min-w-0 items-center gap-2 font-semibold\">\n <!--->\n <!-- ----- Field icon when the group is a single field ----- -->\n @if (!isMixedEditingGroup() && activeFilter()?.icon) {\n <ax-icon class=\"w-5 shrink-0\" [class]=\"'fa-light ' + activeFilter()!.icon\"></ax-icon>\n }\n <span class=\"min-w-0 truncate\">\n {{ isMixedEditingGroup() ? ('@general:terms.interface.filter.filter-group' | translate | async) : ('@general:terms.interface.filter.filter-on' | translate: { params: { title: activeFilterTitle() } } | async) }}\n </span>\n </div>\n <!--->\n <!-- ----- Condition logic AND/OR stays on desktop ----- -->\n @if (!deviceService.isSmall()) {\n <ax-button-group class=\"axp-query-filters__logic-toggle ax-sm shrink-0\" [selection]=\"'single'\" [look]=\"'outline'\" [color]=\"'primary'\">\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.logic-and-all' | translate | async) ?? ''\" [selected]=\"editingLogic() === 'and'\" (onClick)=\"setEditingLogic('and')\"></ax-button-group-item>\n <ax-button-group-item [text]=\"('@general:terms.interface.filter.logic-or-any' | translate | async) ?? ''\" [selected]=\"editingLogic() === 'or'\" (onClick)=\"setEditingLogic('or')\"></ax-button-group-item>\n </ax-button-group>\n }\n </ax-header>\n <ax-content class=\"p-4\">\n @for (condition of editingConditions(); track condition.id; let i = $index) {\n <!--->\n <!-- ----- Numbered condition row with the field widget ----- -->\n @if (i > 0 && !deviceService.isSmall()) {\n <div class=\"axp-query-filters__logic-split\">\n <span class=\"axp-query-filters__logic-split-label\">{{ (editingLogic() === 'or' ? '@general:terms.interface.filter.chip-logic-or' : '@general:terms.interface.filter.chip-logic-and') | translate | async }}</span>\n </div>\n }\n <div class=\"axp-query-filters__condition\">\n <div class=\"axp-query-filters__condition-head\">\n <div class=\"axp-query-filters__condition-heading\">\n <!--->\n <!-- ----- Field picker for mixed-field groups in advanced mode ----- -->\n @if (isAdvanced()) {\n <ax-dropdown-button class=\"ax-sm\" [text]=\"(getConditionDefinition(condition.field)?.title | translate | async) ?? ''\" [mode]=\"'dropdown'\" [look]=\"'outline'\">\n <ax-button-item-list>\n @for (def of advancedFieldOptions(); track def.field) {\n <ax-button-item [text]=\"(def.title | translate | async) ?? ''\" [selected]=\"condition.field === def.field\" [disabled]=\"isFilterDisabled(def)\" (onClick)=\"setConditionField(condition.id, def.field ?? '')\"></ax-button-item>\n }\n </ax-button-item-list>\n </ax-dropdown-button>\n }\n <!--->\n <!-- ----- Active operator for this condition ----- -->\n @if (getConditionOperatorKey(condition.id); as operatorKey) {\n <ax-badge [text]=\"(operatorKey | translate | async) || ''\"></ax-badge>\n }\n </div>\n <button type=\"button\" class=\"axp-query-filters__condition-remove\" (click)=\"handleRemoveCondition(condition.id)\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n </div>\n <ng-container\n axp-widget-renderer\n [node]=\"{\n type: getConditionWidget(condition)?.type || 'text-editor',\n path: resolveEditingConditionContextField(condition.id),\n options: $safeNavigationMigration(getConditionWidget(condition)?.options),\n }\"\n [mode]=\"'edit'\"\n ></ng-container>\n </div>\n }\n <!--->\n <!-- ----- Extra conditions stay on desktop ----- -->\n @if (!deviceService.isSmall()) {\n <button type=\"button\" class=\"axp-query-filters__add-condition\" (click)=\"handleAddCondition()\">\n <ax-icon class=\"fa-light fa-plus\"></ax-icon>\n <span>{{ (isAdvanced() ? '@general:terms.interface.filter.add-condition-generic' : '@general:terms.interface.filter.add-condition') | translate: { params: { title: activeFilterTitle() } } | async }}</span>\n </button>\n }\n </ax-content>\n <ax-footer class=\"border-t flex justify-end gap-2 border-border-light w-full px-4 py-2\">\n <ax-button class=\"ax-sm\" [look]=\"'blank'\" [text]=\"'@general:actions.cancel.title' | translate | async\" (onClick)=\"handleCancelFilter()\"></ax-button>\n <ax-button class=\"ax-sm\" [color]=\"'primary'\" [disabled]=\"!canApplyFilter()\" [text]=\"'@general:terms.interface.filter.apply-filter' | translate | async\" (onClick)=\"handleApplyFilter()\"></ax-button>\n </ax-footer>\n </div>\n } @else {\n <!-- ----- Field picker when no filter is being edited ----- -->\n <div class=\"flex flex-col lightest-surface\">\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items border-none\">\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive() && !isFilterDisabled(field)\"\n [class.axp-query-filters__advance-item--disabled]=\"isFilterDisabled(field)\"\n [attr.aria-disabled]=\"isFilterDisabled(field) ? 'true' : null\"\n [attr.tabindex]=\"isFilterDisabled(field) ? -1 : 0\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n >\n <div class=\"flex items-center gap-2\">\n <ax-icon class=\"axp-query-filters__field-icon\" [ngClass]=\"'fa-light ' + field.icon\"></ax-icon>\n <span class=\"leading-none\">{{ field.title | translate | async }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["@layer properties;axp-query-filters{display:block;width:100%;min-width:0px;overflow:hidden}axp-query-filters>.flex{min-width:0px;flex-wrap:nowrap}axp-query-filters ax-tag-box{width:100%;min-width:0px}axp-query-filters ax-tag-box .editor-container,axp-query-filters ax-tag-box .ax-editor-container{display:flex;width:100%;min-width:0px;flex-wrap:nowrap;align-items:center;background-color:transparent;min-height:2.25rem}axp-query-filters ax-tag-box .ax-tags-container{display:flex;flex:1 1 0%;min-width:0;flex-wrap:nowrap!important;overflow-x:auto;overflow-y:hidden}axp-query-filters ax-tag-box ax-suffix{flex-shrink:0;white-space:nowrap}axp-query-filters>.flex>ax-button button{min-height:var(--ax-sys-size-base);height:var(--ax-sys-size-base);padding-block:0}.axp-query-filters__chips,axp-query-filters ax-tag-box .ax-tags-container{scrollbar-width:none;-ms-overflow-style:none}:is(.axp-query-filters__chips,axp-query-filters ax-tag-box .ax-tags-container)::-webkit-scrollbar{display:none;width:0;height:0;background:transparent}.axp-query-filters__chips{min-width:0px;cursor:grab;overflow-x:auto;overflow-y:hidden}.axp-query-filters__chips.axp-query-filters__chips--panning,.axp-query-filters__chips.axp-query-filters__chips--panning *{cursor:grabbing;-webkit-user-select:none;user-select:none}.axp-query-filters__chip{display:inline-flex;flex-shrink:0;cursor:pointer;align-items:center;gap:var(--spacing, .25rem);border-radius:var(--radius-md, .375rem);background-color:var(--color-surface);color:var(--color-on-surface);border-color:var(--color-border-surface);padding-inline:calc(var(--spacing, .25rem) * 2.5);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));white-space:nowrap}.axp-query-filters__chip:hover{background-color:rgba(var(--ax-sys-color-darkest-surface))}.axp-query-filters__chip--search,.axp-query-filters__chip--active{background-color:rgba(var(--ax-sys-color-primary-surface));color:var(--color-white, #fff)}:is(.axp-query-filters__chip--search,.axp-query-filters__chip--active):hover{background-color:rgba(var(--ax-sys-color-primary-surface))}.axp-query-filters__chip-title{flex-shrink:0;--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}.axp-query-filters__chip-text,.axp-query-filters__chip-operator{min-width:0px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-query-filters__chip-logic{flex-shrink:0;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);color:rgba(var(--ax-sys-color-primary-surface));text-transform:uppercase}.axp-query-filters__chip--active .axp-query-filters__chip-logic,.axp-query-filters__chip--search .axp-query-filters__chip-logic{color:var(--color-white, #fff)}.axp-query-filters__chip-value{display:inline-flex;max-width:12rem;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:.25rem;background-color:rgba(var(--ax-sys-color-lightest-surface));padding-inline:calc(var(--spacing, .25rem) * 1.5);font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: calc(var(--spacing, .25rem) * 5);line-height:calc(var(--spacing, .25rem) * 5);--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}.axp-query-filters__chip--active .axp-query-filters__chip-value,.axp-query-filters__chip--search .axp-query-filters__chip-value{background-color:color-mix(in srgb,#fff 20%,transparent);color:var(--color-white, #fff)}@supports (color: color-mix(in lab,red,red)){.axp-query-filters__chip--active .axp-query-filters__chip-value,.axp-query-filters__chip--search .axp-query-filters__chip-value{background-color:color-mix(in oklab,var(--color-white, #fff) 20%,transparent)}}.axp-query-filters__chip-remove{display:inline-flex;flex-shrink:0;cursor:pointer;align-items:center;justify-content:center;opacity:70%}.axp-query-filters__chip-remove:hover{opacity:100%}.axp-query-filters__mode-toggle{flex:0 0 auto;max-width:6rem;overflow:visible;transition:max-width .32s cubic-bezier(.32,.72,0,1)}.axp-query-filters__mode-toggle--collapsed{max-width:0;pointer-events:none}.axp-query-filters__mode-toggle-inner{position:relative;z-index:10;margin-inline-start:var(--spacing, .25rem);display:inline-flex;border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);border-color:rgba(var(--ax-sys-color-light-surface));--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);width:max-content;transform:translate(0);transition:transform .32s cubic-bezier(.32,.72,0,1),margin .32s cubic-bezier(.32,.72,0,1)}.axp-query-filters__mode-toggle--collapsed .axp-query-filters__mode-toggle-inner{margin-inline-start:0;transform:translate(5rem)}[dir=rtl] .axp-query-filters__mode-toggle--collapsed .axp-query-filters__mode-toggle-inner{transform:translate(-5rem)}.axp-query-filters__mode-toggle-btn{display:inline-flex;align-items:center;justify-content:center;font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));width:1.875rem;height:1.625rem}.axp-query-filters__mode-toggle-btn:first-child{border-start-start-radius:calc(infinity * 1px);border-end-start-radius:calc(infinity * 1px)}.axp-query-filters__mode-toggle-btn:last-child{border-start-end-radius:calc(infinity * 1px);border-end-end-radius:calc(infinity * 1px)}.axp-query-filters__mode-toggle-btn--active{background-color:rgba(var(--ax-sys-color-primary-surface));color:var(--color-white, #fff)}.axp-query-filters__mode-toggle-btn:disabled:not(.axp-query-filters__mode-toggle-btn--active){cursor:not-allowed;opacity:40%}.axp-query-filters__mobile-search{min-width:0px;flex:1}.axp-query-filters__mobile-search ax-search-box,.axp-query-filters__mobile-search ax-search-box .ax-editor,.axp-query-filters__mobile-search ax-search-box .ax-editor-container,.axp-query-filters__mobile-search ax-search-box .editor-container{min-height:1.875rem;height:1.875rem}.axp-query-filters__mobile-search ax-search-box input{min-height:1.875rem;height:1.875rem;font-size:.8125rem;line-height:1.125rem}.axp-query-filters__mobile-row{display:flex;min-width:0px;flex:1;flex-wrap:nowrap;align-items:center;gap:var(--spacing, .25rem);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.axp-query-filters__mobile-row::-webkit-scrollbar{display:none;width:0;height:0;background:transparent}.axp-query-filters__mobile-chip{display:inline-flex;flex-shrink:0;cursor:pointer;align-items:center;gap:var(--spacing, .25rem);border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;background-color:var(--color-surface);color:var(--color-on-surface);border-color:var(--color-border-surface);border-color:rgba(var(--ax-sys-color-light-surface));padding-inline:calc(var(--spacing, .25rem) * 2.5);padding-block:calc(var(--spacing, .25rem) * .5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);white-space:nowrap}.axp-query-filters__mobile-chip--available{cursor:pointer;background-color:transparent}.axp-query-filters__mobile-chip--disabled{cursor:not-allowed;opacity:50%}.axp-query-filters__mobile-chip--applied{border-color:rgba(var(--ax-sys-color-primary-surface));background-color:transparent;color:rgba(var(--ax-sys-color-primary-surface))}.axp-query-filters__mobile-chip-text{max-width:10rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-query-filters__mobile-chip-caret{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));opacity:70%}.axp-query-filters__editor-header{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3)}.axp-query-filters__logic-toggle ax-button-group-item.ax-state-selected ax-button button,.axp-query-filters__logic-toggle ax-button button.ax-state-selected{background-image:none;box-shadow:none;background-color:rgba(var(--ax-sys-color-primary-surface));color:var(--color-white, #fff)}.axp-query-filters__logic-toggle ax-button>button{min-height:2rem;height:2rem;padding-inline:.5rem;padding-block:0;font-size:.8125rem;line-height:1.125rem;font-weight:600}@media(max-width:600px){axp-query-filters{overflow:hidden}axp-query-filters>.flex{gap:.5rem;padding-block:0;padding-inline:.125rem;overflow:hidden}axp-query-filters>.flex.axp-query-filters__bar--toggle-collapsed{gap:0}.axp-query-filters__logic-toggle{flex-wrap:nowrap}.axp-query-filters__chip{gap:.375rem;padding-inline:.625rem;padding-block:.25rem;font-size:.8125rem}.axp-query-filters__chip-value{max-width:none;font-size:.8125rem}}.axp-query-filters__condition{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 2)}.axp-query-filters__condition-head{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 2)}.axp-query-filters__condition-heading{display:flex;min-width:0px;flex-wrap:wrap;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}.axp-query-filters__condition-title{font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-text-default));text-transform:uppercase}@supports (color: color-mix(in lab,red,red)){.axp-query-filters__condition-title{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-query-filters__condition-remove{display:inline-flex;cursor:pointer;align-items:center;justify-content:center;color:rgba(var(--ax-sys-color-text-default))}@supports (color: color-mix(in lab,red,red)){.axp-query-filters__condition-remove{color:color-mix(in oklab,rgba(var(--ax-sys-color-text-default)) 80%,transparent)}}.axp-query-filters__condition-remove:hover{color:rgba(var(--ax-sys-color-danger-surface))}.axp-query-filters__logic-split{position:relative;margin-block:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:center}.axp-query-filters__logic-split:before,.axp-query-filters__logic-split:after{content:\"\";height:1px;flex:1;background-color:rgba(var(--ax-sys-color-border-light-surface))}.axp-query-filters__logic-split-label{margin-inline:calc(var(--spacing, .25rem) * 3);border-radius:calc(infinity * 1px);border-style:var(--tw-border-style);border-width:1px;border-color:rgba(var(--ax-sys-color-border-light-surface));padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * .5);font-size:10px;--tw-font-weight: var(--font-weight-semibold, 600);font-weight:var(--font-weight-semibold, 600);--tw-tracking: var(--tracking-wide, .025em);letter-spacing:var(--tracking-wide, .025em);color:rgba(var(--ax-sys-color-primary-surface));text-transform:uppercase}.axp-query-filters__add-condition{margin-top:calc(var(--spacing, .25rem) * 3);display:inline-flex;cursor:pointer;align-items:center;gap:calc(var(--spacing, .25rem) * 1.5);font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);color:rgba(var(--ax-sys-color-primary-surface))}.axp-query-filters__add-condition:hover{text-decoration-line:underline}.axp-list-items{display:flex;min-width:calc(var(--spacing, .25rem) * 40);flex-direction:column;border-radius:var(--radius-md, .375rem);border-style:var(--tw-border-style);border-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding-block:calc(var(--spacing, .25rem) * 4);--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.axp-list-items>div{min-width:calc(var(--spacing, .25rem) * 28);cursor:pointer;padding-inline:calc(var(--spacing, .25rem) * 4);padding-block:calc(var(--spacing, .25rem) * 2);text-align:start}.axp-list-items>div:focus{outline:none}.axp-list-items>div.axp-state-focused,.axp-list-items>div:hover{background-color:var(--color-surface);color:var(--color-on-surface);border-color:var(--color-border-surface)}.axp-list-items>div.axp-query-filters__advance-item--disabled{cursor:not-allowed;opacity:50%}.axp-list-items>div.axp-query-filters__advance-item--disabled.axp-state-focused,.axp-list-items>div.axp-query-filters__advance-item--disabled:hover{background-color:transparent}.axp-query-filters__field-icon{display:inline-flex;height:calc(var(--spacing, .25rem) * 4);width:calc(var(--spacing, .25rem) * 5);flex-shrink:0;align-items:center;justify-content:center;--tw-leading: 1;line-height:1}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: \"*\"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: \"<percentage>\"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: \"*\"; inherits: false;}@property --tw-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: \"*\"; inherits: false;}@property --tw-inset-ring-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: \"*\"; inherits: false;}@property --tw-ring-offset-width{syntax: \"<length>\"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: \"*\"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: \"*\"; inherits: false; initial-value: 0 0 #0000;}@property --tw-tracking{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-leading: initial;--tw-border-style: solid;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-tracking: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1$2.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$2.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "component", type: i4$2.AXButtonGroupComponent, selector: "ax-button-group", inputs: ["disabled", "fitParent", "color", "look", "class", "selection"], outputs: ["onBlur", "onFocus", "disabledChange", "colorChange", "lookChange", "onClick", "selectionChange", "selectedButtonChange"] }, { kind: "component", type: i4$2.AXButtonGroupItemComponent, selector: "ax-button-group-item", inputs: ["disabled", "color", "text", "class", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange", "classChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", 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: AXDropdownButtonModule }, { kind: "component", type: i6.AXDropdownButtonComponent, selector: "ax-dropdown-button", inputs: ["disabled", "size", "text", "selected", "color", "look", "type", "mode", "iconOnly"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "lookChange", "colorChange", "disabledChange"] }, { kind: "component", type: AXKBDComponent, selector: "ax-kbd", inputs: ["look"] }, { kind: "component", type: AXKBDItemComponent, selector: "ax-kbd-item", inputs: ["keys", "join", "look"], outputs: ["lookChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "restoreFocusOnClose", "openAfter", "closeAfter", "closeOnScroll", "closeOnNavigation", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i3$2.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXSelectionListModule }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i9.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1$5.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1$5.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i11.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i11.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$3.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
7839
8011
  }
7840
8012
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPQueryFiltersComponent, decorators: [{
7841
8013
  type: Component,
@@ -8652,7 +8824,8 @@ class AXPPropertyViewerComponent {
8652
8824
  this.context.set(event.data);
8653
8825
  const isHydration = event.state === 'initiated' ||
8654
8826
  event.state === 'restored' ||
8655
- event.origin === 'system';
8827
+ event.origin === 'system' ||
8828
+ event.origin === 'hydrate';
8656
8829
  this.onChanged.emit({
8657
8830
  values: this.context(),
8658
8831
  mode: isHydration ? 'init' : 'update',
@@ -9145,6 +9318,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
9145
9318
  }]
9146
9319
  }] });
9147
9320
 
9321
+ /**
9322
+ * Fixed virtual-scroll row. The lookup paints a "loading" placeholder for any
9323
+ * index that is still a hole, so this must match the option template exactly.
9324
+ */
9325
+ const ITEM_CONFIGURATOR_OPTION_HEIGHT = 56;
9326
+ /** One page covers the whole catalog so search/reopen never leaves unloaded holes. */
9327
+ const ITEM_CONFIGURATOR_PAGE_SIZE = 500;
9328
+ const ITEM_CONFIGURATOR_FALLBACK_ICON = 'fa-light fa-puzzle-piece';
9148
9329
  //#endregion
9149
9330
  //#region ---- Component ----
9150
9331
  /**
@@ -9152,6 +9333,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
9152
9333
  * Bound state: {@link selectedItemId} and {@link values} (context returned from the viewer). Not tied to {@link AXPWidgetNode}.
9153
9334
  */
9154
9335
  class AXPItemConfiguratorComponent {
9336
+ /**
9337
+ * Visible order follows the translated title. Sorting the raw `@scope:key`
9338
+ * puts the list in key order (PPE, Test Sheet, Address, …).
9339
+ */
9340
+ async rowsInDisplayOrder() {
9341
+ const locale = this.translationService.getActiveLang();
9342
+ const labeled = await Promise.all(this.availableItems().map(async (row) => ({
9343
+ row,
9344
+ label: await this.displayLabel(row.title),
9345
+ })));
9346
+ labeled.sort((a, b) => a.label.localeCompare(b.label, locale, { sensitivity: 'base' }));
9347
+ return labeled.map((entry) => entry.row);
9348
+ }
9349
+ async filterRows(rows, needle) {
9350
+ const locale = this.translationService.getActiveLang();
9351
+ const matched = [];
9352
+ for (const row of rows) {
9353
+ const title = (await this.displayLabel(row.title)).toLocaleLowerCase(locale);
9354
+ const description = (await this.displayLabel(row.description)).toLocaleLowerCase(locale);
9355
+ if (title.includes(needle) || description.includes(needle)) {
9356
+ matched.push(row);
9357
+ }
9358
+ }
9359
+ return matched;
9360
+ }
9361
+ async displayLabel(value) {
9362
+ if (value == null || value === '') {
9363
+ return '';
9364
+ }
9365
+ const translated = await this.translationService.translateAsync(value);
9366
+ return translated.trim();
9367
+ }
9155
9368
  enterEditMode() {
9156
9369
  if (this.readonly()) {
9157
9370
  return;
@@ -9199,17 +9412,17 @@ class AXPItemConfiguratorComponent {
9199
9412
  if (!id) {
9200
9413
  continue;
9201
9414
  }
9202
- const title = resolveSearchableText(row.title, locale, this.translationService).trim() || id;
9415
+ const sortText = resolveSearchableText(row.title, locale, this.translationService).trim() || id;
9203
9416
  list.push({
9204
9417
  value: id,
9205
- text: title,
9418
+ text: typeof row.title === 'string' ? row.title : sortText,
9419
+ title: row.title,
9206
9420
  icon: row.icon,
9207
- description: row.description != null
9208
- ? resolveSearchableText(row.description, locale, this.translationService)
9209
- : undefined,
9421
+ description: row.description,
9422
+ sortText,
9210
9423
  });
9211
9424
  }
9212
- return list.sort((a, b) => compareMultiLanguageStrings(a.text, b.text, locale));
9425
+ return list.sort((a, b) => compareMultiLanguageStrings(a.sortText, b.sortText, locale));
9213
9426
  }, /* @ts-ignore */
9214
9427
  ...(ngDevMode ? [{ debugName: "availableItems" }] : /* istanbul ignore next */ []));
9215
9428
  this.selectedListItem = computed(() => {
@@ -9265,8 +9478,41 @@ class AXPItemConfiguratorComponent {
9265
9478
  ...(ngDevMode ? [{ debugName: "isConfigured" }] : /* istanbul ignore next */ []));
9266
9479
  this.visibleHeaderActions = computed(() => (this.headerActions() ?? []).filter((a) => a != null && a.visible !== false && !a.items?.length), /* @ts-ignore */
9267
9480
  ...(ngDevMode ? [{ debugName: "visibleHeaderActions" }] : /* istanbul ignore next */ []));
9481
+ this.optionRowHeight = ITEM_CONFIGURATOR_OPTION_HEIGHT;
9482
+ this.optionMaxVisibleRows = 8;
9483
+ this.fallbackIcon = ITEM_CONFIGURATOR_FALLBACK_ICON;
9484
+ /**
9485
+ * Owned datasource (not a raw array). The lookup wraps arrays at page size 20;
9486
+ * after a search the virtual list keeps a scroll offset into unloaded pages and
9487
+ * stays on the loading placeholder. One page fills every row.
9488
+ */
9489
+ this.itemDataSource = new AXDataSource({
9490
+ key: 'value',
9491
+ pageSize: ITEM_CONFIGURATOR_PAGE_SIZE,
9492
+ load: async (query) => {
9493
+ const rows = await this.rowsInDisplayOrder();
9494
+ const needle = readLookupFilterText(query.filter);
9495
+ const matched = needle ? await this.filterRows(rows, needle) : rows;
9496
+ const skip = query.skip ?? 0;
9497
+ const take = query.take ?? matched.length;
9498
+ return {
9499
+ items: matched.slice(skip, skip + take),
9500
+ total: matched.length,
9501
+ };
9502
+ },
9503
+ byKey: (key) => this.availableItems().find((row) => row.value == key) ?? {
9504
+ value: String(key ?? ''),
9505
+ text: String(key ?? ''),
9506
+ title: String(key ?? ''),
9507
+ sortText: String(key ?? ''),
9508
+ },
9509
+ });
9268
9510
  this.itemLookup = viewChild(AXLookupComponent, /* @ts-ignore */
9269
9511
  ...(ngDevMode ? [{ debugName: "itemLookup" }] : /* istanbul ignore next */ []));
9512
+ effect(() => {
9513
+ this.availableItems();
9514
+ untracked(() => this.itemDataSource.refresh());
9515
+ });
9270
9516
  effect(() => {
9271
9517
  if (!this.isEditMode()) {
9272
9518
  return;
@@ -9372,7 +9618,7 @@ class AXPItemConfiguratorComponent {
9372
9618
  return action.disabled === true;
9373
9619
  }
9374
9620
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPItemConfiguratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9375
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPItemConfiguratorComponent, isStandalone: true, selector: "axp-item-configurator", inputs: { selectedItemId: { classPropertyName: "selectedItemId", publicName: "selectedItemId", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedItemId: "selectedItemIdChange", values: "valuesChange" }, viewQueries: [{ propertyName: "itemLookup", first: true, predicate: AXLookupComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Item selector & info container -->\n<div class=\"__item-container\">\n @if (isEditMode()) {\n <div class=\"__item-selector\">\n <ax-lookup\n #itemLookup\n mode=\"drop-down-list\"\n [ngModel]=\"selectedItemId()\"\n [dataSource]=\"availableItems()\"\n [placeholder]=\"\n ('@general:actions.select.title' | translate | async) ?? ''\n \"\n [readonly]=\"readonly()\"\n (onValueChanged)=\"onSelectionChange($event)\"\n valueField=\"value\"\n textField=\"text\"\n [searchable]=\"true\"\n [itemTemplate]=\"itemTemplate\"\n [itemHeight]=\"72\"\n [selectedTemplate]=\"selectedTemplate\"\n (onClosed)=\"exitEditMode()\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-lookup>\n </div>\n }\n\n @if (!isEditMode()) {\n @if (selectedItemId() && currentItemConfig(); as config) {\n <div class=\"__item-info\">\n <div\n class=\"__item-header\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <div>\n @if (config.icon) {\n <i [class]=\"config.icon\"></i>\n }\n <div>\n <span>\n {{ config.title | translate | async }}\n </span>\n @if (config.description) {\n <p>\n {{ (config.description | translate | async) ?? '' }}\n </p>\n }\n </div>\n </div>\n\n <div class=\"__action-buttons\" (click)=\"$event.stopPropagation()\">\n @if (config.hasProperties) {\n <ax-button\n [disabled]=\"!canConfigure() || readonly()\"\n [title]=\"\n ('@general:actions.configure.title' | translate | async) ?? ''\n \"\n look=\"blank\"\n [color]=\"isConfigured() ? 'primary' : 'default'\"\n size=\"sm\"\n (onClick)=\"openConfigureDialog()\"\n >\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-button>\n }\n @for (\n action of visibleHeaderActions();\n track action.name ?? $index\n ) {\n <ax-button\n look=\"blank\"\n size=\"sm\"\n [color]=\"action.color ?? 'default'\"\n [disabled]=\"readonly() || isHeaderActionDisabled(action)\"\n [title]=\"(action.title | translate | async) ?? ''\"\n [class.icon-only]=\"action.iconOnly === true\"\n (onClick)=\"onHeaderActionClick(action)\"\n >\n @if (action.icon) {\n <ax-icon [icon]=\"action.icon\"></ax-icon>\n }\n @if (action.iconOnly !== true) {\n <span>{{ (action.title | translate | async) ?? '' }}</span>\n }\n </ax-button>\n }\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"__item-empty\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <i class=\"fa-solid fa-puzzle-piece\"></i>\n <span>\n {{\n ('@general:widgets.widget-configurator.select-widget-type'\n | translate\n | async) ?? 'Select an item type'\n }}\n </span>\n </div>\n }\n }\n\n <ng-template #itemTemplate let-item>\n <div class=\"__item-template flex w-full items-center gap-3 p-2\">\n @if (item.icon) {\n <i [class]=\"item.icon + 'text-base w-5 text-center'\"></i>\n }\n <div class=\"flex flex-col gap-1 flex-1 min-w-0\">\n <div class=\"text-sm font-medium\">\n {{ item.text | translate | async }}\n </div>\n @if (item.description) {\n <div class=\"text-xs text-neutral-600\">\n {{ item.description | translate | async }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #selectedTemplate let-item>\n <div class=\"__selected-template\">\n @if (item?.icon) {\n <i [class]=\"item.icon\"></i>\n }\n <span>\n {{ $safeNavigationMigration(item?.text) | translate | async }}\n </span>\n </div>\n </ng-template>\n</div>\n", styles: ["@layer properties;axp-item-configurator{display:flex;flex-direction:column}axp-item-configurator .__item-selector{display:flex;flex-direction:column}axp-item-configurator .__item-selector ax-lookup{width:100%}axp-item-configurator .__item-info{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3)}axp-item-configurator .__item-info .__item-header{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 1.5)}axp-item-configurator .__item-info .__item-header.__editable{cursor:pointer}axp-item-configurator .__item-info .__item-header.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-info .__item-header:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-info .__item-header>div:first-child{display:flex;flex:1;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-info .__item-header>div:first-child i{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));flex-shrink:0}axp-item-configurator .__item-info .__item-header>div:first-child>div{display:flex;flex:1;flex-direction:column;gap:calc(var(--spacing, .25rem) * .5)}axp-item-configurator .__item-info .__item-header>div:first-child>div>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-item-configurator .__item-info .__item-header>div:first-child>div>p{margin:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-relaxed, 1.625);line-height:var(--leading-relaxed, 1.625);color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__item-info .__action-buttons{display:flex;align-items:center;gap:var(--spacing, .25rem);flex-shrink:0}axp-item-configurator .__item-empty{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-empty.__editable{cursor:pointer}axp-item-configurator .__item-empty.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-empty:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-empty>i{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));color:var(--color-neutral-400, oklch(70.8% 0 none))}axp-item-configurator .__item-empty>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__item-template>i{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}axp-item-configurator .__item-template>div>div:first-child{flex-shrink:0}axp-item-configurator .__item-template>div>div:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-item-configurator .__selected-template{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__selected-template>i{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}axp-item-configurator .__selected-template>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}axp-item-configurator :host([readonly]){pointer-events:none;opacity:.7}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXLookupComponent, selector: "ax-lookup", inputs: ["name", "mode", "dataSource", "treeDataSource", "valueField", "textField", "disabledField", "columns", "treeParentField", "hasChildrenField", "searchable", "adaptivityEnabled", "caption", "alternate", "searchPlaceholder", "placeholder", "disabled", "readonly", "look", "itemHeight", "maxVisibleItems", "treeSelectionBehavior", "highlightSearch", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "value", "valueItems"], outputs: ["lookChange", "valueChange", "onValueChanged", "onSelectionChanged", "onFocus", "onBlur", "onItemClick", "onItemSelected", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
9621
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPItemConfiguratorComponent, isStandalone: true, selector: "axp-item-configurator", inputs: { selectedItemId: { classPropertyName: "selectedItemId", publicName: "selectedItemId", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedItemId: "selectedItemIdChange", values: "valuesChange" }, viewQueries: [{ propertyName: "itemLookup", first: true, predicate: AXLookupComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Item selector & info container -->\n<div class=\"__item-container\">\n @if (isEditMode()) {\n <div class=\"__item-selector\">\n <ax-lookup\n #itemLookup\n mode=\"drop-down-list\"\n [ngModel]=\"selectedItemId()\"\n [dataSource]=\"itemDataSource\"\n [placeholder]=\"\n ('@general:actions.select.title' | translate | async) ?? ''\n \"\n [readonly]=\"readonly()\"\n (onValueChanged)=\"onSelectionChange($event)\"\n valueField=\"value\"\n textField=\"text\"\n [searchable]=\"true\"\n [itemTemplate]=\"itemTemplate\"\n [loadingTemplate]=\"loadingTemplate\"\n [itemHeight]=\"optionRowHeight\"\n [maxVisibleItems]=\"optionMaxVisibleRows\"\n [selectedTemplate]=\"selectedTemplate\"\n (onClosed)=\"exitEditMode()\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-lookup>\n </div>\n }\n\n @if (!isEditMode()) {\n @if (selectedItemId() && currentItemConfig(); as config) {\n <div class=\"__item-info\">\n <div\n class=\"__item-header\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <div>\n @if (config.icon) {\n <ax-icon [icon]=\"config.icon\"></ax-icon>\n }\n <div>\n <span>\n {{ config.title | translate | async }}\n </span>\n @if (config.description) {\n <p>\n {{ (config.description | translate | async) ?? '' }}\n </p>\n }\n </div>\n </div>\n\n <div class=\"__action-buttons\" (click)=\"$event.stopPropagation()\">\n @if (config.hasProperties) {\n <ax-button\n [disabled]=\"!canConfigure() || readonly()\"\n [title]=\"\n ('@general:actions.configure.title' | translate | async) ?? ''\n \"\n look=\"blank\"\n [color]=\"isConfigured() ? 'primary' : 'default'\"\n size=\"sm\"\n (onClick)=\"openConfigureDialog()\"\n >\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-button>\n }\n @for (\n action of visibleHeaderActions();\n track action.name ?? $index\n ) {\n <ax-button\n look=\"blank\"\n size=\"sm\"\n [color]=\"action.color ?? 'default'\"\n [disabled]=\"readonly() || isHeaderActionDisabled(action)\"\n [title]=\"(action.title | translate | async) ?? ''\"\n [class.icon-only]=\"action.iconOnly === true\"\n (onClick)=\"onHeaderActionClick(action)\"\n >\n @if (action.icon) {\n <ax-icon [icon]=\"action.icon\"></ax-icon>\n }\n @if (action.iconOnly !== true) {\n <span>{{ (action.title | translate | async) ?? '' }}</span>\n }\n </ax-button>\n }\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"__item-empty\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <i class=\"fa-solid fa-puzzle-piece\"></i>\n <span>\n {{\n ('@general:widgets.widget-configurator.select-widget-type'\n | translate\n | async) ?? 'Select an item type'\n }}\n </span>\n </div>\n }\n }\n\n <ng-template #itemTemplate let-item>\n @let title = (item.title | translate | async) ?? '';\n @let description = (item.description | translate | async) ?? '';\n <div class=\"axp-item-configurator-option\">\n <ax-icon [icon]=\"item.icon || fallbackIcon\"></ax-icon>\n <div class=\"axp-item-configurator-option__text\">\n <span class=\"axp-item-configurator-option__title\">\n {{ title }}\n </span>\n <!-- ----- One-line description under the title ----- -->\n @if (item.description) {\n <span class=\"axp-item-configurator-option__description\">\n {{ description }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #loadingTemplate>\n <div class=\"axp-item-configurator-option axp-item-configurator-option--loading\">\n <span class=\"axp-item-configurator-option__icon-slot\"></span>\n <span class=\"axp-item-configurator-option__bar\"></span>\n </div>\n </ng-template>\n\n <ng-template #selectedTemplate let-item>\n <div class=\"__selected-template\">\n @if (item?.icon) {\n <ax-icon [icon]=\"item.icon\"></ax-icon>\n }\n <span>\n {{ (item?.title | translate | async) ?? '' }}\n </span>\n </div>\n </ng-template>\n</div>\n", styles: ["@layer properties;axp-item-configurator{display:flex;flex-direction:column}axp-item-configurator .__item-selector{display:flex;flex-direction:column}axp-item-configurator .__item-selector ax-lookup{width:100%}axp-item-configurator .__item-info{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3)}axp-item-configurator .__item-info .__item-header{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 1.5)}axp-item-configurator .__item-info .__item-header.__editable{cursor:pointer}axp-item-configurator .__item-info .__item-header.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-info .__item-header:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-info .__item-header>div:first-child{display:flex;flex:1;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-info .__item-header>div:first-child ax-icon{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));flex-shrink:0}axp-item-configurator .__item-info .__item-header>div:first-child>div{display:flex;flex:1;flex-direction:column;gap:calc(var(--spacing, .25rem) * .5)}axp-item-configurator .__item-info .__item-header>div:first-child>div>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-item-configurator .__item-info .__item-header>div:first-child>div>p{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__item-info .__action-buttons{display:flex;align-items:center;gap:var(--spacing, .25rem);flex-shrink:0}axp-item-configurator .__item-empty{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-empty.__editable{cursor:pointer}axp-item-configurator .__item-empty.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-empty:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-empty>i{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));color:var(--color-neutral-400, oklch(70.8% 0 none))}axp-item-configurator .__item-empty>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__selected-template{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__selected-template>ax-icon{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}axp-item-configurator .__selected-template>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}axp-item-configurator :host([readonly]){pointer-events:none;opacity:.7}.ax-lookup-viewport:has(.axp-item-configurator-option){min-height:224px;overflow-y:scroll;scrollbar-gutter:stable}.ax-lookup-option-host:has(.axp-item-configurator-option){overflow:hidden}.axp-item-configurator-option{box-sizing:border-box;display:flex;align-items:center;gap:.625rem;width:100%;height:100%;min-width:0;overflow:hidden;padding-inline:.75rem}.axp-item-configurator-option>ax-icon{flex-shrink:0;width:1.125rem;font-size:1rem;line-height:1;text-align:center}.axp-item-configurator-option__text{display:flex;min-width:0;flex:1;flex-direction:column;justify-content:center;gap:.125rem;line-height:1.25}.axp-item-configurator-option__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;font-weight:500;line-height:1.25}.axp-item-configurator-option__description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--color-neutral-600, oklch(43.9% 0 none));font-size:.75rem;line-height:1.25}.axp-item-configurator-option--loading{gap:.5rem}.axp-item-configurator-option__icon-slot,.axp-item-configurator-option__bar{display:block;border-radius:.25rem;background:currentColor}@supports (color: color-mix(in lab,red,red)){.axp-item-configurator-option__icon-slot,.axp-item-configurator-option__bar{background:color-mix(in srgb,currentColor 12%,transparent)}}.axp-item-configurator-option__icon-slot{width:1rem;height:1rem;flex-shrink:0}.axp-item-configurator-option__bar{height:.5rem;width:40%}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXLookupComponent, selector: "ax-lookup", inputs: ["name", "mode", "dataSource", "treeDataSource", "valueField", "textField", "disabledField", "columns", "treeParentField", "hasChildrenField", "searchable", "adaptivityEnabled", "caption", "alternate", "searchPlaceholder", "placeholder", "disabled", "readonly", "look", "itemHeight", "maxVisibleItems", "treeSelectionBehavior", "highlightSearch", "allowSelectAll", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "value", "valueItems", "prefetch"], outputs: ["lookChange", "valueChange", "onValueChanged", "onSelectionChanged", "onFocus", "onBlur", "onItemClick", "onItemSelected", "onOpened", "onClosed"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
9376
9622
  }
9377
9623
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPItemConfiguratorComponent, decorators: [{
9378
9624
  type: Component,
@@ -9384,7 +9630,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
9384
9630
  AXLookupComponent,
9385
9631
  AXDecoratorModule,
9386
9632
  AXTranslationModule,
9387
- ], template: "<!-- Item selector & info container -->\n<div class=\"__item-container\">\n @if (isEditMode()) {\n <div class=\"__item-selector\">\n <ax-lookup\n #itemLookup\n mode=\"drop-down-list\"\n [ngModel]=\"selectedItemId()\"\n [dataSource]=\"availableItems()\"\n [placeholder]=\"\n ('@general:actions.select.title' | translate | async) ?? ''\n \"\n [readonly]=\"readonly()\"\n (onValueChanged)=\"onSelectionChange($event)\"\n valueField=\"value\"\n textField=\"text\"\n [searchable]=\"true\"\n [itemTemplate]=\"itemTemplate\"\n [itemHeight]=\"72\"\n [selectedTemplate]=\"selectedTemplate\"\n (onClosed)=\"exitEditMode()\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-lookup>\n </div>\n }\n\n @if (!isEditMode()) {\n @if (selectedItemId() && currentItemConfig(); as config) {\n <div class=\"__item-info\">\n <div\n class=\"__item-header\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <div>\n @if (config.icon) {\n <i [class]=\"config.icon\"></i>\n }\n <div>\n <span>\n {{ config.title | translate | async }}\n </span>\n @if (config.description) {\n <p>\n {{ (config.description | translate | async) ?? '' }}\n </p>\n }\n </div>\n </div>\n\n <div class=\"__action-buttons\" (click)=\"$event.stopPropagation()\">\n @if (config.hasProperties) {\n <ax-button\n [disabled]=\"!canConfigure() || readonly()\"\n [title]=\"\n ('@general:actions.configure.title' | translate | async) ?? ''\n \"\n look=\"blank\"\n [color]=\"isConfigured() ? 'primary' : 'default'\"\n size=\"sm\"\n (onClick)=\"openConfigureDialog()\"\n >\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-button>\n }\n @for (\n action of visibleHeaderActions();\n track action.name ?? $index\n ) {\n <ax-button\n look=\"blank\"\n size=\"sm\"\n [color]=\"action.color ?? 'default'\"\n [disabled]=\"readonly() || isHeaderActionDisabled(action)\"\n [title]=\"(action.title | translate | async) ?? ''\"\n [class.icon-only]=\"action.iconOnly === true\"\n (onClick)=\"onHeaderActionClick(action)\"\n >\n @if (action.icon) {\n <ax-icon [icon]=\"action.icon\"></ax-icon>\n }\n @if (action.iconOnly !== true) {\n <span>{{ (action.title | translate | async) ?? '' }}</span>\n }\n </ax-button>\n }\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"__item-empty\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <i class=\"fa-solid fa-puzzle-piece\"></i>\n <span>\n {{\n ('@general:widgets.widget-configurator.select-widget-type'\n | translate\n | async) ?? 'Select an item type'\n }}\n </span>\n </div>\n }\n }\n\n <ng-template #itemTemplate let-item>\n <div class=\"__item-template flex w-full items-center gap-3 p-2\">\n @if (item.icon) {\n <i [class]=\"item.icon + 'text-base w-5 text-center'\"></i>\n }\n <div class=\"flex flex-col gap-1 flex-1 min-w-0\">\n <div class=\"text-sm font-medium\">\n {{ item.text | translate | async }}\n </div>\n @if (item.description) {\n <div class=\"text-xs text-neutral-600\">\n {{ item.description | translate | async }}\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #selectedTemplate let-item>\n <div class=\"__selected-template\">\n @if (item?.icon) {\n <i [class]=\"item.icon\"></i>\n }\n <span>\n {{ $safeNavigationMigration(item?.text) | translate | async }}\n </span>\n </div>\n </ng-template>\n</div>\n", styles: ["@layer properties;axp-item-configurator{display:flex;flex-direction:column}axp-item-configurator .__item-selector{display:flex;flex-direction:column}axp-item-configurator .__item-selector ax-lookup{width:100%}axp-item-configurator .__item-info{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3)}axp-item-configurator .__item-info .__item-header{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 1.5)}axp-item-configurator .__item-info .__item-header.__editable{cursor:pointer}axp-item-configurator .__item-info .__item-header.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-info .__item-header:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-info .__item-header>div:first-child{display:flex;flex:1;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-info .__item-header>div:first-child i{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));flex-shrink:0}axp-item-configurator .__item-info .__item-header>div:first-child>div{display:flex;flex:1;flex-direction:column;gap:calc(var(--spacing, .25rem) * .5)}axp-item-configurator .__item-info .__item-header>div:first-child>div>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-item-configurator .__item-info .__item-header>div:first-child>div>p{margin:0;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-relaxed, 1.625);line-height:var(--leading-relaxed, 1.625);color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__item-info .__action-buttons{display:flex;align-items:center;gap:var(--spacing, .25rem);flex-shrink:0}axp-item-configurator .__item-empty{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-empty.__editable{cursor:pointer}axp-item-configurator .__item-empty.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-empty:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-empty>i{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));color:var(--color-neutral-400, oklch(70.8% 0 none))}axp-item-configurator .__item-empty>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__item-template>i{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}axp-item-configurator .__item-template>div>div:first-child{flex-shrink:0}axp-item-configurator .__item-template>div>div:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-item-configurator .__selected-template{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__selected-template>i{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}axp-item-configurator .__selected-template>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}axp-item-configurator :host([readonly]){pointer-events:none;opacity:.7}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
9633
+ ], template: "<!-- Item selector & info container -->\n<div class=\"__item-container\">\n @if (isEditMode()) {\n <div class=\"__item-selector\">\n <ax-lookup\n #itemLookup\n mode=\"drop-down-list\"\n [ngModel]=\"selectedItemId()\"\n [dataSource]=\"itemDataSource\"\n [placeholder]=\"\n ('@general:actions.select.title' | translate | async) ?? ''\n \"\n [readonly]=\"readonly()\"\n (onValueChanged)=\"onSelectionChange($event)\"\n valueField=\"value\"\n textField=\"text\"\n [searchable]=\"true\"\n [itemTemplate]=\"itemTemplate\"\n [loadingTemplate]=\"loadingTemplate\"\n [itemHeight]=\"optionRowHeight\"\n [maxVisibleItems]=\"optionMaxVisibleRows\"\n [selectedTemplate]=\"selectedTemplate\"\n (onClosed)=\"exitEditMode()\"\n >\n <ax-clear-button></ax-clear-button>\n </ax-lookup>\n </div>\n }\n\n @if (!isEditMode()) {\n @if (selectedItemId() && currentItemConfig(); as config) {\n <div class=\"__item-info\">\n <div\n class=\"__item-header\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <div>\n @if (config.icon) {\n <ax-icon [icon]=\"config.icon\"></ax-icon>\n }\n <div>\n <span>\n {{ config.title | translate | async }}\n </span>\n @if (config.description) {\n <p>\n {{ (config.description | translate | async) ?? '' }}\n </p>\n }\n </div>\n </div>\n\n <div class=\"__action-buttons\" (click)=\"$event.stopPropagation()\">\n @if (config.hasProperties) {\n <ax-button\n [disabled]=\"!canConfigure() || readonly()\"\n [title]=\"\n ('@general:actions.configure.title' | translate | async) ?? ''\n \"\n look=\"blank\"\n [color]=\"isConfigured() ? 'primary' : 'default'\"\n size=\"sm\"\n (onClick)=\"openConfigureDialog()\"\n >\n <ax-icon icon=\"fa-solid fa-cog\"></ax-icon>\n </ax-button>\n }\n @for (\n action of visibleHeaderActions();\n track action.name ?? $index\n ) {\n <ax-button\n look=\"blank\"\n size=\"sm\"\n [color]=\"action.color ?? 'default'\"\n [disabled]=\"readonly() || isHeaderActionDisabled(action)\"\n [title]=\"(action.title | translate | async) ?? ''\"\n [class.icon-only]=\"action.iconOnly === true\"\n (onClick)=\"onHeaderActionClick(action)\"\n >\n @if (action.icon) {\n <ax-icon [icon]=\"action.icon\"></ax-icon>\n }\n @if (action.iconOnly !== true) {\n <span>{{ (action.title | translate | async) ?? '' }}</span>\n }\n </ax-button>\n }\n </div>\n </div>\n </div>\n } @else {\n <div\n class=\"__item-empty\"\n [class.__editable]=\"!readonly()\"\n (click)=\"enterEditMode()\"\n >\n <i class=\"fa-solid fa-puzzle-piece\"></i>\n <span>\n {{\n ('@general:widgets.widget-configurator.select-widget-type'\n | translate\n | async) ?? 'Select an item type'\n }}\n </span>\n </div>\n }\n }\n\n <ng-template #itemTemplate let-item>\n @let title = (item.title | translate | async) ?? '';\n @let description = (item.description | translate | async) ?? '';\n <div class=\"axp-item-configurator-option\">\n <ax-icon [icon]=\"item.icon || fallbackIcon\"></ax-icon>\n <div class=\"axp-item-configurator-option__text\">\n <span class=\"axp-item-configurator-option__title\">\n {{ title }}\n </span>\n <!-- ----- One-line description under the title ----- -->\n @if (item.description) {\n <span class=\"axp-item-configurator-option__description\">\n {{ description }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #loadingTemplate>\n <div class=\"axp-item-configurator-option axp-item-configurator-option--loading\">\n <span class=\"axp-item-configurator-option__icon-slot\"></span>\n <span class=\"axp-item-configurator-option__bar\"></span>\n </div>\n </ng-template>\n\n <ng-template #selectedTemplate let-item>\n <div class=\"__selected-template\">\n @if (item?.icon) {\n <ax-icon [icon]=\"item.icon\"></ax-icon>\n }\n <span>\n {{ (item?.title | translate | async) ?? '' }}\n </span>\n </div>\n </ng-template>\n</div>\n", styles: ["@layer properties;axp-item-configurator{display:flex;flex-direction:column}axp-item-configurator .__item-selector{display:flex;flex-direction:column}axp-item-configurator .__item-selector ax-lookup{width:100%}axp-item-configurator .__item-info{display:flex;flex-direction:column;gap:calc(var(--spacing, .25rem) * 3)}axp-item-configurator .__item-info .__item-header{display:flex;align-items:center;justify-content:space-between;gap:calc(var(--spacing, .25rem) * 3);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 1.5)}axp-item-configurator .__item-info .__item-header.__editable{cursor:pointer}axp-item-configurator .__item-info .__item-header.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-info .__item-header:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-info .__item-header>div:first-child{display:flex;flex:1;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-info .__item-header>div:first-child ax-icon{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));flex-shrink:0}axp-item-configurator .__item-info .__item-header>div:first-child>div{display:flex;flex:1;flex-direction:column;gap:calc(var(--spacing, .25rem) * .5)}axp-item-configurator .__item-info .__item-header>div:first-child>div>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-item-configurator .__item-info .__item-header>div:first-child>div>p{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-xs, .75rem);line-height:var(--tw-leading, var(--text-xs--line-height, calc(1 / .75)));--tw-leading: var(--leading-tight, 1.25);line-height:var(--leading-tight, 1.25);color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__item-info .__action-buttons{display:flex;align-items:center;gap:var(--spacing, .25rem);flex-shrink:0}axp-item-configurator .__item-empty{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2);padding-inline:calc(var(--spacing, .25rem) * 2);padding-block:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__item-empty.__editable{cursor:pointer}axp-item-configurator .__item-empty.__editable:hover{border-radius:var(--radius-md, .375rem);background-color:rgba(var(--ax-sys-color-lighter-surface))}axp-item-configurator .__item-empty:not(.__editable){cursor:not-allowed}axp-item-configurator .__item-empty>i{font-size:var(--text-base, 1rem);line-height:var(--tw-leading, var(--text-base--line-height, 1.5 ));color:var(--color-neutral-400, oklch(70.8% 0 none))}axp-item-configurator .__item-empty>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));color:var(--color-neutral-600, oklch(43.9% 0 none))}axp-item-configurator .__selected-template{display:flex;align-items:center;gap:calc(var(--spacing, .25rem) * 2)}axp-item-configurator .__selected-template>ax-icon{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)))}axp-item-configurator .__selected-template>span{font-size:var(--text-sm, .875rem);line-height:var(--tw-leading, var(--text-sm--line-height, calc(1.25 / .875)));--tw-font-weight: var(--font-weight-medium, 500);font-weight:var(--font-weight-medium, 500)}axp-item-configurator :host([readonly]){pointer-events:none;opacity:.7}.ax-lookup-viewport:has(.axp-item-configurator-option){min-height:224px;overflow-y:scroll;scrollbar-gutter:stable}.ax-lookup-option-host:has(.axp-item-configurator-option){overflow:hidden}.axp-item-configurator-option{box-sizing:border-box;display:flex;align-items:center;gap:.625rem;width:100%;height:100%;min-width:0;overflow:hidden;padding-inline:.75rem}.axp-item-configurator-option>ax-icon{flex-shrink:0;width:1.125rem;font-size:1rem;line-height:1;text-align:center}.axp-item-configurator-option__text{display:flex;min-width:0;flex:1;flex-direction:column;justify-content:center;gap:.125rem;line-height:1.25}.axp-item-configurator-option__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;font-weight:500;line-height:1.25}.axp-item-configurator-option__description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--color-neutral-600, oklch(43.9% 0 none));font-size:.75rem;line-height:1.25}.axp-item-configurator-option--loading{gap:.5rem}.axp-item-configurator-option__icon-slot,.axp-item-configurator-option__bar{display:block;border-radius:.25rem;background:currentColor}@supports (color: color-mix(in lab,red,red)){.axp-item-configurator-option__icon-slot,.axp-item-configurator-option__bar{background:color-mix(in srgb,currentColor 12%,transparent)}}.axp-item-configurator-option__icon-slot{width:1rem;height:1rem;flex-shrink:0}.axp-item-configurator-option__bar{height:.5rem;width:40%}@property --tw-font-weight{syntax: \"*\"; inherits: false;}@property --tw-leading{syntax: \"*\"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-font-weight: initial;--tw-leading: initial}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
9388
9634
  }], ctorParameters: () => [], propDecorators: { selectedItemId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItemId", required: false }] }, { type: i0.Output, args: ["selectedItemIdChange"] }], values: [{ type: i0.Input, args: [{ isSignal: true, alias: "values", required: false }] }, { type: i0.Output, args: ["valuesChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], itemLookup: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXLookupComponent), { isSignal: true }] }] } });
9389
9635
  //#region ---- Helpers ----
9390
9636
  function isPropertyDefinitionArray(value) {
@@ -9405,6 +9651,24 @@ function extractOptionsPatchFromPropertyViewerValues(values) {
9405
9651
  }
9406
9652
  return values;
9407
9653
  }
9654
+ function readLookupFilterText(filter) {
9655
+ if (!filter || typeof filter !== 'object') {
9656
+ return '';
9657
+ }
9658
+ const candidate = filter;
9659
+ if (candidate.operator?.type === 'contains' && candidate.value != null) {
9660
+ return String(candidate.value).trim().toLocaleLowerCase();
9661
+ }
9662
+ if (Array.isArray(candidate.filters)) {
9663
+ for (const nested of candidate.filters) {
9664
+ const text = readLookupFilterText(nested);
9665
+ if (text) {
9666
+ return text;
9667
+ }
9668
+ }
9669
+ }
9670
+ return '';
9671
+ }
9408
9672
 
9409
9673
  //#region ----- Imports -----
9410
9674
  //#endregion
@@ -15090,6 +15354,7 @@ class AXPUserAvatarComponent {
15090
15354
  this.sessionService = inject(AXPSessionService);
15091
15355
  this.fileStorage = inject(AXPFileStorageService);
15092
15356
  this.presenceService = inject(AXPUserPresenceService, { optional: true });
15357
+ this.userStatus = inject(AXPUserStatusFeatureService);
15093
15358
  this.resolveGeneration = 0;
15094
15359
  this.lastResolvedRef = null;
15095
15360
  this.userInfo = signal(null, /* @ts-ignore */
@@ -15137,13 +15402,14 @@ class AXPUserAvatarComponent {
15137
15402
  ...(ngDevMode ? [{ debugName: "isAway" }] : /* istanbul ignore next */ []));
15138
15403
  this.isBusy = computed(() => this.presenceStatus() === 'busy', /* @ts-ignore */
15139
15404
  ...(ngDevMode ? [{ debugName: "isBusy" }] : /* istanbul ignore next */ []));
15140
- this.showPresenceDot = computed(() => this.showPresence() &&
15405
+ this.showPresenceDot = computed(() => this.userStatus.enabled() &&
15406
+ this.showPresence() &&
15141
15407
  isWatchablePresenceUserId(String(this.userId() ?? '')) &&
15142
15408
  this.presenceStatus() !== null, /* @ts-ignore */
15143
15409
  ...(ngDevMode ? [{ debugName: "showPresenceDot" }] : /* istanbul ignore next */ []));
15144
15410
  effect((onCleanup) => {
15145
15411
  const id = String(this.userId() ?? '').trim();
15146
- const showPresence = this.showPresence();
15412
+ const showPresence = this.showPresence() && this.userStatus.enabled();
15147
15413
  void this.displayName();
15148
15414
  void this.displayAvatar();
15149
15415
  if (!id) {
@@ -15409,6 +15675,7 @@ class AXPUserCardComponent {
15409
15675
  //#region ----- Services & Dependencies -----
15410
15676
  this.avatarService = inject(AXPUserAvatarService);
15411
15677
  this.presenceService = inject(AXPUserPresenceService, { optional: true });
15678
+ this.userStatus = inject(AXPUserStatusFeatureService);
15412
15679
  this.formatService = inject(AXFormatService);
15413
15680
  this.settingsService = inject(AXPSettingsService);
15414
15681
  this.translation = inject(AXTranslationService);
@@ -15465,7 +15732,7 @@ class AXPUserCardComponent {
15465
15732
  }
15466
15733
  }, /* @ts-ignore */
15467
15734
  ...(ngDevMode ? [{ debugName: "presenceLabelKey" }] : /* istanbul ignore next */ []));
15468
- this.showPresence = computed(() => isWatchablePresenceUserId(this.userId()), /* @ts-ignore */
15735
+ this.showPresence = computed(() => this.userStatus.enabled() && isWatchablePresenceUserId(this.userId()), /* @ts-ignore */
15469
15736
  ...(ngDevMode ? [{ debugName: "showPresence" }] : /* istanbul ignore next */ []));
15470
15737
  this.tooltipDisabled = computed(() => !this.tooltipText(), /* @ts-ignore */
15471
15738
  ...(ngDevMode ? [{ debugName: "tooltipDisabled" }] : /* istanbul ignore next */ []));
@@ -15493,7 +15760,7 @@ class AXPUserCardComponent {
15493
15760
  this.subscriptions.add(this.avatarService.getUserInfo$(userId).subscribe((data) => {
15494
15761
  this.identity.set(data);
15495
15762
  }));
15496
- if (this.presenceService && isWatchablePresenceUserId(userId)) {
15763
+ if (this.userStatus.enabled() && this.presenceService && isWatchablePresenceUserId(userId)) {
15497
15764
  this.presenceService.watch(userId);
15498
15765
  this.watchedUserId = userId;
15499
15766
  this.presence.set(this.presenceService.get(userId) ?? { userId, status: 'offline' });
@@ -16875,5 +17142,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
16875
17142
  * Generated bundle index. Do not edit.
16876
17143
  */
16877
17144
 
16878
- export { AXPActivityLogComponent, AXPAvatarComponent, AXPCategoryTreeComponent, AXPColorChooserComponent, AXPColorPalettePickerComponent, AXPColumnItemListComponent, AXPCompareViewComponent, AXPConditionBuilderComponent, AXPConditionBuilderConditionComponent, AXPDataSelectorComponent, AXPDataSelectorService, AXPDragDropListComponent, AXPEntityListStylingDialogService, AXPEntityListStylingPopupComponent, AXPExpressionFieldDefinitions, AXPFileChooserCompressImagesHook, AXPFileChooserDirective, AXPFileChooserHookKeys, AXPFileChooserService, AXPFileChooserZipFilesHook, AXPFileUploaderDirective, AXPFileUploaderHookKeys, AXPFileUploaderService, AXPFileViewerComponent, AXPFileViewerFallbackContentComponent, AXPFileViewerService, AXPImageEditorPopupComponent, AXPImageEditorService, AXPInfiniteScrollDirective, AXPItemConfiguratorComponent, AXPLayoutFloatingZoomBarComponent, AXPLayoutSideDetailPanelComponent, AXPLayoutSideDetailPanelSectionDirective, AXPLocalDataSourceEditorDialogService, AXPMarkdownTemplateDirective, AXPMarkdownViewerComponent, AXPMenuBadgeHelper, AXPMenuCustomizerComponent, AXPMenuCustomizerService, AXPOutcomeResultsViewerComponent, AXPPageComponentRegistryService, AXPPreloadFiltersComponent, AXPPropertyViewerComponent, AXPPropertyViewerPopupComponent, AXPPropertyViewerService, AXPQueryColumnsComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewSaveButtonComponent, AXPQueryViewSaveDialogService, AXPQueryViewTabsComponent, AXPQueryViewsComponent, AXPRepeaterRowsLayoutComponent, AXPResourceAppointmentBoardProvider, AXPResourceAppointmentComponent, AXPResourceAppointmentService, AXPSectionItemsBuilderComponent, AXPSignatureEditorService, AXPSpreadsheetComponent, AXPStandardSectionItemsBuilderComponent, AXPStopwatchComponent, AXPTableColumnsEditorComponent, AXPTableColumnsEditorPopupComponent, AXPTableColumnsEditorService, AXPTableDataEditorComponent, AXPTableDataEditorPopupComponent, AXPTableDataEditorService, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPTemplateViewerComponent, AXPTemplateViewerService, AXPTextCommandColumnComponent, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXPUserCardComponent, AXPUserCardDirective, AXPUserCardService, AXPVirtualKeypadComponent, AXPWidgetFieldConfiguratorComponent, AXPWidgetItemComponent, AXPWidgetPropertyViewerComponent, AXPWidgetPropertyViewerPopupComponent, AXPWidgetPropertyViewerService, AXP_EXPRESSION_LOGIC_DEFINITIONS, AXP_EXPRESSION_OPERATION_DEFINITIONS, AXP_FILE_CHOOSER_DEFAULT_ZIP_ARCHIVE_NAME, AXP_FILE_CHOOSER_HOOK_PROVIDERS, AXP_FILE_CHOOSER_OPTION_KEYS, AXP_FILE_CHOOSER_PROVIDERS, AXP_FILE_UPLOADER_PROVIDERS, AXP_IMAGE_FILE_CHOOSER_ACCEPT, AXP_INFINITE_SCROLL_DEFAULT_ROOT_MARGIN, AXP_MENU_CUSTOMIZER_SERVICE, AXP_PAGE_COMPONENT_PROVIDER, AXP_PAGE_LAYOUT_ELEMENT_ID, AXP_PROFILE_PHOTO_GRAVATAR_SOURCE_KEY, AXP_RESOURCE_APPOINTMENT_PROVIDER, AXP_SIGNATURE_PROVIDER, AXP_SPREADSHEET_COLUMN_WIDGET_TYPES, AXP_SYSTEM_FILE_CHOOSER_PROVIDER, AXP_SYSTEM_FILE_UPLOADER_PROVIDER, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER, PROPERTY_VIEWER_EXPRESSION_EDITOR_MIN_LINES, SPREADSHEET_COLUMN_NAME_PATH, SPREADSHEET_COLUMN_TITLE_PATH, STANDARD_SECTION_ITEMS_SECTION_TABS, USER_CARD_HOVER_OPEN_DELAY_MS, USER_CARD_ITEMS_HOOK, USER_CARD_ITEMS_SKELETON_DELAY_MS, asSpreadsheetColumnTitle, buildEntityListStylingRulesLayout, buildFileChooserOptions, buildGravatarAvatarUrl, buildPropertyViewerInitialContextFromProperties, buildPropertyViewerTabsFromProperties, buildTableColumnsEditorLayout, compressImageFile, createAttachedFileProviderMenu, createZipArchive, fetchGravatarImageFile, fileListItemToFileViewerItem, fileListItemToImageFile, fileMatchesAccept, fileNameMatchesAccept, filterFileProvidersByContext, filterFilesByAcceptAndMaxSize, formatAcceptForDisplay, formatMaxFileSizeForDisplay, getFieldDefinitions, getLogicDefinition, getOperationDefinition, isPropertyBindingExpressionFormValue, isUnrestrictedFileAccept, mapFileListToViewerItems, md5Hex, mergeInfiniteScrollPage, mergeObjectsReplacingArrays, normalizeFileViewerBoundValue, normalizeSpreadsheetColumnName, notifyFileAcceptRejections, observeInfiniteScroll, pickImageFileViaFileChooser, pickProfilePhotoImageFile, preparePropertyForViewer, preparePropertyViewerTabs, provideFileChooserHooks, readSpreadsheetColumnIdentity, readSpreadsheetColumnWidth, registerFieldDefinitions, resolveExcludedFileProviderKeys, resolveFileChooserAccept, resolveFileChooserExtension, resolveFileListItemUrl, resolveFileUploaderEmptyStateDescription, resolveInfiniteScrollRoot, sortUserCardActions, sortUserCardRows, spreadsheetColumnIdentityProperties, toSpreadsheetColumnWidget, validateFileChooserItems, visibleUserCardActions, withValidationsOnEditorNode };
17145
+ export { AXPActivityLogComponent, AXPAvatarComponent, AXPCategoryTreeComponent, AXPColorChooserComponent, AXPColorPalettePickerComponent, AXPColumnItemListComponent, AXPCompareViewComponent, AXPConditionBuilderComponent, AXPConditionBuilderConditionComponent, AXPDataSelectorComponent, AXPDataSelectorService, AXPDragDropListComponent, AXPEntityListStylingDialogService, AXPEntityListStylingPopupComponent, AXPExpressionFieldDefinitions, AXPFileChooserCompressImagesHook, AXPFileChooserDirective, AXPFileChooserHookKeys, AXPFileChooserService, AXPFileChooserZipFilesHook, AXPFileUploaderDirective, AXPFileUploaderHookKeys, AXPFileUploaderService, AXPFileViewerComponent, AXPFileViewerFallbackContentComponent, AXPFileViewerService, AXPImageEditorPopupComponent, AXPImageEditorService, AXPInfiniteScrollDirective, AXPItemConfiguratorComponent, AXPLayoutFloatingZoomBarComponent, AXPLayoutSideDetailPanelComponent, AXPLayoutSideDetailPanelSectionDirective, AXPLocalDataSourceEditorDialogService, AXPMarkdownTemplateDirective, AXPMarkdownViewerComponent, AXPMenuBadgeHelper, AXPMenuCustomizerComponent, AXPMenuCustomizerService, AXPOutcomeResultsViewerComponent, AXPPageComponentRegistryService, AXPPreloadFiltersComponent, AXPPropertyViewerComponent, AXPPropertyViewerPopupComponent, AXPPropertyViewerService, AXPQueryColumnsComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewSaveButtonComponent, AXPQueryViewSaveDialogService, AXPQueryViewTabsComponent, AXPQueryViewsComponent, AXPRepeaterRowsLayoutComponent, AXPResourceAppointmentBoardProvider, AXPResourceAppointmentComponent, AXPResourceAppointmentService, AXPSectionItemsBuilderComponent, AXPSignatureEditorService, AXPSpreadsheetComponent, AXPStandardSectionItemsBuilderComponent, AXPStopwatchComponent, AXPTableColumnsEditorComponent, AXPTableColumnsEditorPopupComponent, AXPTableColumnsEditorService, AXPTableDataEditorComponent, AXPTableDataEditorPopupComponent, AXPTableDataEditorService, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPTemplateViewerComponent, AXPTemplateViewerService, AXPTextCommandColumnComponent, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXPUserCardComponent, AXPUserCardDirective, AXPUserCardService, AXPVirtualKeypadComponent, AXPWidgetFieldConfiguratorComponent, AXPWidgetItemComponent, AXPWidgetPropertyViewerComponent, AXPWidgetPropertyViewerPopupComponent, AXPWidgetPropertyViewerService, AXP_EXPRESSION_LOGIC_DEFINITIONS, AXP_EXPRESSION_OPERATION_DEFINITIONS, AXP_FILE_CHOOSER_DEFAULT_ZIP_ARCHIVE_NAME, AXP_FILE_CHOOSER_HOOK_PROVIDERS, AXP_FILE_CHOOSER_OPTION_KEYS, AXP_FILE_CHOOSER_PROVIDERS, AXP_FILE_UPLOADER_PROVIDERS, AXP_IMAGE_FILE_CHOOSER_ACCEPT, AXP_INFINITE_SCROLL_DEFAULT_ROOT_MARGIN, AXP_MENU_CUSTOMIZER_SERVICE, AXP_PAGE_COMPONENT_PROVIDER, AXP_PAGE_LAYOUT_ELEMENT_ID, AXP_PROFILE_PHOTO_GRAVATAR_SOURCE_KEY, AXP_RESOURCE_APPOINTMENT_PROVIDER, AXP_SIGNATURE_PROVIDER, AXP_SPREADSHEET_COLUMN_WIDGET_TYPES, AXP_SYSTEM_FILE_CHOOSER_PROVIDER, AXP_SYSTEM_FILE_UPLOADER_PROVIDER, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER, PROPERTY_VIEWER_EXPRESSION_EDITOR_MIN_LINES, SPREADSHEET_COLUMN_NAME_PATH, SPREADSHEET_COLUMN_TITLE_PATH, STANDARD_SECTION_ITEMS_SECTION_TABS, USER_CARD_HOVER_OPEN_DELAY_MS, USER_CARD_ITEMS_HOOK, USER_CARD_ITEMS_SKELETON_DELAY_MS, asSpreadsheetColumnTitle, buildEntityListStylingRulesLayout, buildFileChooserOptions, buildGravatarAvatarUrl, buildPropertyViewerInitialContextFromProperties, buildPropertyViewerTabsFromProperties, buildTableColumnsEditorLayout, compressImageFile, createAttachedFileProviderMenu, createZipArchive, fetchGravatarImageFile, fileListItemToFileViewerItem, fileListItemToImageFile, fileMatchesAccept, fileNameMatchesAccept, filterFileProvidersByContext, filterFilesByAcceptAndMaxSize, formatAcceptForDisplay, formatMaxFileSizeForDisplay, getFieldDefinitions, getLogicDefinition, getOperationDefinition, isPropertyBindingExpressionFormValue, isUnrestrictedFileAccept, mapFileListToViewerItems, md5Hex, mergeInfiniteScrollPage, mergeObjectsReplacingArrays, normalizeFileViewerBoundValue, normalizeSpreadsheetColumnName, notifyFileAcceptRejections, observeInfiniteScroll, pickImageFileViaFileChooser, pickProfilePhotoImageFile, preparePropertyForViewer, preparePropertyViewerTabs, provideFileChooserHooks, readSpreadsheetColumnIdentity, readSpreadsheetColumnWidth, registerFieldDefinitions, resolveChooserItemFile, resolveExcludedFileProviderKeys, resolveFileChooserAccept, resolveFileChooserExtension, resolveFileListItemUrl, resolveFileUploaderEmptyStateDescription, resolveInfiniteScrollRoot, sortUserCardActions, sortUserCardRows, spreadsheetColumnIdentityProperties, toSpreadsheetColumnWidget, validateFileChooserItems, visibleUserCardActions, withValidationsOnEditorNode };
16879
17146
  //# sourceMappingURL=acorex-platform-framework-client-layout-components.mjs.map