@fundamental-ngx/platform 0.64.2-rc.2 → 0.64.2-rc.20

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.
@@ -1,7 +1,7 @@
1
1
  import * as i4 from '@angular/cdk/a11y';
2
2
  import { DOWN_ARROW, UP_ARROW, SPACE } from '@angular/cdk/keycodes';
3
3
  import * as i0 from '@angular/core';
4
- import { ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, Inject, signal, inject, DestroyRef, ViewChild, ViewChildren, Input, computed, DOCUMENT, input, ContentChild, Optional, Host, EventEmitter, Output, forwardRef, Pipe, TemplateRef, Directive, ChangeDetectorRef, afterEveryRender, output, linkedSignal, ContentChildren, HostBinding, NgZone, ElementRef, effect, booleanAttribute, NgModule } from '@angular/core';
4
+ import { ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, Inject, signal, inject, DestroyRef, ViewChild, ViewChildren, Input, computed, DOCUMENT, input, ContentChild, Optional, Host, EventEmitter, Output, forwardRef, Pipe, TemplateRef, Directive, ChangeDetectorRef, afterEveryRender, output, linkedSignal, untracked, viewChildren, effect, ContentChildren, HostBinding, NgZone, ElementRef, booleanAttribute, NgModule } from '@angular/core';
5
5
  import { NgTemplateOutlet, NgStyle, AsyncPipe, NgClass } from '@angular/common';
6
6
  import * as i3 from '@fundamental-ngx/cdk/utils';
7
7
  import { TemplateDirective, RtlService, InitialFocusDirective, DisabledBehaviorDirective, FDK_FOCUSABLE_ITEM_DIRECTIVE, FDK_FOCUSABLE_LIST_DIRECTIVE, ValueByPathPipe, set, uuidv4, destroyObservable, KeyUtil, get, range, RangeSelector, resizeObservable, uniq, DragAndDropModule, IntersectionSpyDirective, FDK_FOCUSABLE_GRID_DIRECTIVE, DndListDirective, FocusableGridDirective } from '@fundamental-ngx/cdk/utils';
@@ -20,8 +20,8 @@ import { fromEvent, BehaviorSubject, Subscription, combineLatest, distinctUntilC
20
20
  import { startWith, take, debounceTime, skip, filter, switchMap, takeUntil, map, distinctUntilChanged as distinctUntilChanged$1, tap } from 'rxjs/operators';
21
21
  import { ButtonComponent } from '@fundamental-ngx/core/button';
22
22
  import { takeUntilDestroyed, outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
23
- import { FormItemComponent, FormLabelComponent, FormControlComponent } from '@fundamental-ngx/core/form';
24
- import { ListLinkDirective, ListIconDirective, ListTitleDirective, ListComponent as ListComponent$1, ListItemComponent, ListGroupHeaderDirective } from '@fundamental-ngx/core/list';
23
+ import { FormItemComponent, FormLabelComponent, FormControlComponent, FormGroupComponent } from '@fundamental-ngx/core/form';
24
+ import { ListLinkDirective, ListIconDirective, ListTitleDirective, ListComponent as ListComponent$1, ListItemComponent, ListGroupHeaderDirective, ListSecondaryDirective } from '@fundamental-ngx/core/list';
25
25
  import { PopoverComponent, PopoverTriggerDirective } from '@fundamental-ngx/core/popover';
26
26
  import { PopoverPlacement } from '@fundamental-ngx/core/shared';
27
27
  import { ListComponent, FreeContentListItemComponent } from '@fundamental-ngx/platform/list';
@@ -42,6 +42,8 @@ import { LayoutGridRowDirective, LayoutGridColDirective, LayoutGridComponent } f
42
42
  import { SelectComponent, OptionComponent } from '@fundamental-ngx/core/select';
43
43
  import { PanelComponent, PanelTitleDirective, PanelContentDirective } from '@fundamental-ngx/core/panel';
44
44
  import { RadioButtonComponent } from '@fundamental-ngx/core/radio';
45
+ import { ComboboxComponent } from '@fundamental-ngx/core/combobox';
46
+ import { SegmentedButtonComponent } from '@fundamental-ngx/core/segmented-button';
45
47
  import { IconTabBarComponent, IconTabBarTabComponent } from '@fundamental-ngx/platform/icon-tab-bar';
46
48
  import { InputComponent, PlatformDatePickerComponent, SwitchComponent } from '@fundamental-ngx/platform/form';
47
49
 
@@ -2309,11 +2311,11 @@ class FilterMultiSelectComponent {
2309
2311
  this._value = this._selectableOptions.filter(({ selected }) => selected).map(({ value }) => value);
2310
2312
  }
2311
2313
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FilterMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2312
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: FilterMultiSelectComponent, isStandalone: true, selector: "fdp-filter-multi-select", inputs: { options: "options", filterBy: "filterBy" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<ul fd-list [selection]=\"true\">\n @for (option of _selectableOptions; track option) {\n <li fd-list-item [selected]=\"option.selected\">\n <fd-checkbox [ngModel]=\"option.selected\" (ngModelChange)=\"_onSelectChange(option, $event)\"></fd-checkbox>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n", dependencies: [{ kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "component", type: CheckboxComponent, selector: "fd-checkbox", inputs: ["wrapLabel", "valignLabel", "ariaLabel", "role", "value", "ariaLabelledBy", "ariaDescribedBy", "title", "inputId", "state", "name", "label", "disabled", "readonly", "tristate", "tristateSelectable", "labelClass", "required", "displayOnly", "values", "standalone"], outputs: ["focusChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2314
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: FilterMultiSelectComponent, isStandalone: true, selector: "fdp-filter-multi-select", inputs: { options: "options", filterBy: "filterBy" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<ul fd-list [selection]=\"true\">\n @for (option of _selectableOptions; track option) {\n <li\n fd-list-item\n [selected]=\"option.selected\"\n [attr.aria-label]=\"\n ('platformTable.filterDialogFilterByLabel' | fdTranslate: { filterLabel: option.label })()\n \"\n >\n <fd-checkbox [ngModel]=\"option.selected\" (ngModelChange)=\"_onSelectChange(option, $event)\"></fd-checkbox>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n", dependencies: [{ kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "component", type: CheckboxComponent, selector: "fd-checkbox", inputs: ["wrapLabel", "valignLabel", "ariaLabel", "role", "value", "ariaLabelledBy", "ariaDescribedBy", "title", "inputId", "state", "name", "label", "disabled", "readonly", "tristate", "tristateSelectable", "labelClass", "required", "displayOnly", "values", "standalone"], outputs: ["focusChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2313
2315
  }
2314
2316
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FilterMultiSelectComponent, decorators: [{
2315
2317
  type: Component,
2316
- args: [{ selector: 'fdp-filter-multi-select', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ListComponent$1, ListItemComponent, CheckboxComponent, FormsModule, ListTitleDirective], template: "<ul fd-list [selection]=\"true\">\n @for (option of _selectableOptions; track option) {\n <li fd-list-item [selected]=\"option.selected\">\n <fd-checkbox [ngModel]=\"option.selected\" (ngModelChange)=\"_onSelectChange(option, $event)\"></fd-checkbox>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n" }]
2318
+ args: [{ selector: 'fdp-filter-multi-select', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ListComponent$1, ListItemComponent, CheckboxComponent, FormsModule, ListTitleDirective, FdTranslatePipe], template: "<ul fd-list [selection]=\"true\">\n @for (option of _selectableOptions; track option) {\n <li\n fd-list-item\n [selected]=\"option.selected\"\n [attr.aria-label]=\"\n ('platformTable.filterDialogFilterByLabel' | fdTranslate: { filterLabel: option.label })()\n \"\n >\n <fd-checkbox [ngModel]=\"option.selected\" (ngModelChange)=\"_onSelectChange(option, $event)\"></fd-checkbox>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n" }]
2317
2319
  }], propDecorators: { options: [{
2318
2320
  type: Input
2319
2321
  }], filterBy: [{
@@ -2354,11 +2356,11 @@ class FilterSingleSelectComponent {
2354
2356
  }
2355
2357
  }
2356
2358
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FilterSingleSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2357
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: FilterSingleSelectComponent, isStandalone: true, selector: "fdp-filter-single-select", inputs: { options: "options", filterBy: "filterBy" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<ul fd-list [selection]=\"true\">\n <li fd-list-item [selected]=\"_value === NOT_FILTERED_OPTION_VALUE\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"NOT_FILTERED_OPTION_VALUE\"\n state=\"default\"\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.filterDialogNotFilteredLabel' | fdTranslate)() }}</span>\n </li>\n @for (option of options; track option) {\n <li fd-list-item [selected]=\"option.value === _value\">\n <fd-radio-button\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n [value]=\"option.value\"\n name=\"filtering-settings-single-select\"\n ></fd-radio-button>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n", dependencies: [{ kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "component", type: RadioButtonComponent, selector: "fd-radio-button", inputs: ["ariaLabel", "ariaLabelledBy", "ariaDescribedBy", "title", "tabIndex", "state", "disabled", "readOnly", "selectedValue", "name", "id", "value", "required", "standalone", "wrapLabel", "valignLabel"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2359
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: FilterSingleSelectComponent, isStandalone: true, selector: "fdp-filter-single-select", inputs: { options: "options", filterBy: "filterBy" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<ul fd-list [selection]=\"true\">\n <li fd-list-item [selected]=\"_value === NOT_FILTERED_OPTION_VALUE\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"NOT_FILTERED_OPTION_VALUE\"\n state=\"default\"\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.filterDialogNotFilteredLabel' | fdTranslate)() }}</span>\n </li>\n @for (option of options; track option) {\n <li\n fd-list-item\n [selected]=\"option.value === _value\"\n [attr.aria-label]=\"\n ('platformTable.filterDialogFilterByLabel' | fdTranslate: { filterLabel: option.label })()\n \"\n >\n <fd-radio-button\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n [value]=\"option.value\"\n name=\"filtering-settings-single-select\"\n ></fd-radio-button>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n", dependencies: [{ kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "component", type: RadioButtonComponent, selector: "fd-radio-button", inputs: ["ariaLabel", "ariaLabelledBy", "ariaDescribedBy", "title", "tabIndex", "state", "disabled", "readOnly", "selectedValue", "name", "id", "value", "required", "standalone", "wrapLabel", "valignLabel"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2358
2360
  }
2359
2361
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FilterSingleSelectComponent, decorators: [{
2360
2362
  type: Component,
2361
- args: [{ selector: 'fdp-filter-single-select', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ListComponent$1, ListItemComponent, RadioButtonComponent, FormsModule, ListTitleDirective, FdTranslatePipe], template: "<ul fd-list [selection]=\"true\">\n <li fd-list-item [selected]=\"_value === NOT_FILTERED_OPTION_VALUE\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"NOT_FILTERED_OPTION_VALUE\"\n state=\"default\"\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.filterDialogNotFilteredLabel' | fdTranslate)() }}</span>\n </li>\n @for (option of options; track option) {\n <li fd-list-item [selected]=\"option.value === _value\">\n <fd-radio-button\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n [value]=\"option.value\"\n name=\"filtering-settings-single-select\"\n ></fd-radio-button>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n" }]
2363
+ args: [{ selector: 'fdp-filter-single-select', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ListComponent$1, ListItemComponent, RadioButtonComponent, FormsModule, ListTitleDirective, FdTranslatePipe], template: "<ul fd-list [selection]=\"true\">\n <li fd-list-item [selected]=\"_value === NOT_FILTERED_OPTION_VALUE\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"NOT_FILTERED_OPTION_VALUE\"\n state=\"default\"\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.filterDialogNotFilteredLabel' | fdTranslate)() }}</span>\n </li>\n @for (option of options; track option) {\n <li\n fd-list-item\n [selected]=\"option.value === _value\"\n [attr.aria-label]=\"\n ('platformTable.filterDialogFilterByLabel' | fdTranslate: { filterLabel: option.label })()\n \"\n >\n <fd-radio-button\n [ngModel]=\"_value\"\n (ngModelChange)=\"_onValueChange($event)\"\n [value]=\"option.value\"\n name=\"filtering-settings-single-select\"\n ></fd-radio-button>\n <span fd-list-title>{{ option.label }}</span>\n </li>\n }\n</ul>\n" }]
2362
2364
  }], propDecorators: { options: [{
2363
2365
  type: Input
2364
2366
  }], filterBy: [{
@@ -2447,7 +2449,7 @@ class FiltersListStepComponent {
2447
2449
  this.selectFilter = new EventEmitter();
2448
2450
  }
2449
2451
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FiltersListStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2450
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: FiltersListStepComponent, isStandalone: true, selector: "fdp-filters-list-step", inputs: { filters: "filters", headingLevel: "headingLevel" }, outputs: { selectFilter: "selectFilter" }, providers: [{ provide: FILTERS_VIEW_STEP_TOKEN, useExisting: forwardRef(() => FiltersListStepComponent) }], viewQueries: [{ propertyName: "titleTemplateRef", first: true, predicate: ["titleTemplate"], descendants: true }, { propertyName: "bodyTemplateRef", first: true, predicate: ["bodyTemplate"], descendants: true }], ngImport: i0, template: "<ng-template #titleTemplate>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.filterDialogFilterTitle' | fdTranslate)()\n }}</span>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div fd-list-group-header>\n <span fd-list-title id=\"platformTableInternalFilterListGroupHeader\">\n {{ ('platformTable.filterDialogFilterBy' | fdTranslate)() }}\n </span>\n </div>\n <ul fd-list aria-labelledby=\"platformTableInternalFilterListGroupHeader\" [navigationIndicator]=\"true\">\n @for (filter of filters; track filter) {\n <li\n fd-list-item\n [interactive]=\"true\"\n (click)=\"selectFilter.emit(filter)\"\n (keydown.space)=\"selectFilter.emit(filter)\"\n (keydown.enter)=\"selectFilter.emit(filter)\"\n >\n <a fd-list-link [navigationIndicator]=\"true\">\n <span fd-list-title>{{ filter.label }}</span>\n </a>\n </li>\n }\n </ul>\n</ng-template>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "[fd-title], [fdTitle]", inputs: ["twoLineClamp", "headerSize", "wrap"], exportAs: ["fd-title"] }, { kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "directive", type: ListGroupHeaderDirective, selector: "[fdListGroupHeader], [fd-list-group-header]", inputs: ["nativeElementId"], outputs: ["keyDown"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "directive", type: ListLinkDirective, selector: "[fd-list-link], [fdListLink]", inputs: ["navigationIndicator", "navigated", "focusable"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2452
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: FiltersListStepComponent, isStandalone: true, selector: "fdp-filters-list-step", inputs: { filters: "filters", headingLevel: "headingLevel" }, outputs: { selectFilter: "selectFilter" }, providers: [{ provide: FILTERS_VIEW_STEP_TOKEN, useExisting: forwardRef(() => FiltersListStepComponent) }], viewQueries: [{ propertyName: "titleTemplateRef", first: true, predicate: ["titleTemplate"], descendants: true }, { propertyName: "bodyTemplateRef", first: true, predicate: ["bodyTemplate"], descendants: true }], ngImport: i0, template: "<ng-template #titleTemplate>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.filterDialogFilterTitle' | fdTranslate)()\n }}</span>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div fd-list-group-header>\n <span fd-list-title id=\"platformTableInternalFilterListGroupHeader\">\n {{ ('platformTable.filterDialogFilterBy' | fdTranslate)() }}\n </span>\n </div>\n <ul fd-list aria-labelledby=\"platformTableInternalFilterListGroupHeader\" [navigationIndicator]=\"true\">\n @for (filter of filters; track filter) {\n <li\n fd-list-item\n [interactive]=\"true\"\n (click)=\"selectFilter.emit(filter)\"\n (keydown.space)=\"selectFilter.emit(filter)\"\n (keydown.enter)=\"selectFilter.emit(filter)\"\n aria-expanded=\"false\"\n >\n <a fd-list-link [navigationIndicator]=\"true\">\n <span fd-list-title>{{ filter.label }}</span>\n </a>\n </li>\n }\n </ul>\n</ng-template>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "[fd-title], [fdTitle]", inputs: ["twoLineClamp", "headerSize", "wrap"], exportAs: ["fd-title"] }, { kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "directive", type: ListGroupHeaderDirective, selector: "[fdListGroupHeader], [fd-list-group-header]", inputs: ["nativeElementId"], outputs: ["keyDown"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "directive", type: ListLinkDirective, selector: "[fd-list-link], [fdListLink]", inputs: ["navigationIndicator", "navigated", "focusable"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2451
2453
  }
2452
2454
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FiltersListStepComponent, decorators: [{
2453
2455
  type: Component,
@@ -2459,7 +2461,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
2459
2461
  ListLinkDirective,
2460
2462
  ListTitleDirective,
2461
2463
  FdTranslatePipe
2462
- ], template: "<ng-template #titleTemplate>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.filterDialogFilterTitle' | fdTranslate)()\n }}</span>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div fd-list-group-header>\n <span fd-list-title id=\"platformTableInternalFilterListGroupHeader\">\n {{ ('platformTable.filterDialogFilterBy' | fdTranslate)() }}\n </span>\n </div>\n <ul fd-list aria-labelledby=\"platformTableInternalFilterListGroupHeader\" [navigationIndicator]=\"true\">\n @for (filter of filters; track filter) {\n <li\n fd-list-item\n [interactive]=\"true\"\n (click)=\"selectFilter.emit(filter)\"\n (keydown.space)=\"selectFilter.emit(filter)\"\n (keydown.enter)=\"selectFilter.emit(filter)\"\n >\n <a fd-list-link [navigationIndicator]=\"true\">\n <span fd-list-title>{{ filter.label }}</span>\n </a>\n </li>\n }\n </ul>\n</ng-template>\n" }]
2464
+ ], template: "<ng-template #titleTemplate>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.filterDialogFilterTitle' | fdTranslate)()\n }}</span>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div fd-list-group-header>\n <span fd-list-title id=\"platformTableInternalFilterListGroupHeader\">\n {{ ('platformTable.filterDialogFilterBy' | fdTranslate)() }}\n </span>\n </div>\n <ul fd-list aria-labelledby=\"platformTableInternalFilterListGroupHeader\" [navigationIndicator]=\"true\">\n @for (filter of filters; track filter) {\n <li\n fd-list-item\n [interactive]=\"true\"\n (click)=\"selectFilter.emit(filter)\"\n (keydown.space)=\"selectFilter.emit(filter)\"\n (keydown.enter)=\"selectFilter.emit(filter)\"\n aria-expanded=\"false\"\n >\n <a fd-list-link [navigationIndicator]=\"true\">\n <span fd-list-title>{{ filter.label }}</span>\n </a>\n </li>\n }\n </ul>\n</ng-template>\n" }]
2463
2465
  }], propDecorators: { filters: [{
2464
2466
  type: Input
2465
2467
  }], headingLevel: [{
@@ -2706,6 +2708,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
2706
2708
  let sortOrderHeaderUniqueId = 0;
2707
2709
  let sortDialogSortByHeaderUniqueId = 0;
2708
2710
  class SortingComponent {
2711
+ /** @hidden */
2709
2712
  constructor() {
2710
2713
  /** Input data for sorting */
2711
2714
  this.sortingData = input(/* @ts-ignore */
@@ -2715,12 +2718,42 @@ class SortingComponent {
2715
2718
  ...(ngDevMode ? [undefined, { debugName: "initialSorting" }] : /* istanbul ignore next */ []));
2716
2719
  /** Event emitter for sort changes */
2717
2720
  this.sortChange = output();
2718
- /** Current selected sorting direction - resets when sortingData changes */
2719
- this.direction = linkedSignal(() => this.sortingData()?.direction ?? INITIAL_DIRECTION, /* @ts-ignore */
2720
- ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
2721
- /** Current selected sorting field - resets when sortingData changes */
2722
- this.field = linkedSignal(() => this.sortingData()?.field ?? NOT_SORTED_OPTION_VALUE, /* @ts-ignore */
2723
- ...(ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []));
2721
+ /** Event emitter for reset availability changes */
2722
+ this.resetAvailabilityChange = outputFromObservable(toObservable(computed(() => {
2723
+ const initial = this.initialSorting();
2724
+ if (!initial) {
2725
+ return false;
2726
+ }
2727
+ // Get current sort criteria (only those with fields selected)
2728
+ const currentCriteria = this.sortCriteriaList().filter((c) => c.field !== null);
2729
+ // Build initial criteria array for comparison
2730
+ const initialCriteria = initial.field !== null ? [{ field: initial.field, direction: initial.direction }] : [];
2731
+ // Reset is available if:
2732
+ // 1. Number of sort criteria changed
2733
+ // 2. Any criteria field/direction differs from initial
2734
+ // 3. Combobox has invalid text
2735
+ if (currentCriteria.length !== initialCriteria.length) {
2736
+ return true;
2737
+ }
2738
+ for (let i = 0; i < currentCriteria.length; i++) {
2739
+ if (currentCriteria[i].field !== initialCriteria[i]?.field ||
2740
+ currentCriteria[i].direction !== initialCriteria[i]?.direction) {
2741
+ return true;
2742
+ }
2743
+ }
2744
+ return this._hasInvalidComboboxText();
2745
+ })).pipe(distinctUntilChanged()));
2746
+ /** Event emitter for validity changes */
2747
+ this.validityChange = outputFromObservable(toObservable(computed(() => {
2748
+ const invalidMap = this._invalidInputPerRow();
2749
+ // Valid if no rows have invalid input
2750
+ for (const isInvalid of invalidMap.values()) {
2751
+ if (isInvalid) {
2752
+ return false;
2753
+ }
2754
+ }
2755
+ return true;
2756
+ })).pipe(distinctUntilChanged()));
2724
2757
  /** @hidden */
2725
2758
  this.sortOrderHeaderId = `fdp-table-sort-order-header-${sortOrderHeaderUniqueId++}`;
2726
2759
  /** @hidden */
@@ -2735,40 +2768,450 @@ class SortingComponent {
2735
2768
  /** Available table columns for sorting */
2736
2769
  this.columns = computed(() => this.sortingData()?.columns ?? [], /* @ts-ignore */
2737
2770
  ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
2738
- /** Event emitter for reset availability changes */
2739
- this.resetAvailabilityChange = outputFromObservable(toObservable(computed(() => {
2740
- const initial = this.initialSorting();
2741
- if (!initial) {
2742
- return false;
2771
+ /** @hidden Computed signal that checks if any row has invalid input */
2772
+ this.isValid = computed(() => {
2773
+ const invalidMap = this._invalidInputPerRow();
2774
+ // Valid if no rows have invalid input
2775
+ for (const isInvalid of invalidMap.values()) {
2776
+ if (isInvalid) {
2777
+ return false;
2778
+ }
2743
2779
  }
2744
- return this.direction() !== initial.direction || this.field() !== initial.field;
2745
- })).pipe(distinctUntilChanged()));
2780
+ return true;
2781
+ }, /* @ts-ignore */
2782
+ ...(ngDevMode ? [{ debugName: "isValid" }] : /* istanbul ignore next */ []));
2783
+ /** @hidden Computed signal that returns the currently selected column object */
2784
+ this.selectedColumn = computed(() => {
2785
+ const currentField = this.firstSortingField();
2786
+ return this.columns().find((col) => col.key === currentField) ?? null;
2787
+ }, /* @ts-ignore */
2788
+ ...(ngDevMode ? [{ debugName: "selectedColumn" }] : /* istanbul ignore next */ []));
2789
+ /**
2790
+ * @hidden
2791
+ * Computed signal that returns available columns for each row.
2792
+ * Columns selected in other rows are filtered out.
2793
+ */
2794
+ this.availableColumnsPerRow = computed(() => {
2795
+ const allColumns = this.columns();
2796
+ const criteriaList = this.sortCriteriaList();
2797
+ return criteriaList.map((_, rowIndex) => {
2798
+ // Collect fields selected in OTHER rows
2799
+ const selectedFieldsInOtherRows = new Set(criteriaList.filter((c, index) => index !== rowIndex && c.field !== null).map((c) => c.field));
2800
+ // Return columns not selected in other rows
2801
+ return allColumns.filter((col) => !selectedFieldsInOtherRows.has(col.key));
2802
+ });
2803
+ }, /* @ts-ignore */
2804
+ ...(ngDevMode ? [{ debugName: "availableColumnsPerRow" }] : /* istanbul ignore next */ []));
2805
+ /**
2806
+ * @hidden
2807
+ * Computed signal that returns the selected column object for each row.
2808
+ */
2809
+ this.selectedColumnsPerRow = computed(() => {
2810
+ const allColumns = this.columns();
2811
+ const criteriaList = this.sortCriteriaList();
2812
+ return criteriaList.map((criteria) => {
2813
+ if (!criteria.field) {
2814
+ return null;
2815
+ }
2816
+ return allColumns.find((col) => col.key === criteria.field) ?? null;
2817
+ });
2818
+ }, /* @ts-ignore */
2819
+ ...(ngDevMode ? [{ debugName: "selectedColumnsPerRow" }] : /* istanbul ignore next */ []));
2820
+ /**
2821
+ * @hidden
2822
+ * Computed signal that returns the direction for each row.
2823
+ */
2824
+ this.directionsPerRow = computed(() => this.sortCriteriaList().map((criteria) => criteria.direction ?? INITIAL_DIRECTION), /* @ts-ignore */
2825
+ ...(ngDevMode ? [{ debugName: "directionsPerRow" }] : /* istanbul ignore next */ []));
2826
+ /**
2827
+ * @hidden
2828
+ * Computed signal that returns the form state ('error' or undefined) for each row.
2829
+ */
2830
+ this.rowStates = computed(() => {
2831
+ const invalidMap = this._invalidInputPerRow();
2832
+ return this.sortCriteriaList().map((_, index) => (invalidMap.get(index) ? 'error' : undefined));
2833
+ }, /* @ts-ignore */
2834
+ ...(ngDevMode ? [{ debugName: "rowStates" }] : /* istanbul ignore next */ []));
2835
+ /**
2836
+ * @hidden
2837
+ * Computed signal that returns visibility for each row.
2838
+ * First row is always visible, subsequent rows visible only if previous has selection.
2839
+ */
2840
+ this.rowVisibility = computed(() => {
2841
+ const criteriaList = this.sortCriteriaList();
2842
+ return criteriaList.map((_, index) => {
2843
+ if (index === 0) {
2844
+ return true;
2845
+ }
2846
+ return criteriaList[index - 1]?.field !== null;
2847
+ });
2848
+ }, /* @ts-ignore */
2849
+ ...(ngDevMode ? [{ debugName: "rowVisibility" }] : /* istanbul ignore next */ []));
2850
+ /**
2851
+ * @hidden
2852
+ * Computed signal that returns whether each row can be moved up.
2853
+ */
2854
+ this.canMoveUpPerRow = computed(() => {
2855
+ const criteriaList = this.sortCriteriaList();
2856
+ return criteriaList.map((criteria, index) => {
2857
+ if (index === 0) {
2858
+ return false;
2859
+ }
2860
+ return criteria.field !== null;
2861
+ });
2862
+ }, /* @ts-ignore */
2863
+ ...(ngDevMode ? [{ debugName: "canMoveUpPerRow" }] : /* istanbul ignore next */ []));
2864
+ /**
2865
+ * @hidden
2866
+ * Computed signal that returns whether each row can be moved down.
2867
+ */
2868
+ this.canMoveDownPerRow = computed(() => {
2869
+ const criteriaList = this.sortCriteriaList();
2870
+ return criteriaList.map((criteria, index) => {
2871
+ const nextRow = criteriaList[index + 1];
2872
+ // Can't move down if current row has no selection
2873
+ if (criteria.field === null) {
2874
+ return false;
2875
+ }
2876
+ // Can't move down if next row doesn't exist or has no selection
2877
+ return nextRow !== undefined && nextRow.field !== null;
2878
+ });
2879
+ }, /* @ts-ignore */
2880
+ ...(ngDevMode ? [{ debugName: "canMoveDownPerRow" }] : /* istanbul ignore next */ []));
2881
+ /**
2882
+ * @hidden
2883
+ * Computed signal that returns whether each row can be deleted.
2884
+ */
2885
+ this.canDeletePerRow = computed(() => this.sortCriteriaList().map((criteria) => criteria.field !== null), /* @ts-ignore */
2886
+ ...(ngDevMode ? [{ debugName: "canDeletePerRow" }] : /* istanbul ignore next */ []));
2887
+ /** Current selected sorting direction - derived from first sortBy entry */
2888
+ this.direction = linkedSignal(() => this.sortingData()?.sortBy?.[0]?.direction ?? INITIAL_DIRECTION, /* @ts-ignore */
2889
+ ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
2890
+ /** Current selected sorting field - derived from first sortBy entry */
2891
+ this.firstSortingField = linkedSignal(() => this.sortingData()?.sortBy?.[0]?.field ?? NOT_SORTED_OPTION_VALUE, /* @ts-ignore */
2892
+ ...(ngDevMode ? [{ debugName: "firstSortingField" }] : /* istanbul ignore next */ []));
2893
+ /**
2894
+ * @hidden
2895
+ * Array of sort criteria rows. Each row has a field and direction.
2896
+ * linkedSignal resets when sortBy reference changes (e.g., on reset),
2897
+ * but allows local modifications via .set()/.update().
2898
+ */
2899
+ this.sortCriteriaList = linkedSignal(() => {
2900
+ // Only track sortBy reference changes, not all sortingData changes
2901
+ const sortBy = this._sortByRef() ?? [];
2902
+ // Use untracked for columns since we don't want column changes to reset the list
2903
+ const columns = untracked(() => this.sortingData()?.columns ?? []);
2904
+ return columns.map((_, index) => {
2905
+ const existingCriteria = sortBy[index];
2906
+ if (existingCriteria) {
2907
+ return {
2908
+ field: existingCriteria.field,
2909
+ direction: existingCriteria.direction
2910
+ };
2911
+ }
2912
+ return { field: null, direction: INITIAL_DIRECTION };
2913
+ });
2914
+ }, /* @ts-ignore */
2915
+ ...(ngDevMode ? [{ debugName: "sortCriteriaList" }] : /* istanbul ignore next */ []));
2916
+ /**
2917
+ * @hidden
2918
+ * Extracts the sortBy array reference from sortingData.
2919
+ * Used as the source for linkedSignal to track only sortBy reference changes.
2920
+ */
2921
+ this._sortByRef = computed(() => this.sortingData()?.sortBy, /* @ts-ignore */
2922
+ ...(ngDevMode ? [{ debugName: "_sortByRef" }] : /* istanbul ignore next */ []));
2923
+ /**
2924
+ * @hidden
2925
+ * Tracks invalid input text per row (non-empty text that doesn't match any column).
2926
+ * Resets to empty Map when sortBy reference changes.
2927
+ */
2928
+ this._invalidInputPerRow = linkedSignal(() => {
2929
+ // Only track sortBy reference changes
2930
+ this._sortByRef();
2931
+ return new Map();
2932
+ }, /* @ts-ignore */
2933
+ ...(ngDevMode ? [{ debugName: "_invalidInputPerRow" }] : /* istanbul ignore next */ []));
2934
+ /**
2935
+ * @hidden
2936
+ * Computed signal that checks if any row has invalid combobox text.
2937
+ * Used by resetAvailabilityChange to determine if reset should be available.
2938
+ */
2939
+ this._hasInvalidComboboxText = computed(() => {
2940
+ const invalidMap = this._invalidInputPerRow();
2941
+ for (const isInvalid of invalidMap.values()) {
2942
+ if (isInvalid) {
2943
+ return true;
2944
+ }
2945
+ }
2946
+ return false;
2947
+ }, /* @ts-ignore */
2948
+ ...(ngDevMode ? [{ debugName: "_hasInvalidComboboxText" }] : /* istanbul ignore next */ []));
2949
+ /** @hidden Reference to the comboboxes for programmatic reset */
2950
+ this._comboboxes = viewChildren('sortCombobox', /* @ts-ignore */
2951
+ ...(ngDevMode ? [{ debugName: "_comboboxes" }] : /* istanbul ignore next */ []));
2952
+ // DOM side effect: sync combobox display text when sortBy reference changes.
2953
+ // This is needed because when user types invalid text and reset happens,
2954
+ // the model value might not change but the display text needs to update.
2955
+ effect(() => {
2956
+ const sortBy = this._sortByRef();
2957
+ // Only sync when reference changes (not on every sortingData update)
2958
+ if (sortBy !== this._previousSortByRef) {
2959
+ this._previousSortByRef = sortBy;
2960
+ // Use untracked to avoid creating additional dependencies
2961
+ untracked(() => this._syncComboboxDisplayText());
2962
+ }
2963
+ });
2746
2964
  }
2747
2965
  /**
2748
- * Handle sort direction changes.
2749
- * @param direction New sorting direction.
2966
+ * Get available columns for a specific sort criteria row.
2967
+ * Excludes columns that are already selected in other rows.
2968
+ * @param rowIndex Index of the current row.
2969
+ * @returns Array of columns available for selection.
2750
2970
  */
2751
- _sortDirectionChange(direction) {
2752
- this.direction.set(direction);
2971
+ getAvailableColumns(rowIndex) {
2972
+ return this.availableColumnsPerRow()[rowIndex] ?? [];
2973
+ }
2974
+ /**
2975
+ * Get the selected column object for a specific row.
2976
+ * @param rowIndex Index of the row.
2977
+ * @returns The selected column object or null.
2978
+ */
2979
+ getSelectedColumnForRow(rowIndex) {
2980
+ return this.selectedColumnsPerRow()[rowIndex] ?? null;
2981
+ }
2982
+ /**
2983
+ * Get the direction for a specific row.
2984
+ * @param rowIndex Index of the row.
2985
+ * @returns The sort direction.
2986
+ */
2987
+ getDirectionForRow(rowIndex) {
2988
+ return this.directionsPerRow()[rowIndex] ?? INITIAL_DIRECTION;
2989
+ }
2990
+ /**
2991
+ * Get the form state for a specific row's combobox.
2992
+ * Returns 'error' if the row has invalid input, undefined otherwise.
2993
+ * @param rowIndex Index of the row.
2994
+ * @returns The form state or undefined.
2995
+ */
2996
+ getRowState(rowIndex) {
2997
+ return this.rowStates()[rowIndex];
2998
+ }
2999
+ /**
3000
+ * Determine if a row should be visible.
3001
+ * The first row is always visible. Subsequent rows are only visible
3002
+ * if the previous row has a column selected.
3003
+ * @param rowIndex Index of the row.
3004
+ * @returns True if the row should be visible.
3005
+ */
3006
+ isRowVisible(rowIndex) {
3007
+ return this.rowVisibility()[rowIndex] ?? false;
3008
+ }
3009
+ /**
3010
+ * Check if a row can be moved up.
3011
+ * A row can move up if it's not the first row and has a field selected.
3012
+ * @param rowIndex Index of the row.
3013
+ * @returns True if the row can be moved up.
3014
+ */
3015
+ canMoveUp(rowIndex) {
3016
+ return this.canMoveUpPerRow()[rowIndex] ?? false;
3017
+ }
3018
+ /**
3019
+ * Check if a row can be moved down.
3020
+ * A row can move down if there's a visible row below it with a field selected.
3021
+ * @param rowIndex Index of the row.
3022
+ * @returns True if the row can be moved down.
3023
+ */
3024
+ canMoveDown(rowIndex) {
3025
+ return this.canMoveDownPerRow()[rowIndex] ?? false;
3026
+ }
3027
+ /**
3028
+ * Check if a row can be deleted (cleared).
3029
+ * A row can be deleted if it has a field selected.
3030
+ * @param rowIndex Index of the row.
3031
+ * @returns True if the row can be deleted.
3032
+ */
3033
+ canDelete(rowIndex) {
3034
+ return this.canDeletePerRow()[rowIndex] ?? false;
3035
+ }
3036
+ /**
3037
+ * Move a sort criteria row up (swap with the row above).
3038
+ * @param rowIndex Index of the row to move up.
3039
+ */
3040
+ moveUp(rowIndex) {
3041
+ if (!this.canMoveUpPerRow()[rowIndex]) {
3042
+ return;
3043
+ }
3044
+ this.sortCriteriaList.update((list) => {
3045
+ const newList = [...list];
3046
+ // Swap with the row above
3047
+ [newList[rowIndex - 1], newList[rowIndex]] = [newList[rowIndex], newList[rowIndex - 1]];
3048
+ return newList;
3049
+ });
3050
+ this._syncMainFieldAndDirection();
2753
3051
  this._onModelChange();
2754
3052
  }
2755
3053
  /**
2756
- * Handle sort field changes.
2757
- * @param field New sorting field.
3054
+ * Move a sort criteria row down (swap with the row below).
3055
+ * @param rowIndex Index of the row to move down.
2758
3056
  */
2759
- _sortFieldChange(field) {
2760
- this.field.set(field);
3057
+ moveDown(rowIndex) {
3058
+ if (!this.canMoveDownPerRow()[rowIndex]) {
3059
+ return;
3060
+ }
3061
+ this.sortCriteriaList.update((list) => {
3062
+ const newList = [...list];
3063
+ // Swap with the row below
3064
+ [newList[rowIndex], newList[rowIndex + 1]] = [newList[rowIndex + 1], newList[rowIndex]];
3065
+ return newList;
3066
+ });
3067
+ this._syncMainFieldAndDirection();
3068
+ this._onModelChange();
3069
+ }
3070
+ /**
3071
+ * Delete (clear) a sort criteria row.
3072
+ * This removes the field selection and shifts remaining criteria up.
3073
+ * @param rowIndex Index of the row to delete.
3074
+ */
3075
+ deleteRow(rowIndex) {
3076
+ if (!this.canDeletePerRow()[rowIndex]) {
3077
+ return;
3078
+ }
3079
+ this.sortCriteriaList.update((list) => {
3080
+ const newList = [...list];
3081
+ // Remove the criteria at this index and add an empty one at the end
3082
+ newList.splice(rowIndex, 1);
3083
+ newList.push({ field: null, direction: INITIAL_DIRECTION });
3084
+ return newList;
3085
+ });
3086
+ this._syncMainFieldAndDirection();
2761
3087
  this._onModelChange();
2762
3088
  }
3089
+ /**
3090
+ * Handle sort direction changes for a specific row.
3091
+ * @param rowIndex Index of the row.
3092
+ * @param direction New sorting direction.
3093
+ */
3094
+ _sortDirectionChangeForRow(rowIndex, direction) {
3095
+ this.sortCriteriaList.update((list) => {
3096
+ const newList = [...list];
3097
+ newList[rowIndex] = { ...newList[rowIndex], direction };
3098
+ return newList;
3099
+ });
3100
+ // Update the main direction if this is the first row (for backward compatibility)
3101
+ if (rowIndex === 0) {
3102
+ this.direction.set(direction);
3103
+ }
3104
+ // Always emit changes for multi-column sorting
3105
+ this._onModelChange();
3106
+ }
3107
+ /**
3108
+ * Handle sort field changes for a specific row.
3109
+ * @param rowIndex Index of the row.
3110
+ * @param column Selected column object or string.
3111
+ */
3112
+ _sortFieldChangeForRow(rowIndex, column) {
3113
+ let fieldKey = null;
3114
+ let shouldUpdate = true;
3115
+ let isInvalid = false;
3116
+ if (typeof column === 'string') {
3117
+ if (column === '') {
3118
+ // Empty string - clear any error state and don't update selection
3119
+ // This can happen when combobox re-renders and emits empty value
3120
+ shouldUpdate = false;
3121
+ isInvalid = false;
3122
+ }
3123
+ else {
3124
+ const matchingColumn = this.columns().find((col) => col.label === column);
3125
+ fieldKey = matchingColumn?.key ?? null;
3126
+ // Check if any column label starts with the typed text (case-insensitive)
3127
+ // This handles the case where user is still typing and autocomplete is showing suggestions
3128
+ const hasPartialMatch = this.columns().some((col) => col.label.toLowerCase().startsWith(column.toLowerCase()));
3129
+ // Mark as invalid only if text doesn't match any column AND no partial matches exist
3130
+ isInvalid = matchingColumn === undefined && !hasPartialMatch;
3131
+ // Only update if we found a matching column
3132
+ shouldUpdate = matchingColumn !== undefined;
3133
+ }
3134
+ }
3135
+ else if (column) {
3136
+ fieldKey = column.key;
3137
+ isInvalid = false;
3138
+ }
3139
+ else {
3140
+ // null/undefined column - don't clear existing selection
3141
+ // This can happen when combobox re-renders
3142
+ shouldUpdate = false;
3143
+ isInvalid = false;
3144
+ }
3145
+ // Update invalid state for this row
3146
+ this._invalidInputPerRow.update((map) => {
3147
+ const newMap = new Map(map);
3148
+ if (isInvalid) {
3149
+ newMap.set(rowIndex, true);
3150
+ }
3151
+ else {
3152
+ newMap.delete(rowIndex);
3153
+ }
3154
+ return newMap;
3155
+ });
3156
+ if (shouldUpdate) {
3157
+ this.sortCriteriaList.update((list) => {
3158
+ const newList = [...list];
3159
+ newList[rowIndex] = { ...newList[rowIndex], field: fieldKey };
3160
+ return newList;
3161
+ });
3162
+ // Update the main field if this is the first row (for backward compatibility)
3163
+ if (rowIndex === 0 && fieldKey !== null) {
3164
+ this.firstSortingField.set(fieldKey);
3165
+ }
3166
+ // Always emit changes for multi-column sorting
3167
+ this._onModelChange();
3168
+ }
3169
+ }
3170
+ /** @hidden */
3171
+ displayColumn(column) {
3172
+ return column?.label ?? '';
3173
+ }
3174
+ /**
3175
+ * Sync the main field and direction signals with the first row's values.
3176
+ * Used after move/delete operations to keep backward compatibility.
3177
+ * @hidden
3178
+ */
3179
+ _syncMainFieldAndDirection() {
3180
+ const firstCriteria = this.sortCriteriaList()[0];
3181
+ if (firstCriteria) {
3182
+ this.firstSortingField.set(firstCriteria.field);
3183
+ this.direction.set(firstCriteria.direction);
3184
+ }
3185
+ }
2763
3186
  /**
2764
3187
  * Emit changes to the model.
2765
3188
  * @hidden
2766
3189
  */
2767
3190
  _onModelChange() {
2768
- this.sortChange.emit({ direction: this.direction(), field: this.field() });
3191
+ // Build array of all sort criteria that have a field selected
3192
+ const sortBy = this.sortCriteriaList()
3193
+ .filter((criteria) => criteria.field !== null)
3194
+ .map((criteria) => ({
3195
+ field: criteria.field,
3196
+ direction: criteria.direction
3197
+ }));
3198
+ this.sortChange.emit({ sortBy });
3199
+ }
3200
+ /**
3201
+ * Sync combobox display text with the current selected column.
3202
+ * This is a DOM side effect needed when reset happens and the combobox has invalid text,
3203
+ * because ngModel won't call writeValue if the underlying model value hasn't changed.
3204
+ * @hidden
3205
+ */
3206
+ _syncComboboxDisplayText() {
3207
+ const comboboxes = this._comboboxes();
3208
+ if (comboboxes.length > 0) {
3209
+ const column = this.selectedColumn();
3210
+ comboboxes[0].writeValue(column);
3211
+ }
2769
3212
  }
2770
3213
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SortingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2771
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: SortingComponent, isStandalone: true, selector: "fdp-sorting", inputs: { sortingData: { classPropertyName: "sortingData", publicName: "sortingData", isSignal: true, isRequired: false, transformFunction: null }, initialSorting: { classPropertyName: "initialSorting", publicName: "initialSorting", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", resetAvailabilityChange: "resetAvailabilityChange" }, ngImport: i0, template: "<fieldset>\n <legend fd-list-group-header>\n <span fd-list-title [attr.id]=\"sortOrderHeaderId\">\n {{ ('platformTable.sortDialogSortOrderHeader' | fdTranslate)() }}\n </span>\n </legend>\n <ul fd-list [selection]=\"true\" [attr.aria-labelledby]=\"sortOrderHeaderId\">\n <li fd-list-item [selected]=\"direction() === SORT_DIRECTION.ASC\">\n <fd-radio-button\n name=\"sort-order\"\n value=\"asc\"\n state=\"default\"\n [ngModel]=\"direction()\"\n (ngModelChange)=\"_sortDirectionChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderAsc' | fdTranslate)() }}</span>\n </li>\n <li fd-list-item [selected]=\"direction() === SORT_DIRECTION.DESC\">\n <fd-radio-button\n name=\"sort-order\"\n value=\"desc\"\n state=\"default\"\n [ngModel]=\"direction()\"\n (ngModelChange)=\"_sortDirectionChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderDesc' | fdTranslate)() }}</span>\n </li>\n </ul>\n</fieldset>\n\n<fieldset>\n <legend fd-list-group-header>\n <span fd-list-title [attr.id]=\"sortDialogSortByHeaderId\">\n {{ ('platformTable.sortDialogSortByHeader' | fdTranslate)() }}\n </span>\n </legend>\n <ul fd-list [selection]=\"true\" [attr.aria-labelledby]=\"sortDialogSortByHeaderId\">\n @if (allowDisablingSorting()) {\n <li fd-list-item [selected]=\"field() === NOT_SORTED_OPTION_VALUE\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"NOT_SORTED_OPTION_VALUE\"\n state=\"default\"\n [ngModel]=\"field()\"\n (ngModelChange)=\"_sortFieldChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.sortDialogNotSortedLabel' | fdTranslate)() }}</span>\n </li>\n }\n @for (column of columns(); track column) {\n <li fd-list-item [selected]=\"column.key === field()\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"column.key\"\n state=\"default\"\n [ngModel]=\"field()\"\n (ngModelChange)=\"_sortFieldChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ column.label }}</span>\n </li>\n }\n </ul>\n</fieldset>\n", dependencies: [{ kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "directive", type: ListGroupHeaderDirective, selector: "[fdListGroupHeader], [fd-list-group-header]", inputs: ["nativeElementId"], outputs: ["keyDown"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "component", type: RadioButtonComponent, selector: "fd-radio-button", inputs: ["ariaLabel", "ariaLabelledBy", "ariaDescribedBy", "title", "tabIndex", "state", "disabled", "readOnly", "selectedValue", "name", "id", "value", "required", "standalone", "wrapLabel", "valignLabel"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
3214
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: SortingComponent, isStandalone: true, selector: "fdp-sorting", inputs: { sortingData: { classPropertyName: "sortingData", publicName: "sortingData", isSignal: true, isRequired: false, transformFunction: null }, initialSorting: { classPropertyName: "initialSorting", publicName: "initialSorting", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", resetAvailabilityChange: "resetAvailabilityChange", validityChange: "validityChange" }, viewQueries: [{ propertyName: "_comboboxes", predicate: ["sortCombobox"], descendants: true, isSignal: true }], ngImport: i0, template: "<fieldset>\n <ul fd-list>\n @for (criteria of sortCriteriaList(); track $index; let rowIndex = $index) {\n @if (rowVisibility()[rowIndex]) {\n <li fd-list-item class=\"fdp-sorting__row\">\n <div class=\"fd-margin-end--sm\">\n <fd-combobox\n #sortCombobox\n [dropdownValues]=\"availableColumnsPerRow()[rowIndex]\"\n [displayFn]=\"displayColumn\"\n [placeholder]=\"('platformTable.sortDialogSortByHeader' | fdTranslate)()\"\n [state]=\"rowStates()[rowIndex]\"\n [ngModel]=\"selectedColumnsPerRow()[rowIndex]\"\n (ngModelChange)=\"_sortFieldChangeForRow(rowIndex, $event)\"\n >\n </fd-combobox>\n </div>\n\n <div class=\"fd-margin-end--sm\">\n <fd-segmented-button\n [name]=\"'sort-order-' + rowIndex\"\n [ngModel]=\"directionsPerRow()[rowIndex]\"\n (ngModelChange)=\"_sortDirectionChangeForRow(rowIndex, $event)\"\n >\n <button\n fd-button\n glyph=\"sort-ascending\"\n [attr.title]=\"('platformTable.sortDialogSortOrderAsc' | fdTranslate)()\"\n value=\"asc\"\n ></button>\n <button\n fd-button\n glyph=\"sort-descending\"\n [attr.title]=\"('platformTable.sortDialogSortOrderDesc' | fdTranslate)()\"\n value=\"desc\"\n ></button>\n </fd-segmented-button>\n </div>\n\n @if (directionsPerRow()[rowIndex] === 'asc') {\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderAsc' | fdTranslate)() }}</span>\n }\n\n @if (directionsPerRow()[rowIndex] === 'desc') {\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderDesc' | fdTranslate)() }}</span>\n }\n\n <span fd-list-secondary class=\"fdp-sorting__actions\">\n <button\n fd-button\n glyph=\"slim-arrow-up\"\n [attr.title]=\"('platformTable.sortDialogMoveUp' | fdTranslate)()\"\n [disabled]=\"!canMoveUpPerRow()[rowIndex]\"\n (click)=\"moveUp(rowIndex)\"\n ></button>\n <button\n fd-button\n glyph=\"slim-arrow-down\"\n [attr.title]=\"('platformTable.sortDialogMoveDown' | fdTranslate)()\"\n [disabled]=\"!canMoveDownPerRow()[rowIndex]\"\n (click)=\"moveDown(rowIndex)\"\n ></button>\n <button\n fd-button\n glyph=\"decline\"\n [attr.title]=\"('platformTable.sortDialogDelete' | fdTranslate)()\"\n [disabled]=\"!canDeletePerRow()[rowIndex]\"\n (click)=\"deleteRow(rowIndex)\"\n ></button>\n </span>\n </li>\n }\n }\n </ul>\n</fieldset>\n", styles: [".fd-margin--tiny{margin-block:.5rem;margin-inline:.5rem}.fd-margin--sm{margin-block:1rem;margin-inline:1rem}.fd-margin--md{margin-block:2rem;margin-inline:2rem}.fd-margin--lg{margin-block:3rem;margin-inline:3rem}.fd-margin--none{margin-block:0;margin-inline:0}.fd-margin-top--tiny{-webkit-margin-before:.5rem;margin-block-start:.5rem}.fd-margin-top--sm{-webkit-margin-before:1rem;margin-block-start:1rem}.fd-margin-top--md{-webkit-margin-before:2rem;margin-block-start:2rem}.fd-margin-top--lg{-webkit-margin-before:3rem;margin-block-start:3rem}.fd-margin-top--none{-webkit-margin-before:0;margin-block-start:0}.fd-margin-end--tiny{-webkit-margin-end:.5rem;margin-inline-end:.5rem}.fd-margin-end--sm{-webkit-margin-end:1rem;margin-inline-end:1rem}.fd-margin-end--md{-webkit-margin-end:2rem;margin-inline-end:2rem}.fd-margin-end--lg{-webkit-margin-end:3rem;margin-inline-end:3rem}.fd-margin-end--none{-webkit-margin-end:0;margin-inline-end:0}.fd-margin-bottom--tiny{-webkit-margin-after:.5rem;margin-block-end:.5rem}.fd-margin-bottom--sm{-webkit-margin-after:1rem;margin-block-end:1rem}.fd-margin-bottom--md{-webkit-margin-after:2rem;margin-block-end:2rem}.fd-margin-bottom--lg{-webkit-margin-after:3rem;margin-block-end:3rem}.fd-margin-bottom--none{-webkit-margin-after:0;margin-block-end:0}.fd-margin-begin--tiny{-webkit-margin-start:.5rem;margin-inline-start:.5rem}.fd-margin-begin--sm{-webkit-margin-start:1rem;margin-inline-start:1rem}.fd-margin-begin--md{-webkit-margin-start:2rem;margin-inline-start:2rem}.fd-margin-begin--lg{-webkit-margin-start:3rem;margin-inline-start:3rem}.fd-margin-begin--none{-webkit-margin-start:0;margin-inline-start:0}.fd-margin-top-bottom--tiny{margin-block:.5rem}.fd-margin-top-bottom--sm{margin-block:1rem}.fd-margin-top-bottom--md{margin-block:2rem}.fd-margin-top-bottom--lg{margin-block:3rem}.fd-margin-begin-end--tiny{margin-inline:.5rem}.fd-margin-begin-end--sm{margin-inline:1rem}.fd-margin-begin-end--md{margin-inline:2rem}.fd-margin-begin-end--lg{margin-inline:3rem}.fd-margin-responsive--sm{margin-block:0 1rem;margin-inline:0}.fd-margin-responsive--md{margin-block:1rem;margin-inline:1rem}.fd-margin-responsive--lg{margin-block:1rem;margin-inline:2rem}.fd-margin-responsive--xl{margin-block:1rem;margin-inline:3rem}.fd-margin-negative-begin-end--tiny{margin-block:0;margin-inline:-.5rem}.fd-margin-negative-begin-end--sm{margin-block:0;margin-inline:-1rem}.fd-margin-negative-begin-end--md{margin-block:0;margin-inline:-2rem}.fd-margin-negative-begin-end--lg{margin-block:0;margin-inline:-3rem}.fdp-sorting__actions{visibility:hidden}.fdp-sorting__row:hover .fdp-sorting__actions,.fdp-sorting__row:focus-within .fdp-sorting__actions{visibility:visible}\n/*! Bundled license information:\n\nfundamental-styles/dist/margins.css:\n (*!\n * Fundamental Library Styles v0.41.8\n * Copyright (c) 2026 SAP SE or an SAP affiliate company.\n * Licensed under Apache License 2.0 (https://github.com/SAP/fundamental-styles/blob/main/LICENSE)\n *)\n*/\n"], dependencies: [{ kind: "component", type: ListComponent$1, selector: "[fd-list], [fdList]", inputs: ["dropdownMode", "multiInputMode", "mobileMode", "hasMessage", "noBorder", "navigationIndicator", "selection", "keyboardSupport", "byline", "subline", "theme", "unreadIndicator", "role", "settingsList", "settingsListFooter", "searchResultsList"], outputs: ["focusEscapeList"] }, { kind: "directive", type: ListTitleDirective, selector: "[fd-list-title], [fdListTitle]", inputs: ["wrap", "truncate", "scope"] }, { kind: "component", type: ListItemComponent, selector: "[fdListItem] ,[fd-list-item]", inputs: ["selected", "noData", "action", "interactive", "growing", "counter", "counterRole", "counterAriaLabel", "active", "unread", "byline", "ariaRole", "id", "preventClick", "settingsListTpl", "suggestion"], outputs: ["keyDown"], exportAs: ["fdListItem"] }, { kind: "directive", type: ListSecondaryDirective, selector: "[fd-list-secondary], [fdListSecondary]", inputs: ["type"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SegmentedButtonComponent, selector: "fd-segmented-button", inputs: ["toggle", "vertical"] }, { kind: "component", type: ButtonComponent, selector: "button[fd-button], a[fd-button], span[fd-button]", inputs: ["id"], exportAs: ["fd-button"] }, { kind: "component", type: ComboboxComponent, selector: "fd-combobox", inputs: ["comboboxId", "inputId", "ariaLabel", "ariaLabelledBy", "required", "dropdownValues", "filterFn", "disabled", "placeholder", "isSearch", "glyph", "glyphFont", "showClearButton", "triggers", "closeOnOutsideClick", "openOnKeyboardEvent", "state", "itemTemplate", "groupFn", "maxHeight", "dropDownMaxWidthPx", "noDropDownMaxWidth", "width", "searchFn", "highlighting", "closeOnSelect", "fillOnSelect", "autoComplete", "fillControlMode", "communicateByObject", "displayFn", "buttonFocusable", "clearButtonFocusable", "readOnly", "mobile", "mobileConfig", "showDropdownButton", "includes", "title", "byline", "tabOutStrategy", "valueProperty"], outputs: ["itemClicked", "openChange", "inputTextChange"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2772
3215
  }
2773
3216
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SortingComponent, decorators: [{
2774
3217
  type: Component,
@@ -2777,11 +3220,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
2777
3220
  ListGroupHeaderDirective,
2778
3221
  ListTitleDirective,
2779
3222
  ListItemComponent,
3223
+ ListSecondaryDirective,
2780
3224
  RadioButtonComponent,
2781
3225
  FormsModule,
2782
- FdTranslatePipe
2783
- ], template: "<fieldset>\n <legend fd-list-group-header>\n <span fd-list-title [attr.id]=\"sortOrderHeaderId\">\n {{ ('platformTable.sortDialogSortOrderHeader' | fdTranslate)() }}\n </span>\n </legend>\n <ul fd-list [selection]=\"true\" [attr.aria-labelledby]=\"sortOrderHeaderId\">\n <li fd-list-item [selected]=\"direction() === SORT_DIRECTION.ASC\">\n <fd-radio-button\n name=\"sort-order\"\n value=\"asc\"\n state=\"default\"\n [ngModel]=\"direction()\"\n (ngModelChange)=\"_sortDirectionChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderAsc' | fdTranslate)() }}</span>\n </li>\n <li fd-list-item [selected]=\"direction() === SORT_DIRECTION.DESC\">\n <fd-radio-button\n name=\"sort-order\"\n value=\"desc\"\n state=\"default\"\n [ngModel]=\"direction()\"\n (ngModelChange)=\"_sortDirectionChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderDesc' | fdTranslate)() }}</span>\n </li>\n </ul>\n</fieldset>\n\n<fieldset>\n <legend fd-list-group-header>\n <span fd-list-title [attr.id]=\"sortDialogSortByHeaderId\">\n {{ ('platformTable.sortDialogSortByHeader' | fdTranslate)() }}\n </span>\n </legend>\n <ul fd-list [selection]=\"true\" [attr.aria-labelledby]=\"sortDialogSortByHeaderId\">\n @if (allowDisablingSorting()) {\n <li fd-list-item [selected]=\"field() === NOT_SORTED_OPTION_VALUE\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"NOT_SORTED_OPTION_VALUE\"\n state=\"default\"\n [ngModel]=\"field()\"\n (ngModelChange)=\"_sortFieldChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ ('platformTable.sortDialogNotSortedLabel' | fdTranslate)() }}</span>\n </li>\n }\n @for (column of columns(); track column) {\n <li fd-list-item [selected]=\"column.key === field()\">\n <fd-radio-button\n name=\"sort-by\"\n [value]=\"column.key\"\n state=\"default\"\n [ngModel]=\"field()\"\n (ngModelChange)=\"_sortFieldChange($event)\"\n ></fd-radio-button>\n <span fd-list-title>{{ column.label }}</span>\n </li>\n }\n </ul>\n</fieldset>\n" }]
2784
- }], propDecorators: { sortingData: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortingData", required: false }] }], initialSorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSorting", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], resetAvailabilityChange: [{ type: i0.Output, args: ["resetAvailabilityChange"] }] } });
3226
+ FdTranslatePipe,
3227
+ SegmentedButtonComponent,
3228
+ ButtonComponent,
3229
+ ComboboxComponent,
3230
+ FormGroupComponent
3231
+ ], template: "<fieldset>\n <ul fd-list>\n @for (criteria of sortCriteriaList(); track $index; let rowIndex = $index) {\n @if (rowVisibility()[rowIndex]) {\n <li fd-list-item class=\"fdp-sorting__row\">\n <div class=\"fd-margin-end--sm\">\n <fd-combobox\n #sortCombobox\n [dropdownValues]=\"availableColumnsPerRow()[rowIndex]\"\n [displayFn]=\"displayColumn\"\n [placeholder]=\"('platformTable.sortDialogSortByHeader' | fdTranslate)()\"\n [state]=\"rowStates()[rowIndex]\"\n [ngModel]=\"selectedColumnsPerRow()[rowIndex]\"\n (ngModelChange)=\"_sortFieldChangeForRow(rowIndex, $event)\"\n >\n </fd-combobox>\n </div>\n\n <div class=\"fd-margin-end--sm\">\n <fd-segmented-button\n [name]=\"'sort-order-' + rowIndex\"\n [ngModel]=\"directionsPerRow()[rowIndex]\"\n (ngModelChange)=\"_sortDirectionChangeForRow(rowIndex, $event)\"\n >\n <button\n fd-button\n glyph=\"sort-ascending\"\n [attr.title]=\"('platformTable.sortDialogSortOrderAsc' | fdTranslate)()\"\n value=\"asc\"\n ></button>\n <button\n fd-button\n glyph=\"sort-descending\"\n [attr.title]=\"('platformTable.sortDialogSortOrderDesc' | fdTranslate)()\"\n value=\"desc\"\n ></button>\n </fd-segmented-button>\n </div>\n\n @if (directionsPerRow()[rowIndex] === 'asc') {\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderAsc' | fdTranslate)() }}</span>\n }\n\n @if (directionsPerRow()[rowIndex] === 'desc') {\n <span fd-list-title>{{ ('platformTable.sortDialogSortOrderDesc' | fdTranslate)() }}</span>\n }\n\n <span fd-list-secondary class=\"fdp-sorting__actions\">\n <button\n fd-button\n glyph=\"slim-arrow-up\"\n [attr.title]=\"('platformTable.sortDialogMoveUp' | fdTranslate)()\"\n [disabled]=\"!canMoveUpPerRow()[rowIndex]\"\n (click)=\"moveUp(rowIndex)\"\n ></button>\n <button\n fd-button\n glyph=\"slim-arrow-down\"\n [attr.title]=\"('platformTable.sortDialogMoveDown' | fdTranslate)()\"\n [disabled]=\"!canMoveDownPerRow()[rowIndex]\"\n (click)=\"moveDown(rowIndex)\"\n ></button>\n <button\n fd-button\n glyph=\"decline\"\n [attr.title]=\"('platformTable.sortDialogDelete' | fdTranslate)()\"\n [disabled]=\"!canDeletePerRow()[rowIndex]\"\n (click)=\"deleteRow(rowIndex)\"\n ></button>\n </span>\n </li>\n }\n }\n </ul>\n</fieldset>\n", styles: [".fd-margin--tiny{margin-block:.5rem;margin-inline:.5rem}.fd-margin--sm{margin-block:1rem;margin-inline:1rem}.fd-margin--md{margin-block:2rem;margin-inline:2rem}.fd-margin--lg{margin-block:3rem;margin-inline:3rem}.fd-margin--none{margin-block:0;margin-inline:0}.fd-margin-top--tiny{-webkit-margin-before:.5rem;margin-block-start:.5rem}.fd-margin-top--sm{-webkit-margin-before:1rem;margin-block-start:1rem}.fd-margin-top--md{-webkit-margin-before:2rem;margin-block-start:2rem}.fd-margin-top--lg{-webkit-margin-before:3rem;margin-block-start:3rem}.fd-margin-top--none{-webkit-margin-before:0;margin-block-start:0}.fd-margin-end--tiny{-webkit-margin-end:.5rem;margin-inline-end:.5rem}.fd-margin-end--sm{-webkit-margin-end:1rem;margin-inline-end:1rem}.fd-margin-end--md{-webkit-margin-end:2rem;margin-inline-end:2rem}.fd-margin-end--lg{-webkit-margin-end:3rem;margin-inline-end:3rem}.fd-margin-end--none{-webkit-margin-end:0;margin-inline-end:0}.fd-margin-bottom--tiny{-webkit-margin-after:.5rem;margin-block-end:.5rem}.fd-margin-bottom--sm{-webkit-margin-after:1rem;margin-block-end:1rem}.fd-margin-bottom--md{-webkit-margin-after:2rem;margin-block-end:2rem}.fd-margin-bottom--lg{-webkit-margin-after:3rem;margin-block-end:3rem}.fd-margin-bottom--none{-webkit-margin-after:0;margin-block-end:0}.fd-margin-begin--tiny{-webkit-margin-start:.5rem;margin-inline-start:.5rem}.fd-margin-begin--sm{-webkit-margin-start:1rem;margin-inline-start:1rem}.fd-margin-begin--md{-webkit-margin-start:2rem;margin-inline-start:2rem}.fd-margin-begin--lg{-webkit-margin-start:3rem;margin-inline-start:3rem}.fd-margin-begin--none{-webkit-margin-start:0;margin-inline-start:0}.fd-margin-top-bottom--tiny{margin-block:.5rem}.fd-margin-top-bottom--sm{margin-block:1rem}.fd-margin-top-bottom--md{margin-block:2rem}.fd-margin-top-bottom--lg{margin-block:3rem}.fd-margin-begin-end--tiny{margin-inline:.5rem}.fd-margin-begin-end--sm{margin-inline:1rem}.fd-margin-begin-end--md{margin-inline:2rem}.fd-margin-begin-end--lg{margin-inline:3rem}.fd-margin-responsive--sm{margin-block:0 1rem;margin-inline:0}.fd-margin-responsive--md{margin-block:1rem;margin-inline:1rem}.fd-margin-responsive--lg{margin-block:1rem;margin-inline:2rem}.fd-margin-responsive--xl{margin-block:1rem;margin-inline:3rem}.fd-margin-negative-begin-end--tiny{margin-block:0;margin-inline:-.5rem}.fd-margin-negative-begin-end--sm{margin-block:0;margin-inline:-1rem}.fd-margin-negative-begin-end--md{margin-block:0;margin-inline:-2rem}.fd-margin-negative-begin-end--lg{margin-block:0;margin-inline:-3rem}.fdp-sorting__actions{visibility:hidden}.fdp-sorting__row:hover .fdp-sorting__actions,.fdp-sorting__row:focus-within .fdp-sorting__actions{visibility:visible}\n/*! Bundled license information:\n\nfundamental-styles/dist/margins.css:\n (*!\n * Fundamental Library Styles v0.41.8\n * Copyright (c) 2026 SAP SE or an SAP affiliate company.\n * Licensed under Apache License 2.0 (https://github.com/SAP/fundamental-styles/blob/main/LICENSE)\n *)\n*/\n"] }]
3232
+ }], ctorParameters: () => [], propDecorators: { sortingData: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortingData", required: false }] }], initialSorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSorting", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], resetAvailabilityChange: [{ type: i0.Output, args: ["resetAvailabilityChange"] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], _comboboxes: [{ type: i0.ViewChildren, args: ['sortCombobox', { isSignal: true }] }] } });
2785
3233
 
2786
3234
  const INITIAL_SEARCH_TEXT = '';
2787
3235
  const INITIAL_SHOW_ALL_ITEMS = true;
@@ -3045,6 +3493,9 @@ class SettingsDialogComponent {
3045
3493
  /** Signal to track reset availability */
3046
3494
  this.isResetAvailable$ = signal(false, /* @ts-ignore */
3047
3495
  ...(ngDevMode ? [{ debugName: "isResetAvailable$" }] : /* istanbul ignore next */ []));
3496
+ /** Signal to track if the dialog is valid (OK button can be clicked) */
3497
+ this.isDialogValid = signal(true, /* @ts-ignore */
3498
+ ...(ngDevMode ? [{ debugName: "isDialogValid" }] : /* istanbul ignore next */ []));
3048
3499
  /** @hidden Initial sorting configuration */
3049
3500
  this._initialSorting = signal(null, /* @ts-ignore */
3050
3501
  ...(ngDevMode ? [{ debugName: "_initialSorting" }] : /* istanbul ignore next */ []));
@@ -3089,8 +3540,11 @@ class SettingsDialogComponent {
3089
3540
  const columnsData = this._pendingColumnsChanges
3090
3541
  ? { columns: this._pendingColumnsChanges.columns }
3091
3542
  : this.columnsData();
3543
+ // Build sorting result directly from sortingData signal
3544
+ const sortingData = this.sortingData();
3545
+ const sortingResult = sortingData ? { sortBy: sortingData.sortBy ?? [] } : null;
3092
3546
  this.dialogRef.close({
3093
- sortingData: this.sortingData(),
3547
+ sortingData: sortingResult,
3094
3548
  filteringData: this.filteringData(),
3095
3549
  groupingData: this.groupingData(),
3096
3550
  columnsData
@@ -3107,10 +3561,16 @@ class SettingsDialogComponent {
3107
3561
  */
3108
3562
  reset() {
3109
3563
  if (this.activeTab() === ActiveTab.SORT && this.sortingData()) {
3564
+ const current = this.sortingData();
3565
+ const initial = this._initialSorting();
3566
+ // Reset sortBy to initial sorting (if any)
3567
+ const initialSortBy = initial.field !== NOT_SORTED_OPTION_VALUE
3568
+ ? [{ field: initial.field, direction: initial.direction }]
3569
+ : [];
3110
3570
  this.sortingData.set({
3111
- ...this.sortingData(),
3112
- field: this._initialSorting().field,
3113
- direction: this._initialSorting().direction
3571
+ columns: current.columns,
3572
+ allowDisablingSorting: current.allowDisablingSorting,
3573
+ sortBy: initialSortBy
3114
3574
  });
3115
3575
  }
3116
3576
  if (this.activeTab() === ActiveTab.FILTER && this.filteringData()) {
@@ -3144,12 +3604,19 @@ class SettingsDialogComponent {
3144
3604
  * @param event Updated sorting data.
3145
3605
  */
3146
3606
  onSortChange(event) {
3607
+ // Update sortingData with new sortBy
3147
3608
  this.sortingData.set({
3148
3609
  ...this.sortingData(),
3149
- field: event.field,
3150
- direction: event.direction
3610
+ sortBy: event.sortBy ?? []
3151
3611
  });
3152
3612
  }
3613
+ /**
3614
+ * Handle sort validity change event.
3615
+ * @param isValid Whether the sorting configuration is valid.
3616
+ */
3617
+ onSortValidityChange(isValid) {
3618
+ this.isDialogValid.set(isValid);
3619
+ }
3153
3620
  /**
3154
3621
  * Handle filter change event and update filtering data.
3155
3622
  * @param event Updated filtering data.
@@ -3271,7 +3738,9 @@ class SettingsDialogComponent {
3271
3738
  * Set initial sorting configuration from the table's state.
3272
3739
  */
3273
3740
  _setInitialSorting() {
3274
- const initialSorting = (this._table.initialState?.initialSortBy || [])[0];
3741
+ // Use snapshot which preserves the original initial state
3742
+ // even if initialSortBy input is dynamically updated
3743
+ const initialSorting = (this._table.initialState?.getInitialSortBySnapshot() || [])[0];
3275
3744
  this._initialSorting.set({
3276
3745
  field: initialSorting?.field ?? NOT_SORTED_OPTION_VALUE,
3277
3746
  direction: initialSorting?.direction ?? INITIAL_DIRECTION
@@ -3281,13 +3750,15 @@ class SettingsDialogComponent {
3281
3750
  * Set initial filter configuration from the table's state.
3282
3751
  */
3283
3752
  _setInitialFilters() {
3284
- this._initialFilters.set(this._table.initialState?.initialFilterBy ?? []);
3753
+ // Use snapshot which preserves the original initial state
3754
+ this._initialFilters.set(this._table.initialState?.getInitialFilterBySnapshot() ?? []);
3285
3755
  }
3286
3756
  /**
3287
3757
  * Set initial grouping configuration from the table's state.
3288
3758
  */
3289
3759
  _setInitialGrouping() {
3290
- const initialGrouping = (this._table.initialState?.initialGroupBy || [])[0];
3760
+ // Use snapshot which preserves the original initial state
3761
+ const initialGrouping = (this._table.initialState?.getInitialGroupBySnapshot() || [])[0];
3291
3762
  this._initialGrouping.set({
3292
3763
  field: initialGrouping?.field ?? NOT_GROUPED_OPTION_VALUE,
3293
3764
  direction: initialGrouping?.direction ?? INITIAL_DIRECTION
@@ -3314,7 +3785,7 @@ class SettingsDialogComponent {
3314
3785
  });
3315
3786
  }
3316
3787
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SettingsDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: i1.Table }], target: i0.ɵɵFactoryTarget.Component }); }
3317
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: SettingsDialogComponent, isStandalone: true, selector: "fdp-settings-dialog-settings", providers: [{ provide: RESETTABLE_TOKEN, useExisting: forwardRef(() => SettingsDialogComponent) }], ngImport: i0, template: "<fd-dialog>\n <fd-dialog-header>\n <ng-template fdkTemplate=\"header\">\n <div fd-bar-left>\n @if (activeTab() !== 'filter') {\n <fd-bar-element>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.settingsDialogHeader' | fdTranslate)()\n }}</span>\n </fd-bar-element>\n } @else {\n <fd-bar-element>\n @if (activeFilterStepView()?.titleTemplateRef) {\n <ng-container\n [ngTemplateOutlet]=\"activeFilterStepView()?.titleTemplateRef ?? null\"\n ></ng-container>\n }\n </fd-bar-element>\n }\n </div>\n <div fd-bar-right>\n <fd-bar-element>\n <fdp-table-reset-button></fdp-table-reset-button>\n </fd-bar-element>\n </div>\n </ng-template>\n </fd-dialog-header>\n\n <fd-dialog-body disablePaddings>\n @if (showSubheader()) {\n <fdp-icon-tab-bar layoutMode=\"row\" iconTabSize=\"sm\" (iconTabSelected)=\"onTabSelected($event)\">\n @if (columnsData() && showColumns) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionColumnsButtonTitle' | fdTranslate)()\">\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n </fdp-icon-tab-bar-tab>\n }\n @if (sortingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionSortButtonTitle' | fdTranslate)()\">\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n </fdp-icon-tab-bar-tab>\n }\n @if (filteringData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionFilterButtonTitle' | fdTranslate)()\">\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n </fdp-icon-tab-bar-tab>\n }\n @if (groupingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionGroupButtonTitle' | fdTranslate)()\">\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n </fdp-icon-tab-bar-tab>\n }\n </fdp-icon-tab-bar>\n } @else {\n @if (columnsData() && showColumns) {\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n }\n @if (sortingData()) {\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n }\n @if (filteringData()) {\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n }\n @if (groupingData()) {\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n }\n }\n </fd-dialog-body>\n\n <fd-dialog-footer>\n <fd-button-bar\n fdType=\"emphasized\"\n [label]=\"('platformTable.confirmBtnLabel' | fdTranslate)()\"\n (click)=\"confirm()\"\n ></fd-button-bar>\n <fd-button-bar\n [label]=\"('platformTable.cancelBtnLabel' | fdTranslate)()\"\n fdkInitialFocus\n (click)=\"cancel()\"\n ></fd-button-bar>\n </fd-dialog-footer>\n</fd-dialog>\n", dependencies: [{ kind: "component", type: DialogComponent, selector: "fd-dialog", inputs: ["class", "dialogRef", "dialogConfig"] }, { kind: "component", type: DialogHeaderComponent, selector: "fd-dialog-header", inputs: ["inShellbar"] }, { kind: "directive", type: BarLeftDirective, selector: "[fd-bar-left]", inputs: ["stackContentsVertically"] }, { kind: "directive", type: BarElementDirective, selector: "fd-bar-element", inputs: ["fullWidth"] }, { kind: "directive", type: BarRightDirective, selector: "[fd-bar-right]", inputs: ["stackContentsVertically"] }, { kind: "component", type: ResetButtonComponent, selector: "fdp-table-reset-button" }, { kind: "component", type: DialogBodyComponent, selector: "fd-dialog-body", inputs: ["disablePaddings"] }, { kind: "component", type: DialogFooterComponent, selector: "fd-dialog-footer" }, { kind: "component", type: SortingComponent, selector: "fdp-sorting", inputs: ["sortingData", "initialSorting"], outputs: ["sortChange", "resetAvailabilityChange"] }, { kind: "component", type: FiltersComponent, selector: "fdp-filters", inputs: ["filteringData", "headingLevel", "initialFilters"], outputs: ["activeFilterStepViewChange", "filterChange", "resetAvailabilityChange"] }, { kind: "component", type: GroupingComponent, selector: "fdp-grouping", inputs: ["groupingData", "initialGrouping"], outputs: ["groupChange", "resetAvailabilityChange"] }, { kind: "component", type: ColumnsComponent, selector: "fdp-columns", inputs: ["columnsData", "initialColumns"], outputs: ["columnsChange", "resetAvailabilityChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TemplateDirective, selector: "[fdkTemplate]", inputs: ["fdkTemplate"] }, { kind: "component", type: TitleComponent, selector: "[fd-title], [fdTitle]", inputs: ["twoLineClamp", "headerSize", "wrap"], exportAs: ["fd-title"] }, { kind: "component", type: ButtonBarComponent, selector: "fd-button-bar", inputs: ["fullWidth", "fdType", "title", "ariaLabelledby", "id"] }, { kind: "directive", type: InitialFocusDirective, selector: "[fdkInitialFocus]", inputs: ["fdkInitialFocus", "enabled", "focusLastElement"] }, { kind: "component", type: IconTabBarComponent, selector: "fdp-icon-tab-bar", inputs: ["stackContent", "tabHeadingLevel", "iconTabType", "tabsConfig", "densityMode", "iconTabFont", "enableTabReordering", "showTotalTab", "multiClick", "layoutMode", "iconTabBackground", "iconTabSize", "colorAssociations", "settings", "maxContentHeight"], outputs: ["tabsConfigChange", "densityModeChange", "iconTabSelected", "iconTabReordered", "closeTab"] }, { kind: "component", type: IconTabBarTabComponent, selector: "fdp-icon-tab-bar-tab", inputs: ["label", "color", "icon", "iconFont", "counter", "active", "badge", "closable", "id"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3788
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: SettingsDialogComponent, isStandalone: true, selector: "fdp-settings-dialog-settings", providers: [{ provide: RESETTABLE_TOKEN, useExisting: forwardRef(() => SettingsDialogComponent) }], ngImport: i0, template: "<fd-dialog>\n <fd-dialog-header>\n <ng-template fdkTemplate=\"header\">\n <div fd-bar-left>\n @if (activeTab() !== 'filter') {\n <fd-bar-element>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.settingsDialogHeader' | fdTranslate)()\n }}</span>\n </fd-bar-element>\n } @else {\n <fd-bar-element>\n @if (activeFilterStepView()?.titleTemplateRef) {\n <ng-container\n [ngTemplateOutlet]=\"activeFilterStepView()?.titleTemplateRef ?? null\"\n ></ng-container>\n }\n </fd-bar-element>\n }\n </div>\n <div fd-bar-right>\n <fd-bar-element>\n <fdp-table-reset-button></fdp-table-reset-button>\n </fd-bar-element>\n </div>\n </ng-template>\n </fd-dialog-header>\n\n <fd-dialog-body disablePaddings>\n @if (showSubheader()) {\n <fdp-icon-tab-bar layoutMode=\"row\" iconTabSize=\"sm\" (iconTabSelected)=\"onTabSelected($event)\">\n @if (columnsData() && showColumns) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionColumnsButtonTitle' | fdTranslate)()\">\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n </fdp-icon-tab-bar-tab>\n }\n @if (sortingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionSortButtonTitle' | fdTranslate)()\">\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (validityChange)=\"onSortValidityChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n </fdp-icon-tab-bar-tab>\n }\n @if (filteringData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionFilterButtonTitle' | fdTranslate)()\">\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n </fdp-icon-tab-bar-tab>\n }\n @if (groupingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionGroupButtonTitle' | fdTranslate)()\">\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n </fdp-icon-tab-bar-tab>\n }\n </fdp-icon-tab-bar>\n } @else {\n @if (columnsData() && showColumns) {\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n }\n @if (sortingData()) {\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (validityChange)=\"onSortValidityChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n }\n @if (filteringData()) {\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n }\n @if (groupingData()) {\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n }\n }\n </fd-dialog-body>\n\n <fd-dialog-footer>\n <fd-button-bar\n fdType=\"emphasized\"\n [label]=\"('platformTable.confirmBtnLabel' | fdTranslate)()\"\n [disabled]=\"!isDialogValid()\"\n (click)=\"confirm()\"\n ></fd-button-bar>\n <fd-button-bar\n [label]=\"('platformTable.cancelBtnLabel' | fdTranslate)()\"\n fdkInitialFocus\n (click)=\"cancel()\"\n ></fd-button-bar>\n </fd-dialog-footer>\n</fd-dialog>\n", dependencies: [{ kind: "component", type: DialogComponent, selector: "fd-dialog", inputs: ["class", "dialogRef", "dialogConfig"] }, { kind: "component", type: DialogHeaderComponent, selector: "fd-dialog-header", inputs: ["inShellbar"] }, { kind: "directive", type: BarLeftDirective, selector: "[fd-bar-left]", inputs: ["stackContentsVertically"] }, { kind: "directive", type: BarElementDirective, selector: "fd-bar-element", inputs: ["fullWidth"] }, { kind: "directive", type: BarRightDirective, selector: "[fd-bar-right]", inputs: ["stackContentsVertically"] }, { kind: "component", type: ResetButtonComponent, selector: "fdp-table-reset-button" }, { kind: "component", type: DialogBodyComponent, selector: "fd-dialog-body", inputs: ["disablePaddings"] }, { kind: "component", type: DialogFooterComponent, selector: "fd-dialog-footer" }, { kind: "component", type: SortingComponent, selector: "fdp-sorting", inputs: ["sortingData", "initialSorting"], outputs: ["sortChange", "resetAvailabilityChange", "validityChange"] }, { kind: "component", type: FiltersComponent, selector: "fdp-filters", inputs: ["filteringData", "headingLevel", "initialFilters"], outputs: ["activeFilterStepViewChange", "filterChange", "resetAvailabilityChange"] }, { kind: "component", type: GroupingComponent, selector: "fdp-grouping", inputs: ["groupingData", "initialGrouping"], outputs: ["groupChange", "resetAvailabilityChange"] }, { kind: "component", type: ColumnsComponent, selector: "fdp-columns", inputs: ["columnsData", "initialColumns"], outputs: ["columnsChange", "resetAvailabilityChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TemplateDirective, selector: "[fdkTemplate]", inputs: ["fdkTemplate"] }, { kind: "component", type: TitleComponent, selector: "[fd-title], [fdTitle]", inputs: ["twoLineClamp", "headerSize", "wrap"], exportAs: ["fd-title"] }, { kind: "component", type: ButtonBarComponent, selector: "fd-button-bar", inputs: ["fullWidth", "fdType", "title", "ariaLabelledby", "id"] }, { kind: "directive", type: InitialFocusDirective, selector: "[fdkInitialFocus]", inputs: ["fdkInitialFocus", "enabled", "focusLastElement"] }, { kind: "component", type: IconTabBarComponent, selector: "fdp-icon-tab-bar", inputs: ["stackContent", "tabHeadingLevel", "iconTabType", "tabsConfig", "densityMode", "iconTabFont", "enableTabReordering", "showTotalTab", "multiClick", "layoutMode", "iconTabBackground", "iconTabSize", "colorAssociations", "settings", "maxContentHeight"], outputs: ["tabsConfigChange", "densityModeChange", "iconTabSelected", "iconTabReordered", "closeTab"] }, { kind: "component", type: IconTabBarTabComponent, selector: "fdp-icon-tab-bar-tab", inputs: ["label", "color", "icon", "iconFont", "counter", "active", "badge", "closable", "id"] }, { kind: "pipe", type: FdTranslatePipe, name: "fdTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3318
3789
  }
3319
3790
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SettingsDialogComponent, decorators: [{
3320
3791
  type: Component,
@@ -3340,13 +3811,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
3340
3811
  InitialFocusDirective,
3341
3812
  IconTabBarComponent,
3342
3813
  IconTabBarTabComponent
3343
- ], template: "<fd-dialog>\n <fd-dialog-header>\n <ng-template fdkTemplate=\"header\">\n <div fd-bar-left>\n @if (activeTab() !== 'filter') {\n <fd-bar-element>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.settingsDialogHeader' | fdTranslate)()\n }}</span>\n </fd-bar-element>\n } @else {\n <fd-bar-element>\n @if (activeFilterStepView()?.titleTemplateRef) {\n <ng-container\n [ngTemplateOutlet]=\"activeFilterStepView()?.titleTemplateRef ?? null\"\n ></ng-container>\n }\n </fd-bar-element>\n }\n </div>\n <div fd-bar-right>\n <fd-bar-element>\n <fdp-table-reset-button></fdp-table-reset-button>\n </fd-bar-element>\n </div>\n </ng-template>\n </fd-dialog-header>\n\n <fd-dialog-body disablePaddings>\n @if (showSubheader()) {\n <fdp-icon-tab-bar layoutMode=\"row\" iconTabSize=\"sm\" (iconTabSelected)=\"onTabSelected($event)\">\n @if (columnsData() && showColumns) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionColumnsButtonTitle' | fdTranslate)()\">\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n </fdp-icon-tab-bar-tab>\n }\n @if (sortingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionSortButtonTitle' | fdTranslate)()\">\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n </fdp-icon-tab-bar-tab>\n }\n @if (filteringData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionFilterButtonTitle' | fdTranslate)()\">\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n </fdp-icon-tab-bar-tab>\n }\n @if (groupingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionGroupButtonTitle' | fdTranslate)()\">\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n </fdp-icon-tab-bar-tab>\n }\n </fdp-icon-tab-bar>\n } @else {\n @if (columnsData() && showColumns) {\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n }\n @if (sortingData()) {\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n }\n @if (filteringData()) {\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n }\n @if (groupingData()) {\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n }\n }\n </fd-dialog-body>\n\n <fd-dialog-footer>\n <fd-button-bar\n fdType=\"emphasized\"\n [label]=\"('platformTable.confirmBtnLabel' | fdTranslate)()\"\n (click)=\"confirm()\"\n ></fd-button-bar>\n <fd-button-bar\n [label]=\"('platformTable.cancelBtnLabel' | fdTranslate)()\"\n fdkInitialFocus\n (click)=\"cancel()\"\n ></fd-button-bar>\n </fd-dialog-footer>\n</fd-dialog>\n" }]
3814
+ ], template: "<fd-dialog>\n <fd-dialog-header>\n <ng-template fdkTemplate=\"header\">\n <div fd-bar-left>\n @if (activeTab() !== 'filter') {\n <fd-bar-element>\n <span role=\"heading\" [attr.aria-level]=\"headingLevel\" fd-title [headerSize]=\"4\">{{\n ('platformTable.settingsDialogHeader' | fdTranslate)()\n }}</span>\n </fd-bar-element>\n } @else {\n <fd-bar-element>\n @if (activeFilterStepView()?.titleTemplateRef) {\n <ng-container\n [ngTemplateOutlet]=\"activeFilterStepView()?.titleTemplateRef ?? null\"\n ></ng-container>\n }\n </fd-bar-element>\n }\n </div>\n <div fd-bar-right>\n <fd-bar-element>\n <fdp-table-reset-button></fdp-table-reset-button>\n </fd-bar-element>\n </div>\n </ng-template>\n </fd-dialog-header>\n\n <fd-dialog-body disablePaddings>\n @if (showSubheader()) {\n <fdp-icon-tab-bar layoutMode=\"row\" iconTabSize=\"sm\" (iconTabSelected)=\"onTabSelected($event)\">\n @if (columnsData() && showColumns) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionColumnsButtonTitle' | fdTranslate)()\">\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n </fdp-icon-tab-bar-tab>\n }\n @if (sortingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionSortButtonTitle' | fdTranslate)()\">\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (validityChange)=\"onSortValidityChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n </fdp-icon-tab-bar-tab>\n }\n @if (filteringData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionFilterButtonTitle' | fdTranslate)()\">\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n </fdp-icon-tab-bar-tab>\n }\n @if (groupingData()) {\n <fdp-icon-tab-bar-tab [label]=\"('platformTable.toolbarActionGroupButtonTitle' | fdTranslate)()\">\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n </fdp-icon-tab-bar-tab>\n }\n </fdp-icon-tab-bar>\n } @else {\n @if (columnsData() && showColumns) {\n <fdp-columns\n [columnsData]=\"columnsData()!\"\n [initialColumns]=\"_initialColumns()\"\n (columnsChange)=\"onColumnsChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.COLUMNS, $event)\"\n ></fdp-columns>\n }\n @if (sortingData()) {\n <fdp-sorting\n [sortingData]=\"sortingData()!\"\n [initialSorting]=\"_initialSorting()\"\n (sortChange)=\"onSortChange($event)\"\n (validityChange)=\"onSortValidityChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.SORT, $event)\"\n ></fdp-sorting>\n }\n @if (filteringData()) {\n <fdp-filters\n [headingLevel]=\"headingLevel\"\n [filteringData]=\"filteringData()!\"\n [initialFilters]=\"_initialFilters()\"\n (activeFilterStepViewChange)=\"onActiveFilterStepViewChange($event)\"\n (filterChange)=\"onFilterChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.FILTER, $event)\"\n ></fdp-filters>\n }\n @if (groupingData()) {\n <fdp-grouping\n [groupingData]=\"groupingData()!\"\n [initialGrouping]=\"_initialGrouping()\"\n (groupChange)=\"onGroupChange($event)\"\n (resetAvailabilityChange)=\"updateResetAvailability(ActiveTab.GROUP, $event)\"\n ></fdp-grouping>\n }\n }\n </fd-dialog-body>\n\n <fd-dialog-footer>\n <fd-button-bar\n fdType=\"emphasized\"\n [label]=\"('platformTable.confirmBtnLabel' | fdTranslate)()\"\n [disabled]=\"!isDialogValid()\"\n (click)=\"confirm()\"\n ></fd-button-bar>\n <fd-button-bar\n [label]=\"('platformTable.cancelBtnLabel' | fdTranslate)()\"\n fdkInitialFocus\n (click)=\"cancel()\"\n ></fd-button-bar>\n </fd-dialog-footer>\n</fd-dialog>\n" }]
3344
3815
  }], ctorParameters: () => [{ type: i1$1.DialogRef }, { type: i1.Table }] });
3345
3816
 
3346
3817
  const dialogConfig = {
3347
3818
  responsivePadding: false,
3348
3819
  verticalPadding: false,
3349
- width: 'auto'
3820
+ width: '40rem',
3821
+ height: '80%'
3350
3822
  };
3351
3823
  /**
3352
3824
  * View settings dialog component.
@@ -3397,9 +3869,9 @@ class TableViewSettingsDialogComponent {
3397
3869
  const columns = this._getTableColumns();
3398
3870
  const sortData = {
3399
3871
  columns: columns.filter(({ sortable }) => sortable),
3400
- direction: state.sortBy?.[0]?.direction,
3401
- field: state.sortBy?.[0]?.field,
3402
- allowDisablingSorting: this.allowDisablingSorting
3872
+ allowDisablingSorting: this.allowDisablingSorting,
3873
+ // Filter out any criteria with null fields
3874
+ sortBy: (state.sortBy ?? []).filter((s) => s.field !== null)
3403
3875
  };
3404
3876
  const filterData = {
3405
3877
  columns,
@@ -3481,7 +3953,7 @@ class TableViewSettingsDialogComponent {
3481
3953
  .pipe(filter((result) => !!result), takeUntilDestroyed(this.destroyRef))
3482
3954
  .subscribe(({ sortingData, filteringData, groupingData, columnsData }) => {
3483
3955
  if (sortingData) {
3484
- this._applySorting(sortingData.field, sortingData.direction);
3956
+ this._applySorting(sortingData);
3485
3957
  }
3486
3958
  if (filteringData) {
3487
3959
  this._applyFiltering(filteringData.filterBy);
@@ -3537,8 +4009,9 @@ class TableViewSettingsDialogComponent {
3537
4009
  return this._table?.getTableColumns() || [];
3538
4010
  }
3539
4011
  /** @hidden */
3540
- _applySorting(field, direction) {
3541
- this._table?.sort(field ? [{ field, direction }] : []);
4012
+ _applySorting(sortingData) {
4013
+ const sortRules = sortingData.sortBy ?? [];
4014
+ this._table?.sort(sortRules);
3542
4015
  }
3543
4016
  /** @hidden */
3544
4017
  _applyFiltering(filters) {