@porscheinformatik/clr-addons 19.9.13 → 19.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/fesm2022/clr-addons.mjs +1201 -634
  2. package/fesm2022/clr-addons.mjs.map +1 -1
  3. package/package.json +1 -1
  4. package/styles/clr-addons-phs.css +118 -4
  5. package/styles/clr-addons-phs.css.map +1 -1
  6. package/styles/clr-addons-phs.min.css +1 -1
  7. package/styles/clr-addons-phs.min.css.map +1 -1
  8. package/treetable/built-in/filter/treetable-string-filter.d.ts +24 -0
  9. package/treetable/enums/selection-type.d.ts +5 -0
  10. package/treetable/index.d.ts +5 -0
  11. package/treetable/interfaces/filter-model.d.ts +37 -0
  12. package/treetable/interfaces/treetable-model.d.ts +55 -0
  13. package/treetable/interfaces/treetable-state-model.d.ts +20 -0
  14. package/treetable/providers/filters.d.ts +29 -0
  15. package/treetable/providers/index.d.ts +1 -2
  16. package/treetable/providers/sort.d.ts +15 -14
  17. package/treetable/providers/treetable-data-state.service.d.ts +37 -0
  18. package/treetable/providers/treetable-recursion.service.d.ts +17 -0
  19. package/treetable/renderer/main-renderer.d.ts +2 -2
  20. package/treetable/treetable-action-overflow.d.ts +4 -7
  21. package/treetable/treetable-column.d.ts +11 -16
  22. package/treetable/treetable-filter.d.ts +18 -0
  23. package/treetable/treetable-items.d.ts +21 -14
  24. package/treetable/treetable-recursive-rows.d.ts +12 -0
  25. package/treetable/treetable-row-checkbox.d.ts +10 -0
  26. package/treetable/treetable-row.d.ts +23 -30
  27. package/treetable/treetable.d.ts +23 -28
  28. package/treetable/treetable.module.d.ts +9 -4
  29. package/treetable/util/treetable-filter-util.d.ts +22 -0
  30. package/treetable/util/treetable-state-util.d.ts +10 -0
  31. package/treetable/providers/items.d.ts +0 -21
  32. package/treetable/providers/selection.d.ts +0 -28
@@ -1,18 +1,18 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, NgModule, Injectable, EventEmitter, Input, Output, Directive, ViewChild, ContentChildren, TemplateRef, ViewChildren, HostBinding, ElementRef, Renderer2, forwardRef, Inject, ContentChild, Optional, inject, ChangeDetectorRef, output, ChangeDetectionStrategy, DestroyRef, signal, input, IterableDiffers, ViewContainerRef, effect, InjectionToken, isSignal, HostListener, LOCALE_ID, Self, computed } from '@angular/core';
2
+ import { Component, NgModule, Injectable, EventEmitter, Output, Input, Directive, ViewChild, ContentChildren, TemplateRef, ViewChildren, HostBinding, ElementRef, Renderer2, forwardRef, Inject, ContentChild, Optional, input, ChangeDetectionStrategy, signal, computed, SkipSelf, inject, model, contentChild, linkedSignal, DestroyRef, contentChildren, effect, output, viewChild, InjectionToken, isSignal, HostListener, LOCALE_ID, Self } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { CommonModule, DOCUMENT, NgForOf, NgComponentOutlet, NgTemplateOutlet, getLocaleDateFormat, FormatWidth, NgClass } from '@angular/common';
5
- import { ClarityIcons, arrowIcon, angleIcon, timesIcon, trashIcon, plusCircleIcon, exclamationCircleIcon, searchIcon, ellipsisVerticalIcon, pencilIcon, historyIcon as historyIcon$1, treeViewIcon, organizationIcon, calendarIcon, checkCircleIcon, windowCloseIcon, exclamationTriangleIcon } from '@cds/core/icon';
4
+ import { CommonModule, DOCUMENT, NgComponentOutlet, NgTemplateOutlet, getLocaleDateFormat, FormatWidth, NgForOf, NgClass } from '@angular/common';
5
+ import { ClarityIcons, arrowIcon, angleIcon, timesIcon, trashIcon, plusCircleIcon, exclamationCircleIcon, searchIcon, ellipsisVerticalIcon, filterGridCircleIcon, filterGridIcon, pencilIcon, historyIcon as historyIcon$1, treeViewIcon, organizationIcon, calendarIcon, checkCircleIcon, windowCloseIcon, exclamationTriangleIcon } from '@cds/core/icon';
6
6
  import * as i2 from '@clr/angular';
7
- import { ClarityModule, ClrFormsModule, ClrDropdown, ClrForm, ClrAlert, ClrAxis, ClrSide, ClrAlignment, ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService, ClrIconModule, ClrDropdownModule, ClrDatagrid, ClrDatagridColumn, ClrDatagridSortOrder, DatagridPropertyComparator, ClrDatagridPagination, ClrDatagridFilter, ClrDateContainer, ClrLabel, ClrControlHelper, ClrControlError, ClrControlSuccess, ClrDatepickerModule } from '@clr/angular';
7
+ import { ClarityModule, ClrFormsModule, ClrDropdown, ClrForm, ClrAlert, ClrAlignment, ClrSide, ClrAxis, ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService, ClrPopoverHostDirective, ClrCommonStringsService, ClrIconModule, ClrDropdownModule, ClrDatagrid, ClrDatagridColumn, ClrDatagridSortOrder, DatagridPropertyComparator, ClrDatagridPagination, ClrDatagridFilter, ClrDateContainer, ClrLabel, ClrControlHelper, ClrControlError, ClrControlSuccess, ClrDatepickerModule } from '@clr/angular';
8
8
  import * as i3$1 from '@angular/forms';
9
9
  import { FormsModule, NG_VALIDATORS, NgControl, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormControl, NgModel } from '@angular/forms';
10
- import { Subject, BehaviorSubject, timer as timer$1, asyncScheduler, interval, debounceTime, fromEvent, of, tap, switchMap, filter as filter$1, ReplaySubject, takeUntil as takeUntil$1, delay } from 'rxjs';
11
- import { takeUntil, take, observeOn, debounceTime as debounceTime$1, filter as filter$2 } from 'rxjs/operators';
10
+ import { Subject, BehaviorSubject, timer as timer$1, asyncScheduler, interval, map as map$1, distinctUntilChanged, shareReplay, combineLatest, skip, auditTime, fromEvent, take as take$1, merge, debounceTime as debounceTime$1, tap, of, switchMap, filter as filter$2, ReplaySubject, takeUntil as takeUntil$1, delay } from 'rxjs';
11
+ import { takeUntil, take, observeOn, filter as filter$1, debounceTime } from 'rxjs/operators';
12
12
  import * as i3 from '@angular/router';
13
13
  import { RouterModule } from '@angular/router';
14
14
  import { trigger, transition, style, animate, state } from '@angular/animations';
15
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
+ import { takeUntilDestroyed, toObservable, outputFromObservable, toSignal } from '@angular/core/rxjs-interop';
16
16
  import * as i1$1 from '@angular/common/http';
17
17
  import '@cds/core/icon/register.js';
18
18
  import { CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
@@ -3581,6 +3581,90 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImpor
3581
3581
  * The full license information can be found in LICENSE in the root directory of this project.
3582
3582
  */
3583
3583
 
3584
+ /*
3585
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3586
+ * This software is released under MIT license.
3587
+ * The full license information can be found in LICENSE in the root directory of this project.
3588
+ */
3589
+ class ClrTreetableActionOverflow {
3590
+ constructor(smartToggleService, zone) {
3591
+ this.smartToggleService = smartToggleService;
3592
+ this.zone = zone;
3593
+ this.empty = input(false);
3594
+ this.smartPosition = {
3595
+ axis: ClrAxis.HORIZONTAL,
3596
+ side: ClrSide.AFTER,
3597
+ anchor: ClrAlignment.CENTER,
3598
+ content: ClrAlignment.CENTER,
3599
+ };
3600
+ this.smartToggleService.openChange.pipe(takeUntilDestroyed()).subscribe(openState => {
3601
+ if (openState) {
3602
+ this.focusFirstButton();
3603
+ }
3604
+ });
3605
+ }
3606
+ focusFirstButton() {
3607
+ this.zone.runOutsideAngular(() => setTimeout(() => {
3608
+ const firstButton = document.querySelector('button.action-item');
3609
+ if (firstButton) {
3610
+ firstButton.focus();
3611
+ }
3612
+ }));
3613
+ }
3614
+ closeOverflowContent(event) {
3615
+ this.smartToggleService.toggleWithEvent(event);
3616
+ }
3617
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableActionOverflow, deps: [{ token: i2.ClrPopoverToggleService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
3618
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetableActionOverflow, isStandalone: false, selector: "clr-tt-action-overflow", inputs: { empty: { classPropertyName: "empty", publicName: "empty", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "cell" }, properties: { "class.treetable-row-actions": "true", "class.treetable-cell": "true" } }, providers: [ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService], ngImport: i0, template: `
3619
+ @if (!empty()) {
3620
+ <ng-container>
3621
+ <button class="treetable-action-trigger" clrPopoverAnchor clrPopoverOpenCloseButton>
3622
+ <cds-icon shape="ellipsis-vertical"></cds-icon>
3623
+ </button>
3624
+ <div
3625
+ class="datagrid-action-overflow"
3626
+ clrFocusTrap
3627
+ (click)="closeOverflowContent($event)"
3628
+ *clrPopoverContent="false; at: smartPosition; outsideClickToClose: true; scrollToClose: true"
3629
+ >
3630
+ <ng-content></ng-content>
3631
+ </div>
3632
+ </ng-container>
3633
+ }
3634
+ `, isInline: true, dependencies: [{ kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: i2.ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: i2.ÇlrClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: i2.ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3635
+ }
3636
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableActionOverflow, decorators: [{
3637
+ type: Component,
3638
+ args: [{
3639
+ selector: 'clr-tt-action-overflow',
3640
+ providers: [ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService],
3641
+ template: `
3642
+ @if (!empty()) {
3643
+ <ng-container>
3644
+ <button class="treetable-action-trigger" clrPopoverAnchor clrPopoverOpenCloseButton>
3645
+ <cds-icon shape="ellipsis-vertical"></cds-icon>
3646
+ </button>
3647
+ <div
3648
+ class="datagrid-action-overflow"
3649
+ clrFocusTrap
3650
+ (click)="closeOverflowContent($event)"
3651
+ *clrPopoverContent="false; at: smartPosition; outsideClickToClose: true; scrollToClose: true"
3652
+ >
3653
+ <ng-content></ng-content>
3654
+ </div>
3655
+ </ng-container>
3656
+ }
3657
+ `,
3658
+ host: {
3659
+ '[class.treetable-row-actions]': 'true',
3660
+ '[class.treetable-cell]': 'true',
3661
+ role: 'cell',
3662
+ },
3663
+ standalone: false,
3664
+ changeDetection: ChangeDetectionStrategy.OnPush,
3665
+ }]
3666
+ }], ctorParameters: () => [{ type: i2.ClrPopoverToggleService }, { type: i0.NgZone }] });
3667
+
3584
3668
  /*
3585
3669
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3586
3670
  * This software is released under MIT license.
@@ -3591,765 +3675,1074 @@ var SelectionType;
3591
3675
  SelectionType[SelectionType["None"] = 0] = "None";
3592
3676
  SelectionType[SelectionType["Multi"] = 1] = "Multi";
3593
3677
  })(SelectionType || (SelectionType = {}));
3678
+ var ClrTreetableSelectedState;
3679
+ (function (ClrTreetableSelectedState) {
3680
+ ClrTreetableSelectedState[ClrTreetableSelectedState["UNSELECTED"] = 0] = "UNSELECTED";
3681
+ ClrTreetableSelectedState[ClrTreetableSelectedState["SELECTED"] = 1] = "SELECTED";
3682
+ ClrTreetableSelectedState[ClrTreetableSelectedState["INDETERMINATE"] = 2] = "INDETERMINATE";
3683
+ })(ClrTreetableSelectedState || (ClrTreetableSelectedState = {}));
3594
3684
 
3595
3685
  /*
3596
3686
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3597
3687
  * This software is released under MIT license.
3598
3688
  * The full license information can be found in LICENSE in the root directory of this project.
3599
3689
  */
3600
- class Sort {
3690
+ class ClrTreetableRecursionService {
3691
+ constructor() {
3692
+ this._template = signal(null);
3693
+ this.recursionTemplate = computed(() => this._template());
3694
+ this.isRecursionMode = computed(() => !!this._template());
3695
+ }
3696
+ setTemplate(newTemplate) {
3697
+ this._template.set(newTemplate);
3698
+ }
3699
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRecursionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3700
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRecursionService }); }
3701
+ }
3702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRecursionService, decorators: [{
3703
+ type: Injectable
3704
+ }] });
3705
+ function treetableRecursionServiceFactory(existing) {
3706
+ return existing || new ClrTreetableRecursionService();
3707
+ }
3708
+ const TREETABLE_RECURSION_SERVICE_PROVIDER = {
3709
+ provide: ClrTreetableRecursionService,
3710
+ useFactory: treetableRecursionServiceFactory,
3711
+ deps: [[new Optional(), new SkipSelf(), ClrTreetableRecursionService]],
3712
+ };
3713
+
3714
+ /*
3715
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3716
+ * This software is released under MIT license.
3717
+ * The full license information can be found in LICENSE in the root directory of this project.
3718
+ */
3719
+ class ClrTreetableRecursiveRows {
3720
+ constructor() {
3721
+ this._recursionService = inject((ClrTreetableRecursionService));
3722
+ this.parent = input(null);
3723
+ this.children = input([]);
3724
+ this.template = computed(() => this._recursionService.recursionTemplate());
3725
+ }
3726
+ getContext(node) {
3727
+ return { $implicit: node.value, isLeaf: node.isLeaf, clrTtNode: node };
3728
+ }
3729
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRecursiveRows, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3730
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetableRecursiveRows, isStandalone: false, selector: "clr-tt-recursive-rows", inputs: { parent: { classPropertyName: "parent", publicName: "parent", isSignal: true, isRequired: false, transformFunction: null }, children: { classPropertyName: "children", publicName: "children", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.role": "\"group\"" } }, ngImport: i0, template: `
3731
+ <ng-container>
3732
+ @for (child of parent()?.children || children(); track child.id) {
3733
+ <ng-container *ngTemplateOutlet="template(); context: getContext(child)" />
3734
+ }
3735
+ </ng-container>
3736
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3737
+ }
3738
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRecursiveRows, decorators: [{
3739
+ type: Component,
3740
+ args: [{
3741
+ selector: 'clr-tt-recursive-rows',
3742
+ template: `
3743
+ <ng-container>
3744
+ @for (child of parent()?.children || children(); track child.id) {
3745
+ <ng-container *ngTemplateOutlet="template(); context: getContext(child)" />
3746
+ }
3747
+ </ng-container>
3748
+ `,
3749
+ host: {
3750
+ '[attr.role]': '"group"',
3751
+ },
3752
+ changeDetection: ChangeDetectionStrategy.OnPush,
3753
+ standalone: false,
3754
+ }]
3755
+ }] });
3756
+
3757
+ /*
3758
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3759
+ * This software is released under MIT license.
3760
+ * The full license information can be found in LICENSE in the root directory of this project.
3761
+ */
3762
+ class ClrTreetableRowCheckbox {
3763
+ constructor() {
3764
+ this.clrTtSelectionState = model(ClrTreetableSelectedState.UNSELECTED);
3765
+ this.isSelected = computed(() => this.clrTtSelectionState() === ClrTreetableSelectedState.SELECTED);
3766
+ this.isIndeterminate = computed(() => this.clrTtSelectionState() === ClrTreetableSelectedState.INDETERMINATE);
3767
+ }
3768
+ toggle() {
3769
+ this.clrTtSelectionState.update(current => current === ClrTreetableSelectedState.SELECTED
3770
+ ? ClrTreetableSelectedState.UNSELECTED
3771
+ : ClrTreetableSelectedState.SELECTED);
3772
+ }
3773
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRowCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3774
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.6", type: ClrTreetableRowCheckbox, isStandalone: false, selector: "clr-tt-row-checkbox", inputs: { clrTtSelectionState: { classPropertyName: "clrTtSelectionState", publicName: "clrTtSelectionState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clrTtSelectionState: "clrTtSelectionStateChange" }, ngImport: i0, template: `
3775
+ <div class="clr-checkbox-wrapper treetable-row-selection treetable-cell">
3776
+ <input
3777
+ type="checkbox"
3778
+ data-testId="clrTtRowCheckbox"
3779
+ [indeterminate]="isIndeterminate()"
3780
+ [checked]="isSelected()"
3781
+ (change)="toggle()"
3782
+ />
3783
+ </div>
3784
+ `, isInline: true, styles: [".treetable-children-container{opacity:0;will-change:height,opacity}.treetable-children-container.expanded{opacity:1}.treetable-children-container.collapsed{height:0;opacity:0;overflow:hidden}.treetable-children-container.animate{transition:height .4s ease,opacity .4s ease}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3785
+ }
3786
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRowCheckbox, decorators: [{
3787
+ type: Component,
3788
+ args: [{ selector: 'clr-tt-row-checkbox', template: `
3789
+ <div class="clr-checkbox-wrapper treetable-row-selection treetable-cell">
3790
+ <input
3791
+ type="checkbox"
3792
+ data-testId="clrTtRowCheckbox"
3793
+ [indeterminate]="isIndeterminate()"
3794
+ [checked]="isSelected()"
3795
+ (change)="toggle()"
3796
+ />
3797
+ </div>
3798
+ `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, styles: [".treetable-children-container{opacity:0;will-change:height,opacity}.treetable-children-container.expanded{opacity:1}.treetable-children-container.collapsed{height:0;opacity:0;overflow:hidden}.treetable-children-container.animate{transition:height .4s ease,opacity .4s ease}\n"] }]
3799
+ }] });
3800
+
3801
+ /*
3802
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3803
+ * This software is released under MIT license.
3804
+ * The full license information can be found in LICENSE in the root directory of this project.
3805
+ */
3806
+ class ClrTreetableRow {
3601
3807
  constructor() {
3602
- this._reverse = false;
3603
- this._change = new Subject();
3808
+ this._recursionService = inject(ClrTreetableRecursionService);
3809
+ this._treetable = inject(ClrTreetable);
3810
+ this.clrExpanded = model(false);
3811
+ this.clrExpandable = input(false);
3812
+ this.clrClickable = input(true);
3813
+ this.clrTtItem = input(undefined);
3814
+ this._actionOverflow = contentChild(ClrTreetableActionOverflow);
3815
+ this.shouldAnimate = signal(false);
3816
+ this.isRecursionMode = this._recursionService.isRecursionMode;
3817
+ this._isClickable = computed(() => this._treetable.clrClickableRows() && this.clrClickable());
3818
+ this.isSelected = computed(() => this.clrTtItem()?.selected() === ClrTreetableSelectedState.SELECTED);
3819
+ this.showActionOverflow = computed(() => this._treetable.hasActionOverflow() || !!this._actionOverflow());
3820
+ this.showEmptyActionOverflow = computed(() => !this._actionOverflow());
3821
+ this.showClickClass = computed(() => this._treetable.clrClickableRows() && this.clrExpandable());
3822
+ this.showSelection = computed(() => this._treetable.selectionType() === SelectionType.Multi);
3823
+ }
3824
+ onExpandCollapseClick() {
3825
+ // Only animate on user click (not on sorting or initial rendering)
3826
+ this.shouldAnimate.set(true);
3827
+ this.toggleExpand();
3828
+ // Remove .animate after animation to prevent unwanted transitions
3829
+ setTimeout(() => {
3830
+ this.shouldAnimate.set(false);
3831
+ }, 350);
3604
3832
  }
3605
- get comparator() {
3606
- return this._comparator;
3833
+ toggleSelection(selectionState) {
3834
+ this.clrTtItem()?.setSelected(selectionState);
3607
3835
  }
3608
- set comparator(value) {
3609
- this._comparator = value;
3610
- this.emitChange();
3836
+ toggleExpand() {
3837
+ if (this.clrExpandable()) {
3838
+ this.clrExpanded.update(state => !state);
3839
+ }
3611
3840
  }
3612
- get reverse() {
3613
- return this._reverse;
3841
+ onRowClick(event) {
3842
+ if (this._isClickable() && !event.target.closest('.treetable-action-trigger')) {
3843
+ this.onExpandCollapseClick();
3844
+ }
3614
3845
  }
3615
- set reverse(value) {
3616
- this._reverse = value;
3617
- this.emitChange();
3846
+ onCaretClick() {
3847
+ if (!this._isClickable()) {
3848
+ this.onExpandCollapseClick();
3849
+ }
3618
3850
  }
3619
- // We do not want to expose the Subject itself, but the Observable which is read-only
3620
- get change() {
3621
- return this._change.asObservable();
3851
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRow, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3852
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetableRow, isStandalone: false, selector: "clr-tt-row", inputs: { clrExpanded: { classPropertyName: "clrExpanded", publicName: "clrExpanded", isSignal: true, isRequired: false, transformFunction: null }, clrExpandable: { classPropertyName: "clrExpandable", publicName: "clrExpandable", isSignal: true, isRequired: false, transformFunction: null }, clrClickable: { classPropertyName: "clrClickable", publicName: "clrClickable", isSignal: true, isRequired: false, transformFunction: null }, clrTtItem: { classPropertyName: "clrTtItem", publicName: "clrTtItem", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clrExpanded: "clrExpandedChange" }, host: { properties: { "class.treetable-row-wrapper": "true", "class.treetable-selected": "isSelected()" } }, providers: [TREETABLE_RECURSION_SERVICE_PROVIDER], queries: [{ propertyName: "_actionOverflow", first: true, predicate: ClrTreetableActionOverflow, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div\n class=\"clr-tt-node-content treetable-row\"\n [class.clr-row-clickable]=\"showClickClass()\"\n [class.treetable-selected]=\"isSelected()\"\n (click)=\"onRowClick($event)\"\n>\n @if (showSelection()) {\n <clr-tt-row-checkbox\n [clrTtSelectionState]=\"clrTtItem().selected()\"\n (clrTtSelectionStateChange)=\"toggleSelection($event)\"\n (click)=\"$event.stopPropagation()\"\n >\n </clr-tt-row-checkbox>\n }\n\n <ng-content select=\"clr-tt-action-overflow\" />\n\n @if (showActionOverflow() && showEmptyActionOverflow()) {\n <clr-tt-action-overflow [empty]=\"true\" />\n }\n\n <div class=\"treetable-scrolling-cells\">\n @if (clrExpandable()) {\n <div class=\"treetable-expandable-caret\">\n <button\n type=\"button\"\n class=\"treetable-expandable-caret-button\"\n data-testId=\"clrTtRowCaret\"\n (click)=\"onCaretClick()\"\n >\n <cds-icon\n shape=\"angle\"\n [attr.direction]=\"clrExpanded() ? 'down' : 'right'\"\n class=\"treetable-expandable-caret-icon\"\n ></cds-icon>\n </button>\n </div>\n }\n\n <ng-content select=\"clr-tt-cell\" />\n </div>\n</div>\n\n<div\n class=\"treetable-children-container\"\n data-testId=\"clrTtRowChildContainer\"\n [class.expanded]=\"clrExpanded()\"\n [class.collapsed]=\"!clrExpanded()\"\n [class.animate]=\"shouldAnimate()\"\n>\n @if (isRecursionMode()) {\n <clr-tt-recursive-rows [parent]=\"clrTtItem()\" />\n } @else {\n <ng-content select=\"clr-tt-row\" />\n }\n</div>\n", styles: [".treetable-children-container{opacity:0;will-change:height,opacity}.treetable-children-container.expanded{opacity:1}.treetable-children-container.collapsed{height:0;opacity:0;overflow:hidden}.treetable-children-container.animate{transition:height .4s ease,opacity .4s ease}\n"], dependencies: [{ kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrTreetableActionOverflow, selector: "clr-tt-action-overflow", inputs: ["empty"] }, { kind: "component", type: ClrTreetableRecursiveRows, selector: "clr-tt-recursive-rows", inputs: ["parent", "children"] }, { kind: "component", type: ClrTreetableRowCheckbox, selector: "clr-tt-row-checkbox", inputs: ["clrTtSelectionState"], outputs: ["clrTtSelectionStateChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3853
+ }
3854
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRow, decorators: [{
3855
+ type: Component,
3856
+ args: [{ selector: 'clr-tt-row', providers: [TREETABLE_RECURSION_SERVICE_PROVIDER], host: { '[class.treetable-row-wrapper]': 'true', '[class.treetable-selected]': 'isSelected()' }, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div\n class=\"clr-tt-node-content treetable-row\"\n [class.clr-row-clickable]=\"showClickClass()\"\n [class.treetable-selected]=\"isSelected()\"\n (click)=\"onRowClick($event)\"\n>\n @if (showSelection()) {\n <clr-tt-row-checkbox\n [clrTtSelectionState]=\"clrTtItem().selected()\"\n (clrTtSelectionStateChange)=\"toggleSelection($event)\"\n (click)=\"$event.stopPropagation()\"\n >\n </clr-tt-row-checkbox>\n }\n\n <ng-content select=\"clr-tt-action-overflow\" />\n\n @if (showActionOverflow() && showEmptyActionOverflow()) {\n <clr-tt-action-overflow [empty]=\"true\" />\n }\n\n <div class=\"treetable-scrolling-cells\">\n @if (clrExpandable()) {\n <div class=\"treetable-expandable-caret\">\n <button\n type=\"button\"\n class=\"treetable-expandable-caret-button\"\n data-testId=\"clrTtRowCaret\"\n (click)=\"onCaretClick()\"\n >\n <cds-icon\n shape=\"angle\"\n [attr.direction]=\"clrExpanded() ? 'down' : 'right'\"\n class=\"treetable-expandable-caret-icon\"\n ></cds-icon>\n </button>\n </div>\n }\n\n <ng-content select=\"clr-tt-cell\" />\n </div>\n</div>\n\n<div\n class=\"treetable-children-container\"\n data-testId=\"clrTtRowChildContainer\"\n [class.expanded]=\"clrExpanded()\"\n [class.collapsed]=\"!clrExpanded()\"\n [class.animate]=\"shouldAnimate()\"\n>\n @if (isRecursionMode()) {\n <clr-tt-recursive-rows [parent]=\"clrTtItem()\" />\n } @else {\n <ng-content select=\"clr-tt-row\" />\n }\n</div>\n", styles: [".treetable-children-container{opacity:0;will-change:height,opacity}.treetable-children-container.expanded{opacity:1}.treetable-children-container.collapsed{height:0;opacity:0;overflow:hidden}.treetable-children-container.animate{transition:height .4s ease,opacity .4s ease}\n"] }]
3857
+ }] });
3858
+
3859
+ /*
3860
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3861
+ * This software is released under MIT license.
3862
+ * The full license information can be found in LICENSE in the root directory of this project.
3863
+ */
3864
+ class Sort {
3865
+ constructor() {
3866
+ this._comparator = signal(null);
3867
+ this._reverse = signal(false);
3868
+ this.sortState = computed(() => ({
3869
+ comparator: this._comparator(),
3870
+ reverse: this._reverse(),
3871
+ }));
3872
+ this.changes$ = toObservable(this.sortState);
3622
3873
  }
3623
3874
  /**
3624
3875
  * Sets a comparator as the current one, or toggles reverse if the comparator is already used. The
3625
3876
  * optional forceReverse input parameter allows to override that toggling behavior by sorting in
3626
3877
  * reverse order if `true`.
3627
- *
3628
- * @memberof Sort
3629
3878
  */
3630
3879
  toggle(sortBy, forceReverse) {
3631
- if (this.comparator === sortBy) {
3632
- this._reverse = typeof forceReverse !== 'undefined' ? forceReverse || !this._reverse : !this._reverse;
3880
+ if (this._comparator() === sortBy) {
3881
+ const newReverse = typeof forceReverse !== 'undefined' ? forceReverse : !this._reverse();
3882
+ this._reverse.set(newReverse);
3633
3883
  }
3634
3884
  else {
3635
- this._comparator = sortBy;
3636
- this._reverse = typeof forceReverse !== 'undefined' ? forceReverse : false;
3885
+ this._comparator.set(sortBy);
3886
+ this._reverse.set(typeof forceReverse !== 'undefined' ? forceReverse : false);
3637
3887
  }
3638
- this.emitChange();
3639
3888
  }
3889
+ /**
3890
+ * Clears the current comparator
3891
+ */
3640
3892
  clear() {
3641
- this.comparator = null;
3893
+ this._comparator.set(null);
3642
3894
  }
3895
+ /**
3896
+ * Compares two items using the current comparator and reverse flag
3897
+ */
3643
3898
  compare(a, b) {
3644
- return (this.reverse ? -1 : 1) * this.comparator.compare(a, b);
3645
- }
3646
- emitChange() {
3647
- this._change.next(this);
3899
+ const currentComparator = this._comparator();
3900
+ if (!currentComparator) {
3901
+ return 0;
3902
+ }
3903
+ return (this._reverse() ? -1 : 1) * currentComparator.compare(a, b);
3648
3904
  }
3649
3905
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Sort, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3650
3906
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Sort }); }
3651
3907
  }
3652
3908
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Sort, decorators: [{
3653
3909
  type: Injectable
3654
- }], ctorParameters: () => [] });
3910
+ }] });
3655
3911
 
3656
3912
  /*
3657
3913
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3658
3914
  * This software is released under MIT license.
3659
3915
  * The full license information can be found in LICENSE in the root directory of this project.
3660
3916
  */
3661
- class Items {
3662
- constructor() {
3663
- this._all = [];
3664
- this._displayed = [];
3665
- this._change = new Subject();
3666
- this._sort = inject((Sort));
3667
- this._sort.change.pipe(takeUntilDestroyed()).subscribe(() => {
3668
- this.sortItems();
3917
+ /**
3918
+ * Internal counter for generating unique node ids.
3919
+ */
3920
+ let treeNodeIdCounter = 0;
3921
+ /**
3922
+ * Creates a unique id for a tree node instance.
3923
+ */
3924
+ function uniqueTreeNodeIdFactory() {
3925
+ return `clr-treetable-node-${treeNodeIdCounter++}`;
3926
+ }
3927
+ /**
3928
+ * Represents a single tree node inside the treetable.
3929
+ * Maintains derived selection state (SELECTED / UNSELECTED / INDETERMINATE) based on:
3930
+ * - Manual selection of this node.
3931
+ * - Aggregated selection states of all descendants.
3932
+ * Selection propagation to descendants happens only on explicit setSelected calls.
3933
+ */
3934
+ class ClrTreetableTreeNode {
3935
+ constructor(value, parent = null, children = [], stickyIndeterminate = false) {
3936
+ this.id = uniqueTreeNodeIdFactory();
3937
+ this.parent = null;
3938
+ this.children = [];
3939
+ this.manuallySelected = signal(false);
3940
+ this.selected = linkedSignal(() => {
3941
+ const isManuallySelected = this.manuallySelected();
3942
+ let allChildrenSelected = true;
3943
+ let anyChildSelected = false;
3944
+ for (const child of this.children) {
3945
+ switch (child.selected()) {
3946
+ case ClrTreetableSelectedState.SELECTED:
3947
+ anyChildSelected = true;
3948
+ break;
3949
+ case ClrTreetableSelectedState.INDETERMINATE:
3950
+ anyChildSelected = true;
3951
+ allChildrenSelected = false;
3952
+ break;
3953
+ case ClrTreetableSelectedState.UNSELECTED:
3954
+ default:
3955
+ allChildrenSelected = false;
3956
+ break;
3957
+ }
3958
+ if (!allChildrenSelected && anyChildSelected) {
3959
+ break;
3960
+ }
3961
+ }
3962
+ if (isManuallySelected && allChildrenSelected) {
3963
+ return ClrTreetableSelectedState.SELECTED;
3964
+ }
3965
+ if (this.isLeaf) {
3966
+ return ClrTreetableSelectedState.UNSELECTED;
3967
+ }
3968
+ if (!anyChildSelected) {
3969
+ return ClrTreetableSelectedState.UNSELECTED;
3970
+ }
3971
+ if (allChildrenSelected && !this.stickyIndeterminate) {
3972
+ return ClrTreetableSelectedState.SELECTED;
3973
+ }
3974
+ return ClrTreetableSelectedState.INDETERMINATE;
3669
3975
  });
3670
- }
3671
- get all() {
3672
- return this._all;
3673
- }
3674
- addItems(items) {
3675
- this._all = this._all.concat([items.slice()]);
3676
- this._displayed = this._displayed.concat([items.slice()]);
3677
- this.emitChange();
3678
- }
3679
- get displayed() {
3680
- return this._displayed;
3681
- }
3682
- get change() {
3683
- return this._change.asObservable();
3976
+ this.value = value;
3977
+ this.parent = parent;
3978
+ this.children = children;
3979
+ this.stickyIndeterminate = stickyIndeterminate;
3684
3980
  }
3685
3981
  /**
3686
- * Checks if we don't have data to process yet, to abort early operations
3982
+ * Depth level in the tree (root = 0).
3687
3983
  */
3688
- get uninitialized() {
3689
- return !this._all;
3984
+ get depth() {
3985
+ return this.parent ? this.parent.depth + 1 : 0;
3690
3986
  }
3691
- emitChange() {
3692
- this._change.next(this.displayed);
3987
+ /**
3988
+ * True if this node has no children.
3989
+ */
3990
+ get isLeaf() {
3991
+ return this.children?.length === 0;
3693
3992
  }
3694
- sortItems() {
3695
- if (this.uninitialized) {
3696
- return;
3993
+ /**
3994
+ * Sets the selection state for this node and propagates to all descendants (except INDETERMINATE).
3995
+ * @param state Desired selection state.
3996
+ */
3997
+ setSelected(state) {
3998
+ switch (state) {
3999
+ case ClrTreetableSelectedState.SELECTED:
4000
+ if (!this.manuallySelected()) {
4001
+ this.manuallySelected.set(true);
4002
+ }
4003
+ this.propagateToChildren(true);
4004
+ break;
4005
+ case ClrTreetableSelectedState.UNSELECTED:
4006
+ if (this.manuallySelected()) {
4007
+ this.manuallySelected.set(false);
4008
+ }
4009
+ this.propagateToChildren(false);
4010
+ break;
4011
+ case ClrTreetableSelectedState.INDETERMINATE:
4012
+ break;
3697
4013
  }
3698
- if (this._sort.comparator) {
3699
- this._displayed.forEach(subArray => {
3700
- subArray.sort((a, b) => this._sort.compare(a, b));
3701
- });
4014
+ }
4015
+ /**
4016
+ * Returns all descendants as a flat generator.
4017
+ */
4018
+ *getFlatDescendants() {
4019
+ for (const child of this.children) {
4020
+ yield child;
4021
+ if (!child.isLeaf) {
4022
+ yield* child.getFlatDescendants();
4023
+ }
3702
4024
  }
3703
- else {
3704
- this._displayed = this._all.map(subArray => subArray.slice());
4025
+ }
4026
+ /**
4027
+ * Recursively applies a selected/unselected state to all descendants.
4028
+ */
4029
+ propagateToChildren(selected) {
4030
+ for (const child of this.children) {
4031
+ child.setSelected(selected ? ClrTreetableSelectedState.SELECTED : ClrTreetableSelectedState.UNSELECTED);
4032
+ if (!child.isLeaf) {
4033
+ child.propagateToChildren(selected);
4034
+ }
3705
4035
  }
3706
- this.emitChange();
3707
4036
  }
3708
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Items, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3709
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Items }); }
3710
4037
  }
3711
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Items, decorators: [{
3712
- type: Injectable
3713
- }], ctorParameters: () => [] });
4038
+ /**
4039
+ * Internal recursive helper building the internal tree node structure.
4040
+ */
4041
+ function mapToInternalTreeRecursive(value, getChildren, parent, stickyIndeterminate) {
4042
+ const node = new ClrTreetableTreeNode(value, parent, [], stickyIndeterminate);
4043
+ const rawChildren = getChildren(value) || [];
4044
+ node.children = rawChildren.map(child => mapToInternalTreeRecursive(child, getChildren, node, stickyIndeterminate));
4045
+ return node;
4046
+ }
4047
+ /**
4048
+ * Creates an internal tree node hierarchy from a raw data object.
4049
+ *
4050
+ * @param value Root raw data object.
4051
+ * @param getChildren Function returning direct children of a node.
4052
+ * @param stickyIndeterminate Whether to keep INDETERMINATE even if all descendants become selected.
4053
+ */
4054
+ function mapToInternalTree(value, getChildren, stickyIndeterminate) {
4055
+ return mapToInternalTreeRecursive(value, getChildren, null, stickyIndeterminate);
4056
+ }
3714
4057
 
3715
4058
  /*
3716
4059
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3717
4060
  * This software is released under MIT license.
3718
4061
  * The full license information can be found in LICENSE in the root directory of this project.
3719
4062
  */
3720
- class Selection {
3721
- constructor() {
3722
- this._change = new Subject();
3723
- this._allSelected = new Subject();
3724
- //debounce and batch changes before emitting them to subscribers
3725
- this._valueCollector = new Subject();
3726
- this._selectionType = SelectionType.None;
3727
- this._items = inject(Items);
3728
- this._valueCollector.pipe(debounceTime(0), takeUntilDestroyed()).subscribe(() => this.emitChange());
3729
- }
3730
- get selectionType() {
3731
- return this._selectionType;
3732
- }
3733
- set selectionType(value) {
3734
- if (value === this.selectionType) {
3735
- return;
3736
- }
3737
- this._selectionType = value;
3738
- if (value === SelectionType.None) {
3739
- delete this.current;
3740
- }
3741
- else {
3742
- this.updateCurrent([], false);
3743
- }
3744
- }
3745
- get current() {
3746
- return this._current;
3747
- }
3748
- set current(value) {
3749
- this.updateCurrent(value, true);
4063
+ /**
4064
+ * Helper function to check if a primitive filter value is valid. Complex objects will always be valid.
4065
+ * This function is a fallback for primitive values, if a custom filter does not set the isActive method correctly.
4066
+ *
4067
+ * @param value the value to check
4068
+ */
4069
+ function isValidFilterValue(value) {
4070
+ if (value == null || value === false) {
4071
+ return false;
3750
4072
  }
3751
- updateCurrent(value, emit) {
3752
- this._current = value;
3753
- if (emit) {
3754
- this._valueCollector.next(value);
3755
- }
4073
+ if (typeof value === 'string') {
4074
+ return value.trim().length > 0;
3756
4075
  }
3757
- get change() {
3758
- return this._change.asObservable();
4076
+ if (typeof value === 'number') {
4077
+ return !Number.isNaN(value);
3759
4078
  }
3760
- get allSelectedChange() {
3761
- return this._allSelected.asObservable();
4079
+ return true;
4080
+ }
4081
+ /**
4082
+ * Comparator for distinctUntilChanged on the filter values stream.
4083
+ * Emits only when:
4084
+ * - Array length changes, or
4085
+ * - A primitive value at some index changes, or
4086
+ * - Any element is non-primitive (object / function / array) -> always treated as changed.
4087
+ *
4088
+ * Rationale:
4089
+ * Objects/arrays are assumed to have unstable identity/content; any occurrence triggers a new emission.
4090
+ *
4091
+ * @param prev Previous emitted array of active filter values.
4092
+ * @param curr Current emitted array of active filter values.
4093
+ * @returns true if both arrays should be considered equal (no new emission), false otherwise.
4094
+ */
4095
+ function areFiltersDistinct(prev, curr) {
4096
+ if (prev === curr) {
4097
+ return true;
3762
4098
  }
3763
- isSelected(item) {
3764
- return this.current.indexOf(item) >= 0;
4099
+ if (!Array.isArray(prev) || !Array.isArray(curr)) {
4100
+ return false;
3765
4101
  }
3766
- setSelected(item, selected) {
3767
- const index = this.current ? this.current.indexOf(item) : -1;
3768
- if (index >= 0 && !selected) {
3769
- this.deselectItem(index);
3770
- }
3771
- else if (index < 0 && selected) {
3772
- this.selectItem(item);
3773
- }
4102
+ if (prev.length !== curr.length) {
4103
+ return false;
3774
4104
  }
3775
- isAllSelected() {
3776
- const displayedItems = this._items.displayed;
3777
- const nbDisplayed = displayedItems.length;
3778
- if (nbDisplayed < 1) {
4105
+ const isPrimitive = (v) => v == null || (typeof v !== 'object' && typeof v !== 'function');
4106
+ for (let i = 0; i < prev.length; i++) {
4107
+ const a = prev[i];
4108
+ const b = curr[i];
4109
+ // Non-primitive anywhere => force emission
4110
+ if (!isPrimitive(a) || !isPrimitive(b)) {
3779
4111
  return false;
3780
4112
  }
3781
- const flattenedDisplayedItems = displayedItems.flat();
3782
- const selectedItems = flattenedDisplayedItems.filter(item => this.current.indexOf(item) > -1);
3783
- return selectedItems.length === flattenedDisplayedItems.length;
3784
- }
3785
- toggleAll() {
3786
- const isAllSelected = this.isAllSelected();
3787
- if (isAllSelected) {
3788
- this._items.displayed.forEach(items => {
3789
- items.forEach(item => {
3790
- const currentIndex = this.current.indexOf(item);
3791
- if (currentIndex > -1) {
3792
- this.deselectItem(currentIndex);
3793
- }
3794
- });
3795
- });
3796
- }
3797
- else {
3798
- this._items.displayed.forEach(items => {
3799
- items.forEach(item => {
3800
- if (this.current.indexOf(item) < 0) {
3801
- this.selectItem(item);
3802
- }
3803
- });
3804
- });
4113
+ if (!Object.is(a, b)) {
4114
+ return false;
3805
4115
  }
3806
- this._allSelected.next(!isAllSelected);
3807
4116
  }
3808
- selectItem(item) {
3809
- this.current = this.current.concat(item);
3810
- }
3811
- deselectItem(indexOfItem) {
3812
- this.current = this.current.slice(0, indexOfItem).concat(this.current.slice(indexOfItem + 1));
3813
- }
3814
- emitChange() {
3815
- this._change.next(this.current);
3816
- }
3817
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Selection, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3818
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Selection }); }
4117
+ return true;
3819
4118
  }
3820
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Selection, decorators: [{
3821
- type: Injectable
3822
- }], ctorParameters: () => [] });
3823
4119
 
3824
4120
  /*
3825
4121
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3826
4122
  * This software is released under MIT license.
3827
4123
  * The full license information can be found in LICENSE in the root directory of this project.
3828
4124
  */
3829
- var ClrTreetableSortOrder;
3830
- (function (ClrTreetableSortOrder) {
3831
- ClrTreetableSortOrder[ClrTreetableSortOrder["UNSORTED"] = 0] = "UNSORTED";
3832
- ClrTreetableSortOrder[ClrTreetableSortOrder["ASC"] = 1] = "ASC";
3833
- ClrTreetableSortOrder[ClrTreetableSortOrder["DESC"] = -1] = "DESC";
3834
- })(ClrTreetableSortOrder || (ClrTreetableSortOrder = {}));
3835
-
3836
- /*
3837
- * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3838
- * This software is released under MIT license.
3839
- * The full license information can be found in LICENSE in the root directory of this project.
4125
+ /**
4126
+ * Wrapper for a treetable filter instance that holds the filter and its unregister callback.
4127
+ *
4128
+ * @template T The row data type processed by the treetable.
4129
+ * @template F The concrete filter type implementing <code>ClrTreetableFilterInterface</code> for <code>T</code>.
4130
+ * @property filter The concrete filter instance.
4131
+ * @property unregister Callback to remove this filter from the Filters service.
3840
4132
  */
3841
- class ClrTreetableColumn {
3842
- get sortBy() {
3843
- return this._sortBy;
3844
- }
3845
- set sortBy(comparator) {
3846
- this._sortBy = comparator;
3847
- }
3848
- get sortOrder() {
3849
- return this._sortOrder;
3850
- }
3851
- set sortOrder(value) {
3852
- if (typeof value === 'undefined') {
3853
- return;
3854
- }
3855
- // nothing to do when incoming sort order is the same
3856
- if (this._sortOrder === value) {
3857
- return;
3858
- }
3859
- switch (value) {
3860
- case ClrTreetableSortOrder.ASC:
3861
- this.sort(false);
3862
- break;
3863
- case ClrTreetableSortOrder.DESC:
3864
- this.sort(true);
3865
- break;
3866
- // UNSORTED when neither ASC or DESC
3867
- case ClrTreetableSortOrder.UNSORTED:
3868
- default:
3869
- this._sort.clear();
3870
- break;
3871
- }
3872
- }
3873
- get sortDirection() {
3874
- return this._sortDirection;
4133
+ class RegisteredTreetableFilter {
4134
+ constructor(filter, unregister) {
4135
+ this.filter = filter;
4136
+ this.unregister = unregister;
3875
4137
  }
4138
+ }
4139
+ class Filters {
3876
4140
  constructor() {
3877
- this._sort = inject((Sort));
3878
- this._cdr = inject(ChangeDetectorRef);
3879
- this._sortOrder = ClrTreetableSortOrder.UNSORTED;
3880
- this.sortOrderChange = output({ alias: 'clrTtSortOrderChange' });
3881
- this.listenForSortingChanges();
3882
- }
3883
- get ariaSort() {
3884
- switch (this._sortOrder) {
3885
- case ClrTreetableSortOrder.ASC:
3886
- return 'ascending';
3887
- case ClrTreetableSortOrder.DESC:
3888
- return 'descending';
3889
- case ClrTreetableSortOrder.UNSORTED:
3890
- default:
3891
- return 'none';
3892
- }
3893
- }
3894
- get sortable() {
3895
- return !!this._sortBy;
4141
+ this._destroyRef = inject(DestroyRef);
4142
+ this.filterId = 0;
4143
+ this.updateFilterValue$ = new Subject();
4144
+ this._filterState = signal({});
4145
+ this._registeredFilters = computed(() => {
4146
+ const filterStates = Object.values(this._filterState());
4147
+ return filterStates.map(({ filter }) => filter);
4148
+ });
4149
+ this.activeFilters = computed(() => {
4150
+ return this._registeredFilters()
4151
+ .filter(({ filter }) => filter.isActive())
4152
+ .map(({ filter }) => filter);
4153
+ });
4154
+ this.hasActiveFilters = computed(() => this.activeFilters().length > 0);
4155
+ this.changes$ = toObservable(this._filterState).pipe(map$1(filterState => Object.values(filterState)
4156
+ .filter(({ filter }) => filter.filter.isActive())
4157
+ .map(({ value }) => value)
4158
+ .filter(value => isValidFilterValue(value))), distinctUntilChanged(areFiltersDistinct), shareReplay(1));
4159
+ this.updateFilterValue$.pipe(takeUntilDestroyed()).subscribe((update) => {
4160
+ this._filterState.update(current => {
4161
+ const state = current[update.filterId] || { filter: undefined, value: undefined };
4162
+ return {
4163
+ ...current,
4164
+ [update.filterId]: {
4165
+ ...state,
4166
+ value: update.value,
4167
+ },
4168
+ };
4169
+ });
4170
+ });
3896
4171
  }
3897
- sort(reverse) {
3898
- if (!this.sortable) {
3899
- return;
4172
+ register(treetableFilter) {
4173
+ if (!treetableFilter) {
4174
+ return undefined;
3900
4175
  }
3901
- this._sort.toggle(this._sortBy, reverse);
3902
- // setting the private variable to not retrigger the setter logic
3903
- this._sortOrder = this._sort.reverse ? ClrTreetableSortOrder.DESC : ClrTreetableSortOrder.ASC;
3904
- // Sets the correct icon for current sort order
3905
- this._sortDirection = this._sortOrder === ClrTreetableSortOrder.DESC ? 'down' : 'up';
3906
- this.sortOrderChange.emit(this._sortOrder);
3907
- }
3908
- listenForSortingChanges() {
3909
- this._sort.change.pipe(takeUntilDestroyed()).subscribe(sort => {
3910
- // Need to manually mark the component to be checked
3911
- // for both activating and deactivating sorting
3912
- this._cdr.markForCheck();
3913
- // We're only listening to make sure we emit an event when the column goes from sorted to unsorted
3914
- if (this.sortOrder !== ClrTreetableSortOrder.UNSORTED && sort.comparator !== this._sortBy) {
3915
- this._sortOrder = ClrTreetableSortOrder.UNSORTED;
3916
- this.sortOrderChange.emit(this._sortOrder);
3917
- this._sortDirection = null;
4176
+ const filterId = `clr-tt-filter-${this.filterId++}`;
4177
+ const subscription = treetableFilter.changes
4178
+ .pipe(takeUntilDestroyed(this._destroyRef))
4179
+ .subscribe(valueChange => this.updateFilterValue$.next({ filterId, value: valueChange }));
4180
+ let hasUnregistered = false;
4181
+ const registered = new RegisteredTreetableFilter(treetableFilter, () => {
4182
+ if (hasUnregistered) {
4183
+ return;
3918
4184
  }
4185
+ subscription.unsubscribe();
4186
+ this._filterState.update(current => {
4187
+ delete current[filterId];
4188
+ return { ...current };
4189
+ });
4190
+ hasUnregistered = true;
3919
4191
  });
4192
+ this._filterState.update(current => {
4193
+ const state = current[filterId] || { filter: undefined, value: undefined };
4194
+ return {
4195
+ ...current,
4196
+ [filterId]: {
4197
+ ...state,
4198
+ filter: registered,
4199
+ },
4200
+ };
4201
+ });
4202
+ return registered;
3920
4203
  }
3921
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableColumn, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3922
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetableColumn, isStandalone: false, selector: "clr-tt-column", inputs: { sortBy: ["clrTtSortBy", "sortBy"], sortOrder: ["clrTtSortOrder", "sortOrder"] }, outputs: { sortOrderChange: "clrTtSortOrderChange" }, host: { attributes: { "role": "columnheader" }, properties: { "class.treetable-column": "true", "attr.aria-sort": "ariaSort" } }, ngImport: i0, template: `
3923
- @if(sortable) {
3924
- <button class="treetable-column-title" (click)="sort()" type="button">
3925
- <ng-container *ngTemplateOutlet="columnTitle" />
3926
- <cds-icon
3927
- *ngIf="sortDirection"
3928
- shape="arrow"
3929
- [attr.direction]="sortDirection"
3930
- aria-hidden="true"
3931
- class="sort-icon"
3932
- />
3933
- </button>
3934
- } @else {
3935
- <ng-container *ngTemplateOutlet="columnTitle" />
3936
- }
3937
-
3938
- <ng-template #columnTitle>
3939
- <ng-content />
3940
- </ng-template>
3941
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4204
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Filters, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4205
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Filters }); }
3942
4206
  }
3943
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableColumn, decorators: [{
3944
- type: Component,
3945
- args: [{
3946
- selector: 'clr-tt-column',
3947
- template: `
3948
- @if(sortable) {
3949
- <button class="treetable-column-title" (click)="sort()" type="button">
3950
- <ng-container *ngTemplateOutlet="columnTitle" />
3951
- <cds-icon
3952
- *ngIf="sortDirection"
3953
- shape="arrow"
3954
- [attr.direction]="sortDirection"
3955
- aria-hidden="true"
3956
- class="sort-icon"
3957
- />
3958
- </button>
3959
- } @else {
3960
- <ng-container *ngTemplateOutlet="columnTitle" />
3961
- }
3962
-
3963
- <ng-template #columnTitle>
3964
- <ng-content />
3965
- </ng-template>
3966
- `,
3967
- host: {
3968
- '[class.treetable-column]': 'true',
3969
- '[attr.aria-sort]': 'ariaSort',
3970
- role: 'columnheader',
3971
- },
3972
- changeDetection: ChangeDetectionStrategy.OnPush,
3973
- standalone: false,
3974
- }]
3975
- }], ctorParameters: () => [], propDecorators: { sortBy: [{
3976
- type: Input,
3977
- args: ['clrTtSortBy']
3978
- }], sortOrder: [{
3979
- type: Input,
3980
- args: ['clrTtSortOrder']
3981
- }] } });
4207
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: Filters, decorators: [{
4208
+ type: Injectable
4209
+ }], ctorParameters: () => [] });
3982
4210
 
3983
4211
  /*
3984
4212
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
3985
4213
  * This software is released under MIT license.
3986
4214
  * The full license information can be found in LICENSE in the root directory of this project.
3987
4215
  */
3988
- ClarityIcons.addIcons(ellipsisVerticalIcon);
3989
- class ClrTreetableActionOverflow {
3990
- constructor(smartToggleService, zone) {
3991
- this.smartToggleService = smartToggleService;
3992
- this.zone = zone;
3993
- this.empty = false;
3994
- this.smartPosition = {
3995
- axis: ClrAxis.HORIZONTAL,
3996
- side: ClrSide.AFTER,
3997
- anchor: ClrAlignment.CENTER,
3998
- content: ClrAlignment.CENTER,
3999
- };
4000
- this.destroyed$ = new Subject();
4001
- this.smartToggleService.openChange.pipe(takeUntil(this.destroyed$.asObservable())).subscribe(openState => {
4002
- if (openState) {
4003
- this.focusFirstButton();
4004
- }
4005
- });
4216
+ /**
4217
+ * Compares two sort state objects for equality.
4218
+ * Returns true if they are the same reference, both null/undefined,
4219
+ * or if both comparator and reverse flag match.
4220
+ *
4221
+ * @typeParam T - Type of the row data.
4222
+ * @param a - First sort state or null.
4223
+ * @param b - Second sort state or null.
4224
+ * @returns Whether both sort states are equal.
4225
+ */
4226
+ function areSortStatesEqual(a, b) {
4227
+ if (a === b) {
4228
+ return true;
4006
4229
  }
4007
- focusFirstButton() {
4008
- this.zone.runOutsideAngular(() => setTimeout(() => {
4009
- const firstButton = document.querySelector('button.action-item');
4010
- if (firstButton) {
4011
- firstButton.focus();
4012
- }
4013
- }));
4230
+ if (!a || !b) {
4231
+ return !a && !b;
4014
4232
  }
4015
- closeOverflowContent(event) {
4016
- this.smartToggleService.toggleWithEvent(event);
4233
+ return a.reverse === b.reverse && a.comparator === b.comparator;
4234
+ }
4235
+ /**
4236
+ * Performs a shallow comparison of two filter value arrays.
4237
+ * Treats undefined as an empty array. Order and reference equality of entries matter.
4238
+ *
4239
+ * @param a - First array of filter values or undefined.
4240
+ * @param b - Second array of filter values or undefined.
4241
+ * @returns Whether both arrays have the same length and elements.
4242
+ */
4243
+ function areFilterValuesEqual(a, b) {
4244
+ const arrayA = a || [];
4245
+ const arrayB = b || [];
4246
+ if (arrayA.length !== arrayB.length) {
4247
+ return false;
4017
4248
  }
4018
- ngOnDestroy() {
4019
- this.destroyed$.next();
4020
- this.destroyed$.complete();
4249
+ for (let i = 0; i < arrayA.length; i++) {
4250
+ if (arrayA[i] !== arrayB[i]) {
4251
+ return false;
4252
+ }
4021
4253
  }
4022
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableActionOverflow, deps: [{ token: i2.ClrPopoverToggleService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
4023
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: ClrTreetableActionOverflow, isStandalone: false, selector: "clr-tt-action-overflow", inputs: { empty: "empty" }, host: { attributes: { "role": "cell" }, properties: { "class.treetable-row-actions": "true", "class.treetable-cell": "true" } }, providers: [ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService], ngImport: i0, template: `
4024
- <ng-container *ngIf="!empty">
4025
- <button class="treetable-action-trigger" clrPopoverAnchor clrPopoverOpenCloseButton>
4026
- <cds-icon shape="ellipsis-vertical"></cds-icon>
4027
- </button>
4028
- <div
4029
- class="datagrid-action-overflow"
4030
- clrFocusTrap
4031
- (click)="closeOverflowContent($event)"
4032
- *clrPopoverContent="false; at: smartPosition; outsideClickToClose: true; scrollToClose: true"
4033
- >
4034
- <ng-content></ng-content>
4035
- </div>
4036
- </ng-container>
4037
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: i2.ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: i2.ÇlrClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: i2.ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }] }); }
4254
+ return true;
4255
+ }
4256
+ /**
4257
+ * Compares two treetable states (sort and filters) for equality.
4258
+ *
4259
+ * @typeParam T - Type of the tree node values.
4260
+ * @param prev - Previous state.
4261
+ * @param curr - Current state.
4262
+ * @returns Whether both states are considered equal.
4263
+ */
4264
+ function areTreetableStatesEqual(prev, curr) {
4265
+ return areSortStatesEqual(prev.sort, curr.sort) && areFilterValuesEqual(prev.filters, curr.filters);
4038
4266
  }
4039
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableActionOverflow, decorators: [{
4040
- type: Component,
4041
- args: [{
4042
- selector: 'clr-tt-action-overflow',
4043
- providers: [ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService],
4044
- template: `
4045
- <ng-container *ngIf="!empty">
4046
- <button class="treetable-action-trigger" clrPopoverAnchor clrPopoverOpenCloseButton>
4047
- <cds-icon shape="ellipsis-vertical"></cds-icon>
4048
- </button>
4049
- <div
4050
- class="datagrid-action-overflow"
4051
- clrFocusTrap
4052
- (click)="closeOverflowContent($event)"
4053
- *clrPopoverContent="false; at: smartPosition; outsideClickToClose: true; scrollToClose: true"
4054
- >
4055
- <ng-content></ng-content>
4056
- </div>
4057
- </ng-container>
4058
- `,
4059
- host: {
4060
- '[class.treetable-row-actions]': 'true',
4061
- '[class.treetable-cell]': 'true',
4062
- role: 'cell',
4063
- },
4064
- standalone: false,
4065
- }]
4066
- }], ctorParameters: () => [{ type: i2.ClrPopoverToggleService }, { type: i0.NgZone }], propDecorators: { empty: [{
4067
- type: Input
4068
- }] } });
4069
4267
 
4070
4268
  /*
4071
4269
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4072
4270
  * This software is released under MIT license.
4073
4271
  * The full license information can be found in LICENSE in the root directory of this project.
4074
4272
  */
4075
- ClarityIcons.addIcons(angleIcon);
4076
- class ClrTreetableRow {
4273
+ class TreetableDataStateService {
4077
4274
  constructor() {
4078
- this.selection = inject(Selection);
4079
- this._cdr = inject(ChangeDetectorRef);
4080
- this._destroyRef = inject(DestroyRef);
4081
- this._selected = false;
4082
- this.shouldAnimate = signal(false);
4083
- this.expanded = false;
4084
- this.clickable = true;
4085
- this.expandable = false;
4086
- this.clrTtItem = input();
4087
- this.hasActionOverflow = new EventEmitter();
4088
- this.expandedChange = new EventEmitter();
4089
- this.selectedChanged = new EventEmitter(false);
4090
- this.showActionOverflow = false;
4091
- this.showEmptyActionOverflow = false;
4092
- this.showClickClass = false;
4093
- this.SelectionType = SelectionType;
4094
- }
4095
- set actionOverflow(actionOverflow) {
4096
- this.showActionOverflow = !!actionOverflow;
4097
- this.showEmptyActionOverflow = !this.showActionOverflow;
4098
- this.hasActionOverflow.emit(this.showActionOverflow);
4099
- }
4100
- ngOnInit() {
4101
- this.showClickClass = this.expandable && this.clickable;
4102
- // We need to trigger change detection when the checkbox in overall treetable is clicked
4103
- // because of ChangeDetectionStrategy.OnPush
4104
- this.selection.allSelectedChange.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
4105
- this._cdr.markForCheck();
4275
+ this._filters = inject((Filters));
4276
+ this._sort = inject((Sort));
4277
+ this._dataSource = signal(undefined);
4278
+ this._stickyIndeterminate = signal(false);
4279
+ this._itemsExternallySelected = signal([]);
4280
+ this._treetableNodes = computed(() => {
4281
+ const dataSource = this._dataSource();
4282
+ const stickyIndeterminate = this._stickyIndeterminate();
4283
+ return dataSource
4284
+ ? dataSource.items.map(item => mapToInternalTree(item, dataSource.getChildren, stickyIndeterminate))
4285
+ : [];
4286
+ });
4287
+ this._filteredNodes = computed(() => {
4288
+ const treetableNodes = this._treetableNodes();
4289
+ const activeFilters = this._filters.activeFilters();
4290
+ const hasActiveFilters = this._filters.hasActiveFilters();
4291
+ if (!hasActiveFilters) {
4292
+ return treetableNodes;
4293
+ }
4294
+ return this.filterTreeRecursively(treetableNodes, activeFilters);
4295
+ });
4296
+ this.displayedNodes = computed(() => {
4297
+ const nodes = this._filteredNodes();
4298
+ const { comparator } = this._sort.sortState();
4299
+ if (!comparator) {
4300
+ return nodes;
4301
+ }
4302
+ return this.sortTreeRecursively(nodes);
4303
+ });
4304
+ this.areAllNodesSelected = computed(() => this.displayedNodes().every(node => node.selected() === ClrTreetableSelectedState.SELECTED));
4305
+ this.selectedNodes = computed(() => {
4306
+ const result = [];
4307
+ this.traverseTreeNodes(this.displayedNodes(), (node) => {
4308
+ if (node.selected() === ClrTreetableSelectedState.SELECTED) {
4309
+ result.push(node.value);
4310
+ }
4311
+ });
4312
+ return result;
4313
+ });
4314
+ this.changes$ = combineLatest([
4315
+ this._filters.changes$,
4316
+ this._sort.changes$,
4317
+ ]).pipe(map$1(([filterValues, sortState]) => ({
4318
+ sort: sortState.comparator ? { comparator: sortState.comparator, reverse: sortState.reverse } : null,
4319
+ filters: filterValues,
4320
+ })), skip(1), auditTime(500), distinctUntilChanged((a, b) => areTreetableStatesEqual(a, b)), shareReplay(1));
4321
+ // Externally selected has to be handled as a signal, as it is a synchronous change. Simply using a subject instead
4322
+ // of a signal results in errors.
4323
+ const externallySelectedItems$ = toObservable(this._itemsExternallySelected).pipe(map$1(items => new Set(items)));
4324
+ const treetableNodes$ = toObservable(this._treetableNodes).pipe(filter$1(nodes => nodes.length > 0));
4325
+ const handleExternalSelect$ = combineLatest([externallySelectedItems$, treetableNodes$]);
4326
+ // This stream handles the external setting of selected nodes. Typically, this will run only once in the
4327
+ // beginning, if some nodes need to be selected from the start (e.g. restoring treetable state from local storage).
4328
+ // The subscribe function only runs, if the selectedItems differ in length to the currently selectedNodes.
4329
+ handleExternalSelect$
4330
+ .pipe(map$1(([externallySelectedItems, treetableNodes]) => ({
4331
+ externallySelectedItems: externallySelectedItems,
4332
+ nodes: treetableNodes,
4333
+ selectedNodes: this.selectedNodes(),
4334
+ })), filter$1(({ externallySelectedItems, selectedNodes }) => externallySelectedItems.size !== selectedNodes.length), takeUntilDestroyed())
4335
+ .subscribe(({ externallySelectedItems, nodes }) => {
4336
+ if (externallySelectedItems.size === 0) {
4337
+ this.setSelectionForDisplayedNodes(ClrTreetableSelectedState.UNSELECTED);
4338
+ return;
4339
+ }
4340
+ this.traverseTreeNodes(nodes, (node) => {
4341
+ if (externallySelectedItems.has(node.value)) {
4342
+ node.setSelected(ClrTreetableSelectedState.SELECTED);
4343
+ // Remove node and all descendants from set to speed up external selection.
4344
+ externallySelectedItems.delete(node.value);
4345
+ for (const descendant of node.getFlatDescendants() ?? []) {
4346
+ externallySelectedItems.delete(descendant.value);
4347
+ }
4348
+ }
4349
+ }, () => externallySelectedItems.size > 0);
4106
4350
  });
4107
4351
  }
4108
- onExpandCollapseClick() {
4109
- // Only animate on user click (not on sorting or initial rendering)
4110
- this.shouldAnimate.set(true);
4111
- this.toggleExpand();
4112
- // Remove .animate after animation to prevent unwanted transitions
4113
- setTimeout(() => {
4114
- this.shouldAnimate.set(false);
4115
- }, 350);
4352
+ setDataSource(items, getChildren) {
4353
+ this._dataSource.set({ items, getChildren });
4116
4354
  }
4117
- toggle(selected = !this.selected) {
4118
- if (selected !== this.selected) {
4119
- this.selected = selected;
4120
- this.selectedChanged.emit(selected);
4121
- }
4355
+ setExternallySelectedItems(items) {
4356
+ this._itemsExternallySelected.set(items);
4122
4357
  }
4123
- toggleExpand() {
4124
- if (this.expandable) {
4125
- this.expanded = !this.expanded;
4126
- this.expandedChange.emit(this.expanded);
4127
- }
4358
+ setStickyIndeterminate(value) {
4359
+ this._stickyIndeterminate.set(value);
4128
4360
  }
4129
- onRowClick(event) {
4130
- if (this.clickable && !event.target.closest('.treetable-action-trigger')) {
4131
- this.onExpandCollapseClick();
4132
- }
4361
+ toggleSelectionForDisplayedNodes() {
4362
+ const nextState = this.areAllNodesSelected()
4363
+ ? ClrTreetableSelectedState.UNSELECTED
4364
+ : ClrTreetableSelectedState.SELECTED;
4365
+ this.setSelectionForDisplayedNodes(nextState);
4133
4366
  }
4134
- onCaretClick() {
4135
- if (!this.clickable) {
4136
- this.onExpandCollapseClick();
4367
+ setSelectionForDisplayedNodes(state) {
4368
+ for (const node of this.displayedNodes()) {
4369
+ node.setSelected(state);
4137
4370
  }
4138
4371
  }
4139
- get selected() {
4140
- if (this.selection.selectionType === SelectionType.None) {
4141
- return this._selected;
4142
- }
4143
- else {
4144
- return this.selection.isSelected(this.clrTtItem());
4372
+ /**
4373
+ * Recursively filters the provided <code>ClrTreetableTreeNodes</code>. It returns the lowest depth nodes of the
4374
+ * provided nodes, that pass all the filters and it's ancestors. The method returns a cloned subset of the provided nodes.
4375
+ *
4376
+ * @param nodes The nodes to filter.
4377
+ * @param activeFilters The currently active filters that have to be passed.
4378
+ * @param parent The parent node to set for the recursive filtering.
4379
+ * @private
4380
+ */
4381
+ filterTreeRecursively(nodes, activeFilters, parent = null) {
4382
+ const passesAllFilters = (node) => activeFilters.every(f => f.accepts(node.value));
4383
+ const result = [];
4384
+ for (const original of nodes) {
4385
+ const filteredChildren = this.filterTreeRecursively(original.children, activeFilters, null);
4386
+ if (filteredChildren.length > 0 || passesAllFilters(original)) {
4387
+ // A new instance is necessary here, for the selection state to still work
4388
+ const newNode = new ClrTreetableTreeNode(original.value, parent, [], this._stickyIndeterminate());
4389
+ newNode.children = filteredChildren.map(child => {
4390
+ child.parent = newNode;
4391
+ return child;
4392
+ });
4393
+ result.push(newNode);
4394
+ }
4145
4395
  }
4396
+ return result;
4146
4397
  }
4147
- set selected(value) {
4148
- this.selection.setSelected(this.clrTtItem(), value);
4398
+ sortTreeRecursively(nodes) {
4399
+ const sortedNodes = [...nodes].sort((nodeA, nodeB) => this._sort.compare(nodeA.value, nodeB.value));
4400
+ return sortedNodes.map(node => {
4401
+ if (!node.isLeaf) {
4402
+ const cloned = Object.assign(Object.create(Object.getPrototypeOf(node)), node);
4403
+ cloned.children = this.sortTreeRecursively(node.children);
4404
+ return cloned;
4405
+ }
4406
+ return node;
4407
+ });
4149
4408
  }
4150
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRow, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4151
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetableRow, isStandalone: false, selector: "clr-tt-row", inputs: { expanded: { classPropertyName: "expanded", publicName: "clrExpanded", isSignal: false, isRequired: false, transformFunction: null }, clickable: { classPropertyName: "clickable", publicName: "clrClickable", isSignal: false, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "clrExpandable", isSignal: false, isRequired: false, transformFunction: null }, clrTtItem: { classPropertyName: "clrTtItem", publicName: "clrTtItem", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hasActionOverflow: "hasActionOverflow", expandedChange: "clrExpandedChange", selectedChanged: "clrTtSelectedChange" }, host: { properties: { "class.treetable-row-wrapper": "true", "class.treetable-selected": "selected" } }, queries: [{ propertyName: "actionOverflow", first: true, predicate: ClrTreetableActionOverflow, descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div\n [ngClass]=\"{'clr-row-clickable': showClickClass, 'treetable-selected': selected}\"\n class=\"clr-tt-node-content treetable-row\"\n (click)=\"onRowClick($event)\"\n>\n @if(selection.selectionType === SelectionType.Multi){\n <div class=\"clr-checkbox-wrapper treetable-row-selection treetable-cell\">\n <input type=\"checkbox\" [ngModel]=\"selected\" (ngModelChange)=\"toggle($event)\" (click)=\"$event.stopPropagation()\" />\n </div>\n }\n\n <ng-content select=\"clr-tt-action-overflow\"></ng-content>\n <clr-tt-action-overflow *ngIf=\"showActionOverflow && showEmptyActionOverflow\" [empty]=\"true\"></clr-tt-action-overflow>\n <div class=\"treetable-scrolling-cells\">\n <div class=\"treetable-expandable-caret\" *ngIf=\"expandable\">\n <button type=\"button\" class=\"treetable-expandable-caret-button\" (click)=\"onCaretClick()\">\n <cds-icon\n shape=\"angle\"\n [attr.direction]=\"expanded ? 'down' : 'right'\"\n class=\"treetable-expandable-caret-icon\"\n ></cds-icon>\n </button>\n </div>\n\n <ng-content select=\"clr-tt-cell\"></ng-content>\n </div>\n</div>\n\n<div\n class=\"treetable-row-animation-container\"\n [class.expanded]=\"expanded\"\n [class.collapsed]=\"!expanded\"\n [class.animate]=\"shouldAnimate()\"\n>\n <div class=\"treetable-row-animation-wrapper\">\n <ng-content select=\"clr-tt-row\"></ng-content>\n </div>\n</div>\n", styles: [".treetable-row-animation-container.expanded{display:grid;grid-template-rows:1fr;opacity:1}.treetable-row-animation-container.collapsed{display:none;grid-template-rows:0fr;opacity:0}.treetable-row-animation-container.animate{transition:grid-template-rows .3s ease,opacity .3s ease,display .3s ease allow-discrete}@starting-style{.treetable-row-animation-container.animate.expanded{grid-template-rows:0fr;opacity:0}}@starting-style{.treetable-row-animation-container.animate.collapsed{grid-template-rows:1fr;opacity:1}}.treetable-row-animation-wrapper{min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: i3$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClrTreetableActionOverflow, selector: "clr-tt-action-overflow", inputs: ["empty"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4409
+ traverseTreeNodes(nodes, callBackFn, breakCondition = () => true) {
4410
+ for (const node of nodes) {
4411
+ callBackFn(node);
4412
+ if (!node.isLeaf && breakCondition(node)) {
4413
+ this.traverseTreeNodes(node.children, callBackFn, breakCondition);
4414
+ }
4415
+ }
4416
+ }
4417
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableDataStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4418
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableDataStateService }); }
4152
4419
  }
4153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableRow, decorators: [{
4154
- type: Component,
4155
- args: [{ selector: 'clr-tt-row', host: { '[class.treetable-row-wrapper]': 'true', '[class.treetable-selected]': 'selected' }, standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div\n [ngClass]=\"{'clr-row-clickable': showClickClass, 'treetable-selected': selected}\"\n class=\"clr-tt-node-content treetable-row\"\n (click)=\"onRowClick($event)\"\n>\n @if(selection.selectionType === SelectionType.Multi){\n <div class=\"clr-checkbox-wrapper treetable-row-selection treetable-cell\">\n <input type=\"checkbox\" [ngModel]=\"selected\" (ngModelChange)=\"toggle($event)\" (click)=\"$event.stopPropagation()\" />\n </div>\n }\n\n <ng-content select=\"clr-tt-action-overflow\"></ng-content>\n <clr-tt-action-overflow *ngIf=\"showActionOverflow && showEmptyActionOverflow\" [empty]=\"true\"></clr-tt-action-overflow>\n <div class=\"treetable-scrolling-cells\">\n <div class=\"treetable-expandable-caret\" *ngIf=\"expandable\">\n <button type=\"button\" class=\"treetable-expandable-caret-button\" (click)=\"onCaretClick()\">\n <cds-icon\n shape=\"angle\"\n [attr.direction]=\"expanded ? 'down' : 'right'\"\n class=\"treetable-expandable-caret-icon\"\n ></cds-icon>\n </button>\n </div>\n\n <ng-content select=\"clr-tt-cell\"></ng-content>\n </div>\n</div>\n\n<div\n class=\"treetable-row-animation-container\"\n [class.expanded]=\"expanded\"\n [class.collapsed]=\"!expanded\"\n [class.animate]=\"shouldAnimate()\"\n>\n <div class=\"treetable-row-animation-wrapper\">\n <ng-content select=\"clr-tt-row\"></ng-content>\n </div>\n</div>\n", styles: [".treetable-row-animation-container.expanded{display:grid;grid-template-rows:1fr;opacity:1}.treetable-row-animation-container.collapsed{display:none;grid-template-rows:0fr;opacity:0}.treetable-row-animation-container.animate{transition:grid-template-rows .3s ease,opacity .3s ease,display .3s ease allow-discrete}@starting-style{.treetable-row-animation-container.animate.expanded{grid-template-rows:0fr;opacity:0}}@starting-style{.treetable-row-animation-container.animate.collapsed{grid-template-rows:1fr;opacity:1}}.treetable-row-animation-wrapper{min-height:0;overflow:hidden}\n"] }]
4156
- }], propDecorators: { expanded: [{
4157
- type: Input,
4158
- args: ['clrExpanded']
4159
- }], clickable: [{
4160
- type: Input,
4161
- args: ['clrClickable']
4162
- }], expandable: [{
4163
- type: Input,
4164
- args: ['clrExpandable']
4165
- }], hasActionOverflow: [{
4166
- type: Output
4167
- }], expandedChange: [{
4168
- type: Output,
4169
- args: ['clrExpandedChange']
4170
- }], selectedChanged: [{
4171
- type: Output,
4172
- args: ['clrTtSelectedChange']
4173
- }], actionOverflow: [{
4174
- type: ContentChild,
4175
- args: [ClrTreetableActionOverflow]
4176
- }] } });
4420
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableDataStateService, decorators: [{
4421
+ type: Injectable
4422
+ }], ctorParameters: () => [] });
4177
4423
 
4178
4424
  /*
4179
4425
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4180
4426
  * This software is released under MIT license.
4181
4427
  * The full license information can be found in LICENSE in the root directory of this project.
4182
4428
  */
4183
- class TreetableItemsDirective {
4184
- get clrTtItems() {
4185
- return this.ttItems();
4186
- }
4187
- set clrTtItems(items) {
4188
- if (items == null || items.length === 0) {
4189
- return;
4190
- }
4191
- this._items.addItems(items);
4192
- if (this._sort.comparator) {
4193
- this._cdr.detach();
4194
- items.sort((a, b) => this._sort.compare(a, b)); // Sort in place
4195
- this._cdr.reattach();
4196
- }
4197
- this.ttItems.set(items);
4198
- }
4199
- set trackBy(value) {
4200
- this._iterableProxy.ngForTrackBy = value;
4201
- }
4429
+ class ClrTreetable {
4202
4430
  constructor() {
4203
- this._items = inject((Items));
4204
- this._sort = inject((Sort));
4205
- this._template = inject((TemplateRef));
4206
- this._differs = inject(IterableDiffers);
4207
- this._vcr = inject(ViewContainerRef);
4208
- this._cdr = inject(ChangeDetectorRef);
4209
- this.ttItems = signal([]);
4210
- this._iterableProxy = new NgForOf(this._vcr, this._template, this._differs);
4431
+ this._dataStateService = inject((TreetableDataStateService));
4432
+ this._recursionService = inject((ClrTreetableRecursionService));
4433
+ this.clrClickableRows = input(true);
4434
+ this.clrHideHeader = input(false);
4435
+ this.clrTtLoading = input(false);
4436
+ this.clrTtSelected = input(undefined);
4437
+ this.clrTtAutoParentSelection = input(true);
4438
+ this.clrTtSelectedChange = outputFromObservable(toObservable(this._dataStateService.selectedNodes));
4439
+ this.clrTtRefresh = outputFromObservable(this._dataStateService.changes$);
4440
+ this._ttRows = contentChildren(ClrTreetableRow, { descendants: true });
4441
+ this._actionOverflow = contentChildren(ClrTreetableActionOverflow, { descendants: true });
4442
+ this.empty = computed(() => !this._ttRows() || this._ttRows().length === 0);
4443
+ this.displayedNodes = this._dataStateService.displayedNodes;
4444
+ this.isRecursionMode = this._recursionService.isRecursionMode;
4445
+ this.selectionType = computed(() => (this.clrTtSelected() ? SelectionType.Multi : SelectionType.None));
4446
+ this.showSelection = computed(() => this.selectionType() === SelectionType.Multi);
4447
+ this.areAllRowsSelected = computed(() => this._dataStateService.areAllNodesSelected());
4448
+ this.hasActionOverflow = computed(() => this._actionOverflow()?.length > 0);
4211
4449
  effect(() => {
4212
- const newItems = this.ttItems();
4213
- if (newItems) {
4214
- this._iterableProxy.ngForOf = newItems;
4215
- this._iterableProxy.ngDoCheck();
4450
+ const selectedItems = this.clrTtSelected();
4451
+ if (selectedItems) {
4452
+ this._dataStateService.setExternallySelectedItems(selectedItems);
4216
4453
  }
4217
4454
  });
4455
+ effect(() => {
4456
+ this._dataStateService.setStickyIndeterminate(!this.clrTtAutoParentSelection());
4457
+ });
4218
4458
  }
4219
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableItemsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4220
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: TreetableItemsDirective, isStandalone: false, selector: "[clrTtItems]", inputs: { clrTtItems: "clrTtItems", trackBy: ["clrTtItemsTrackBy", "trackBy"] }, ngImport: i0 }); }
4459
+ toggleSelectAll() {
4460
+ this._dataStateService.toggleSelectionForDisplayedNodes();
4461
+ }
4462
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetable, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4463
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetable, isStandalone: false, selector: "clr-treetable", inputs: { clrClickableRows: { classPropertyName: "clrClickableRows", publicName: "clrClickableRows", isSignal: true, isRequired: false, transformFunction: null }, clrHideHeader: { classPropertyName: "clrHideHeader", publicName: "clrHideHeader", isSignal: true, isRequired: false, transformFunction: null }, clrTtLoading: { classPropertyName: "clrTtLoading", publicName: "clrTtLoading", isSignal: true, isRequired: false, transformFunction: null }, clrTtSelected: { classPropertyName: "clrTtSelected", publicName: "clrTtSelected", isSignal: true, isRequired: false, transformFunction: null }, clrTtAutoParentSelection: { classPropertyName: "clrTtAutoParentSelection", publicName: "clrTtAutoParentSelection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clrTtSelectedChange: "clrTtSelectedChange", clrTtRefresh: "clrTtRefresh" }, host: { properties: { "class.empty": "empty()", "class.treetable-host": "true" } }, providers: [TREETABLE_RECURSION_SERVICE_PROVIDER, TreetableDataStateService, Sort, Filters], queries: [{ propertyName: "_ttRows", predicate: ClrTreetableRow, descendants: true, isSignal: true }, { propertyName: "_actionOverflow", predicate: ClrTreetableActionOverflow, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div class=\"treetable\">\n <div class=\"treetable-grid\" role=\"grid\">\n <div class=\"treetable-header\" role=\"rowgroup\" [class.hide-header]=\"clrHideHeader()\">\n @if (showSelection() && !empty()) {\n <div class=\"clr-checkbox-wrapper treetable-row-selection treetable-column\" role=\"row\">\n <input\n type=\"checkbox\"\n data-testId=\"clrTtSelectAll\"\n [checked]=\"areAllRowsSelected()\"\n (change)=\"toggleSelectAll()\"\n />\n </div>\n }\n\n <div *ngIf=\"hasActionOverflow()\" class=\"treetable-row-actions treetable-column\">&nbsp;</div>\n <div class=\"treetable-row-scrollable\" role=\"row\">\n <ng-content select=\"clr-tt-column\" />\n </div>\n </div>\n <div class=\"treetable-body\">\n @if (isRecursionMode()) {\n <clr-tt-recursive-rows [children]=\"displayedNodes()\" />\n } @else {\n <ng-content select=\"clr-tt-row\" />\n } @if (empty()) {\n <ng-content select=\"clr-tt-placeholder\" />\n }\n </div>\n </div>\n @if (clrTtLoading()) {\n <div class=\"treetable-spinner\">\n <clr-spinner clrMedium />\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }, { kind: "component", type: ClrTreetableRecursiveRows, selector: "clr-tt-recursive-rows", inputs: ["parent", "children"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4221
4464
  }
4222
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableItemsDirective, decorators: [{
4223
- type: Directive,
4224
- args: [{
4225
- selector: '[clrTtItems]',
4226
- standalone: false,
4227
- }]
4228
- }], ctorParameters: () => [], propDecorators: { clrTtItems: [{
4229
- type: Input
4230
- }], trackBy: [{
4231
- type: Input,
4232
- args: ['clrTtItemsTrackBy']
4233
- }] } });
4465
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetable, decorators: [{
4466
+ type: Component,
4467
+ args: [{ selector: 'clr-treetable', host: { '[class.empty]': 'empty()', '[class.treetable-host]': 'true' }, providers: [TREETABLE_RECURSION_SERVICE_PROVIDER, TreetableDataStateService, Sort, Filters], changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div class=\"treetable\">\n <div class=\"treetable-grid\" role=\"grid\">\n <div class=\"treetable-header\" role=\"rowgroup\" [class.hide-header]=\"clrHideHeader()\">\n @if (showSelection() && !empty()) {\n <div class=\"clr-checkbox-wrapper treetable-row-selection treetable-column\" role=\"row\">\n <input\n type=\"checkbox\"\n data-testId=\"clrTtSelectAll\"\n [checked]=\"areAllRowsSelected()\"\n (change)=\"toggleSelectAll()\"\n />\n </div>\n }\n\n <div *ngIf=\"hasActionOverflow()\" class=\"treetable-row-actions treetable-column\">&nbsp;</div>\n <div class=\"treetable-row-scrollable\" role=\"row\">\n <ng-content select=\"clr-tt-column\" />\n </div>\n </div>\n <div class=\"treetable-body\">\n @if (isRecursionMode()) {\n <clr-tt-recursive-rows [children]=\"displayedNodes()\" />\n } @else {\n <ng-content select=\"clr-tt-row\" />\n } @if (empty()) {\n <ng-content select=\"clr-tt-placeholder\" />\n }\n </div>\n </div>\n @if (clrTtLoading()) {\n <div class=\"treetable-spinner\">\n <clr-spinner clrMedium />\n </div>\n }\n</div>\n" }]
4468
+ }], ctorParameters: () => [] });
4234
4469
 
4235
4470
  /*
4236
4471
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4237
4472
  * This software is released under MIT license.
4238
4473
  * The full license information can be found in LICENSE in the root directory of this project.
4239
4474
  */
4240
- class ClrTreetable {
4475
+ var ClrTreetableSortOrder;
4476
+ (function (ClrTreetableSortOrder) {
4477
+ ClrTreetableSortOrder[ClrTreetableSortOrder["UNSORTED"] = 0] = "UNSORTED";
4478
+ ClrTreetableSortOrder[ClrTreetableSortOrder["ASC"] = 1] = "ASC";
4479
+ ClrTreetableSortOrder[ClrTreetableSortOrder["DESC"] = -1] = "DESC";
4480
+ })(ClrTreetableSortOrder || (ClrTreetableSortOrder = {}));
4481
+
4482
+ /*
4483
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4484
+ * This software is released under MIT license.
4485
+ * The full license information can be found in LICENSE in the root directory of this project.
4486
+ */
4487
+ class ClrTreetableColumn {
4241
4488
  constructor() {
4242
- this.selection = inject((Selection));
4243
- this._items = inject((Items));
4244
- this._destroyRef = inject(DestroyRef);
4245
- this.cdr = inject(ChangeDetectorRef);
4246
- this.clrClickableRows = true;
4247
- this.hideHeader = false;
4248
- this.selectedChanged = new EventEmitter(false);
4249
- this.empty = true;
4250
- this.hasActionOverflow = false;
4251
- this.SelectionType = SelectionType;
4252
- }
4253
- set selected(value) {
4254
- if (value) {
4255
- this.selection.selectionType = SelectionType.Multi;
4256
- }
4257
- else {
4258
- this.selection.selectionType = SelectionType.None;
4259
- }
4260
- this.selection.updateCurrent(value, false);
4261
- }
4262
- set ttRows(items) {
4263
- this._ttRows = items;
4264
- this.hasActionOverflow = false;
4265
- this.initClickableRows();
4266
- this.initEmpty();
4267
- this.initActionOverflow();
4268
- }
4269
- ngAfterViewInit() {
4270
- this.selection.change.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(items => {
4271
- this.selectedChanged.emit(items);
4489
+ this._sort = inject((Sort));
4490
+ this.clrTtSortBy = input(null);
4491
+ this.clrTtSortOrder = input(ClrTreetableSortOrder.UNSORTED);
4492
+ this.clrTtSortOrderChange = output();
4493
+ this._internalSortOrder = computed(() => {
4494
+ const sortState = this._sort.sortState();
4495
+ const sortBy = this.clrTtSortBy();
4496
+ if (sortBy == null || sortState.comparator !== sortBy) {
4497
+ return ClrTreetableSortOrder.UNSORTED;
4498
+ }
4499
+ return sortState.reverse ? ClrTreetableSortOrder.DESC : ClrTreetableSortOrder.ASC;
4272
4500
  });
4273
- //_items changed, therefore we need to update the ttItems in the directives
4274
- // in order to display them right again -> e.g when sorting changed
4275
- this._items.change.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((allItems) => {
4276
- const directives = this.iterator.toArray();
4277
- directives.forEach((directive, index) => {
4278
- if (allItems[index]) {
4279
- const sortedItems = [...allItems[index]];
4280
- directive.ttItems.set(sortedItems);
4281
- }
4282
- });
4501
+ this.isSortable = computed(() => !!this.clrTtSortBy());
4502
+ this.sortDirection = computed(() => {
4503
+ const order = this._internalSortOrder();
4504
+ if (order === ClrTreetableSortOrder.UNSORTED) {
4505
+ return null;
4506
+ }
4507
+ return order === ClrTreetableSortOrder.DESC ? 'down' : 'up';
4508
+ });
4509
+ this.ariaSort = computed(() => {
4510
+ switch (this._internalSortOrder()) {
4511
+ case ClrTreetableSortOrder.ASC:
4512
+ return 'ascending';
4513
+ case ClrTreetableSortOrder.DESC:
4514
+ return 'descending';
4515
+ case ClrTreetableSortOrder.UNSORTED:
4516
+ default:
4517
+ return 'none';
4518
+ }
4519
+ });
4520
+ // Handle incoming sort order changes
4521
+ const sortOrder$ = toObservable(this.clrTtSortOrder);
4522
+ const sortBy$ = toObservable(this.clrTtSortBy);
4523
+ const handleExternalSortOrderChange$ = combineLatest([sortOrder$, sortBy$]);
4524
+ // CombineLatest does not contain sortState, because only external sort changes should trigger this stream.
4525
+ // Only react to external sort order changes, if no current sortState exists, or this column is responsible for it.
4526
+ handleExternalSortOrderChange$
4527
+ .pipe(map$1(([sortOrder, comparator]) => ({
4528
+ sortOrder,
4529
+ comparator,
4530
+ sortState: this._sort.sortState(),
4531
+ })), filter$1(({ comparator, sortState }) => !!comparator && (sortState.comparator == null || sortState.comparator === comparator)), map$1(({ sortOrder, comparator, sortState }) => ({
4532
+ sortOrder: sortOrder,
4533
+ isCurrentActiveComparator: sortState.comparator === comparator,
4534
+ reverse: sortState.reverse,
4535
+ })), takeUntilDestroyed())
4536
+ .subscribe(({ sortOrder, isCurrentActiveComparator, reverse }) => {
4537
+ switch (sortOrder) {
4538
+ case ClrTreetableSortOrder.ASC:
4539
+ if (!isCurrentActiveComparator || (isCurrentActiveComparator && reverse)) {
4540
+ this.sort(false);
4541
+ }
4542
+ break;
4543
+ case ClrTreetableSortOrder.DESC:
4544
+ if (!isCurrentActiveComparator || (isCurrentActiveComparator && !reverse)) {
4545
+ this.sort(true);
4546
+ }
4547
+ break;
4548
+ case ClrTreetableSortOrder.UNSORTED:
4549
+ if (isCurrentActiveComparator) {
4550
+ this._sort.clear();
4551
+ }
4552
+ break;
4553
+ }
4554
+ });
4555
+ // Emit sort order changes of the column
4556
+ effect(() => {
4557
+ const internalSortOrder = this._internalSortOrder();
4558
+ this.clrTtSortOrderChange.emit(internalSortOrder);
4283
4559
  });
4284
4560
  }
4285
- initClickableRows() {
4286
- if (this._ttRows) {
4287
- this._ttRows.forEach(ttRow => {
4288
- ttRow.clickable = this.clrClickableRows;
4289
- });
4561
+ sort(reverse) {
4562
+ const comparator = this.clrTtSortBy();
4563
+ if (!comparator) {
4564
+ return;
4290
4565
  }
4566
+ this._sort.toggle(comparator, reverse);
4291
4567
  }
4292
- initEmpty() {
4293
- this.empty = this._ttRows.length === 0;
4294
- }
4295
- initActionOverflow() {
4296
- this._ttRows.forEach(row => {
4297
- this.setActionOverflow(row.showActionOverflow);
4298
- row.hasActionOverflow.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((hasActionOverflow) => {
4299
- this.setActionOverflow(hasActionOverflow);
4300
- });
4301
- });
4568
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableColumn, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4569
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetableColumn, isStandalone: false, selector: "clr-tt-column", inputs: { clrTtSortBy: { classPropertyName: "clrTtSortBy", publicName: "clrTtSortBy", isSignal: true, isRequired: false, transformFunction: null }, clrTtSortOrder: { classPropertyName: "clrTtSortOrder", publicName: "clrTtSortOrder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clrTtSortOrderChange: "clrTtSortOrderChange" }, host: { attributes: { "role": "columnheader" }, properties: { "class.treetable-column": "true", "attr.aria-sort": "ariaSort()" } }, providers: [ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService], hostDirectives: [{ directive: i2.ClrPopoverHostDirective }], ngImport: i0, template: `
4570
+ @if (isSortable()) {
4571
+ <button type="button" class="treetable-column-title" data-testId="clrTtSortButton" (click)="sort()">
4572
+ <ng-container *ngTemplateOutlet="columnTitle" />
4573
+ @if (sortDirection()) {
4574
+ <cds-icon
4575
+ shape="arrow"
4576
+ aria-hidden="true"
4577
+ class="sort-icon"
4578
+ data-testId="clrTtSortIndicator"
4579
+ [attr.direction]="sortDirection()"
4580
+ />
4581
+ }
4582
+ </button>
4583
+ } @else {
4584
+ <div class="treetable-column-title">
4585
+ <ng-container *ngTemplateOutlet="columnTitle" />
4586
+ </div>
4302
4587
  }
4303
- setActionOverflow(hasActionOverflow) {
4304
- if (!this.hasActionOverflow && hasActionOverflow) {
4305
- this.hasActionOverflow = true;
4306
- this.cdr.markForCheck();
4307
- // setTimeout needed, as this method needs to change data which shouldn't be changed anymore in this cycle
4308
- setTimeout(() => {
4309
- if (this.hasActionOverflow) {
4310
- this._ttRows.forEach(ttRow => (ttRow.showActionOverflow = true));
4311
- }
4312
- });
4313
- }
4588
+
4589
+ <ng-content select="clr-tt-filter, clr-tt-string-filter" />
4590
+
4591
+ <ng-template #columnTitle>
4592
+ <ng-content />
4593
+ </ng-template>
4594
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4595
+ }
4596
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableColumn, decorators: [{
4597
+ type: Component,
4598
+ args: [{
4599
+ selector: 'clr-tt-column',
4600
+ providers: [ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService],
4601
+ template: `
4602
+ @if (isSortable()) {
4603
+ <button type="button" class="treetable-column-title" data-testId="clrTtSortButton" (click)="sort()">
4604
+ <ng-container *ngTemplateOutlet="columnTitle" />
4605
+ @if (sortDirection()) {
4606
+ <cds-icon
4607
+ shape="arrow"
4608
+ aria-hidden="true"
4609
+ class="sort-icon"
4610
+ data-testId="clrTtSortIndicator"
4611
+ [attr.direction]="sortDirection()"
4612
+ />
4613
+ }
4614
+ </button>
4615
+ } @else {
4616
+ <div class="treetable-column-title">
4617
+ <ng-container *ngTemplateOutlet="columnTitle" />
4618
+ </div>
4314
4619
  }
4315
- get allSelected() {
4316
- return this.selection.isAllSelected();
4620
+
4621
+ <ng-content select="clr-tt-filter, clr-tt-string-filter" />
4622
+
4623
+ <ng-template #columnTitle>
4624
+ <ng-content />
4625
+ </ng-template>
4626
+ `,
4627
+ hostDirectives: [ClrPopoverHostDirective],
4628
+ host: {
4629
+ '[class.treetable-column]': 'true',
4630
+ '[attr.aria-sort]': 'ariaSort()',
4631
+ role: 'columnheader',
4632
+ },
4633
+ changeDetection: ChangeDetectionStrategy.OnPush,
4634
+ standalone: false,
4635
+ }]
4636
+ }], ctorParameters: () => [] });
4637
+
4638
+ /*
4639
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4640
+ * This software is released under MIT license.
4641
+ * The full license information can be found in LICENSE in the root directory of this project.
4642
+ */
4643
+ class ClrTreetableFilter {
4644
+ constructor() {
4645
+ this.commonStringsService = inject(ClrCommonStringsService);
4646
+ this.smartToggleService = inject(ClrPopoverToggleService);
4647
+ this.filterProvider = inject((Filters));
4648
+ // Smart Popover
4649
+ this.smartPosition = {
4650
+ axis: ClrAxis.VERTICAL,
4651
+ side: ClrSide.AFTER,
4652
+ anchor: ClrAlignment.END,
4653
+ content: ClrAlignment.END,
4654
+ };
4655
+ this.clrTtFilter = input.required();
4656
+ this.registered = signal(undefined);
4657
+ this.open = toSignal(this.smartToggleService.openChange);
4658
+ this.active = computed(() => this.clrTtFilter()?.isActive());
4317
4659
  }
4318
- set allSelected(_) {
4319
- /**
4320
- * This is a setter but we ignore the value.
4321
- * It's strange, but it lets us have an indeterminate state where only
4322
- * some of the _items are selected.
4323
- */
4324
- this.selection.toggleAll();
4660
+ ngOnInit() {
4661
+ this.registered.set(this.filterProvider.register(this.clrTtFilter()));
4325
4662
  }
4326
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetable, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4327
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: ClrTreetable, isStandalone: false, selector: "clr-treetable", inputs: { clrClickableRows: "clrClickableRows", hideHeader: ["clrHideHeader", "hideHeader"], selected: ["clrTtSelected", "selected"] }, outputs: { selectedChanged: "clrTtSelectedChange" }, host: { properties: { "class.empty": "empty", "class.treetable-host": "true" } }, providers: [Selection, Items, Sort], queries: [{ propertyName: "ttColumns", predicate: ClrTreetableColumn, descendants: true }, { propertyName: "ttRows", predicate: ClrTreetableRow, descendants: true }, { propertyName: "iterator", predicate: TreetableItemsDirective, descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div class=\"treetable\">\n <div class=\"treetable-grid\" role=\"grid\">\n <div class=\"treetable-header\" role=\"rowgroup\" [class.hide-header]=\"hideHeader\">\n @if(selection.selectionType === SelectionType.Multi && !empty){\n <div class=\"clr-checkbox-wrapper treetable-row-selection treetable-column\" role=\"row\">\n <input type=\"checkbox\" [(ngModel)]=\"allSelected\" />\n </div>\n }\n\n <div *ngIf=\"hasActionOverflow\" class=\"treetable-row-actions treetable-column\">&nbsp;</div>\n <div class=\"treetable-row-scrollable\" role=\"row\">\n <ng-content select=\"clr-tt-column\"></ng-content>\n </div>\n </div>\n <div class=\"treetable-body\">\n <ng-content select=\"clr-tt-row\"></ng-content>\n <ng-content select=\"clr-tt-placeholder\"></ng-content>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4663
+ ngOnDestroy() {
4664
+ if (this.registered()) {
4665
+ this.registered().unregister();
4666
+ }
4667
+ }
4668
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableFilter, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4669
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.6", type: ClrTreetableFilter, isStandalone: false, selector: "clr-tt-filter", inputs: { clrTtFilter: { classPropertyName: "clrTtFilter", publicName: "clrTtFilter", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
4670
+ <button
4671
+ type="button"
4672
+ clrPopoverAnchor
4673
+ clrPopoverOpenCloseButton
4674
+ class="treetable-filter-toggle"
4675
+ data-testId="clrTtToggleFilterButton"
4676
+ [class.treetable-filter-open]="open()"
4677
+ [class.treetable-filtered]="active()"
4678
+ [attr.aria-expanded]="open()"
4679
+ >
4680
+ <cds-icon
4681
+ [attr.status]="active() ? 'info' : null"
4682
+ [attr.shape]="active() ? 'filter-grid-circle' : 'filter-grid'"
4683
+ solid
4684
+ ></cds-icon>
4685
+ </button>
4686
+
4687
+ <div
4688
+ class="treetable-filter"
4689
+ role="dialog"
4690
+ cdkTrapFocus
4691
+ *clrPopoverContent="open(); at: smartPosition; outsideClickToClose: true; scrollToClose: true"
4692
+ [attr.aria-label]="commonStringsService.keys.datagridFilterDialogAriaLabel"
4693
+ >
4694
+ <div class="treetable-filter-close-wrapper">
4695
+ <button type="button" class="close" clrPopoverCloseButton>
4696
+ <cds-icon shape="window-close" [attr.aria-label]="commonStringsService.keys.close"></cds-icon>
4697
+ </button>
4698
+ </div>
4699
+
4700
+ <ng-content></ng-content>
4701
+ </div>
4702
+ `, isInline: true, dependencies: [{ kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: i2.ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: i2.ÇlrClrPopoverCloseButton, selector: "[clrPopoverCloseButton]", outputs: ["clrPopoverOnCloseChange"] }, { kind: "directive", type: i2.ÇlrClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: i2.ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4328
4703
  }
4329
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetable, decorators: [{
4704
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableFilter, decorators: [{
4330
4705
  type: Component,
4331
- args: [{ selector: 'clr-treetable', host: { '[class.empty]': 'empty', '[class.treetable-host]': 'true' }, standalone: false, providers: [Selection, Items, Sort], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n ~ Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<div class=\"treetable\">\n <div class=\"treetable-grid\" role=\"grid\">\n <div class=\"treetable-header\" role=\"rowgroup\" [class.hide-header]=\"hideHeader\">\n @if(selection.selectionType === SelectionType.Multi && !empty){\n <div class=\"clr-checkbox-wrapper treetable-row-selection treetable-column\" role=\"row\">\n <input type=\"checkbox\" [(ngModel)]=\"allSelected\" />\n </div>\n }\n\n <div *ngIf=\"hasActionOverflow\" class=\"treetable-row-actions treetable-column\">&nbsp;</div>\n <div class=\"treetable-row-scrollable\" role=\"row\">\n <ng-content select=\"clr-tt-column\"></ng-content>\n </div>\n </div>\n <div class=\"treetable-body\">\n <ng-content select=\"clr-tt-row\"></ng-content>\n <ng-content select=\"clr-tt-placeholder\"></ng-content>\n </div>\n </div>\n</div>\n" }]
4332
- }], propDecorators: { clrClickableRows: [{
4333
- type: Input
4334
- }], hideHeader: [{
4335
- type: Input,
4336
- args: ['clrHideHeader']
4337
- }], selected: [{
4338
- type: Input,
4339
- args: ['clrTtSelected']
4340
- }], selectedChanged: [{
4341
- type: Output,
4342
- args: ['clrTtSelectedChange']
4343
- }], ttColumns: [{
4344
- type: ContentChildren,
4345
- args: [ClrTreetableColumn, { descendants: true }]
4346
- }], ttRows: [{
4347
- type: ContentChildren,
4348
- args: [ClrTreetableRow, { descendants: true }]
4349
- }], iterator: [{
4350
- type: ContentChildren,
4351
- args: [TreetableItemsDirective, { descendants: true }]
4352
- }] } });
4706
+ args: [{
4707
+ selector: 'clr-tt-filter',
4708
+ template: `
4709
+ <button
4710
+ type="button"
4711
+ clrPopoverAnchor
4712
+ clrPopoverOpenCloseButton
4713
+ class="treetable-filter-toggle"
4714
+ data-testId="clrTtToggleFilterButton"
4715
+ [class.treetable-filter-open]="open()"
4716
+ [class.treetable-filtered]="active()"
4717
+ [attr.aria-expanded]="open()"
4718
+ >
4719
+ <cds-icon
4720
+ [attr.status]="active() ? 'info' : null"
4721
+ [attr.shape]="active() ? 'filter-grid-circle' : 'filter-grid'"
4722
+ solid
4723
+ ></cds-icon>
4724
+ </button>
4725
+
4726
+ <div
4727
+ class="treetable-filter"
4728
+ role="dialog"
4729
+ cdkTrapFocus
4730
+ *clrPopoverContent="open(); at: smartPosition; outsideClickToClose: true; scrollToClose: true"
4731
+ [attr.aria-label]="commonStringsService.keys.datagridFilterDialogAriaLabel"
4732
+ >
4733
+ <div class="treetable-filter-close-wrapper">
4734
+ <button type="button" class="close" clrPopoverCloseButton>
4735
+ <cds-icon shape="window-close" [attr.aria-label]="commonStringsService.keys.close"></cds-icon>
4736
+ </button>
4737
+ </div>
4738
+
4739
+ <ng-content></ng-content>
4740
+ </div>
4741
+ `,
4742
+ changeDetection: ChangeDetectionStrategy.OnPush,
4743
+ standalone: false,
4744
+ }]
4745
+ }] });
4353
4746
 
4354
4747
  /*
4355
4748
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
@@ -4506,7 +4899,7 @@ class TreetableMainRenderer {
4506
4899
  }
4507
4900
  ngOnInit() {
4508
4901
  fromEvent(window, 'resize')
4509
- .pipe(debounceTime$1(200))
4902
+ .pipe(debounceTime(200))
4510
4903
  .subscribe(() => this.applyMaxWidth());
4511
4904
  }
4512
4905
  ngAfterContentInit() {
@@ -4595,6 +4988,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImpor
4595
4988
  args: [ClrTreetableColumn]
4596
4989
  }] } });
4597
4990
 
4991
+ /*
4992
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4993
+ * This software is released under MIT license.
4994
+ * The full license information can be found in LICENSE in the root directory of this project.
4995
+ */
4996
+ class TreetableItemsDirective {
4997
+ constructor() {
4998
+ this._dataStateService = inject((TreetableDataStateService));
4999
+ this._recursionService = inject((ClrTreetableRecursionService));
5000
+ this._templateRef = inject((TemplateRef));
5001
+ this.clrTtItemsOf = input.required();
5002
+ this.clrTtItemsGetChildren = input.required();
5003
+ if (this._templateRef) {
5004
+ this._recursionService.setTemplate(this._templateRef);
5005
+ }
5006
+ effect(() => {
5007
+ const items = this.clrTtItemsOf();
5008
+ const getChildren = this.clrTtItemsGetChildren();
5009
+ if (items) {
5010
+ this._dataStateService.setDataSource(items, getChildren);
5011
+ }
5012
+ });
5013
+ }
5014
+ static ngTemplateContextGuard(
5015
+ // @ts-expect-error This is a valid Angular context guard.
5016
+ dir,
5017
+ // @ts-expect-error This is a valid Angular context guard.
5018
+ ctx) {
5019
+ return true;
5020
+ }
5021
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableItemsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
5022
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.6", type: TreetableItemsDirective, isStandalone: false, selector: "[clrTtItems][clrTtItemsOf]", inputs: { clrTtItemsOf: { classPropertyName: "clrTtItemsOf", publicName: "clrTtItemsOf", isSignal: true, isRequired: true, transformFunction: null }, clrTtItemsGetChildren: { classPropertyName: "clrTtItemsGetChildren", publicName: "clrTtItemsGetChildren", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
5023
+ }
5024
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TreetableItemsDirective, decorators: [{
5025
+ type: Directive,
5026
+ args: [{
5027
+ selector: '[clrTtItems][clrTtItemsOf]',
5028
+ standalone: false,
5029
+ }]
5030
+ }], ctorParameters: () => [] });
5031
+
5032
+ /*
5033
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
5034
+ * This software is released under MIT license.
5035
+ * The full license information can be found in LICENSE in the root directory of this project.
5036
+ */
5037
+ const DEBOUNCE_TIME = 300;
5038
+ class ClrTreetableStringFilter {
5039
+ constructor() {
5040
+ this.smartToggleService = inject(ClrPopoverToggleService);
5041
+ this.commonStrings = inject(ClrCommonStringsService);
5042
+ this.elementRef = inject(ElementRef);
5043
+ this.clrTtStringFilter = input.required();
5044
+ this.clrTtFilterPlaceholder = input(this.commonStrings.keys.filterItems);
5045
+ this.clrTtFilterLabel = input('');
5046
+ this.clrTtFilterValue = model();
5047
+ this._input = viewChild('input', { read: (ElementRef) });
5048
+ this._textChange$ = new Subject();
5049
+ this.filterLabel = computed(() => {
5050
+ const label = this.clrTtFilterLabel();
5051
+ if (label) {
5052
+ return label;
5053
+ }
5054
+ const columnElement = this.elementRef.nativeElement?.closest('clr-tt-column');
5055
+ const columnTitleElement = columnElement?.querySelector('.treetable-column-title');
5056
+ return this.commonStrings.parse(this.commonStrings.keys.datagridFilterLabel, {
5057
+ COLUMN: columnTitleElement?.textContent.trim() || '',
5058
+ });
5059
+ });
5060
+ // Only emits the initial value once if it exists
5061
+ this.initialValue$ = toObservable(this.clrTtFilterValue).pipe(take$1(1), filter$1(value => !!value));
5062
+ this.changes = merge(this.initialValue$, this._textChange$).pipe(debounceTime$1(DEBOUNCE_TIME), tap(input => this.clrTtFilterValue.set(input)));
5063
+ this.smartToggleService.openChange.pipe(takeUntilDestroyed()).subscribe(openChange => {
5064
+ if (openChange) {
5065
+ setTimeout(() => this._input()?.nativeElement.focus());
5066
+ }
5067
+ });
5068
+ }
5069
+ accepts(item) {
5070
+ const filterValue = this.clrTtFilterValue();
5071
+ if (!this.isActive() || !filterValue) {
5072
+ return true;
5073
+ }
5074
+ return this.clrTtStringFilter()(item, filterValue.toLowerCase());
5075
+ }
5076
+ isActive() {
5077
+ const value = this.clrTtFilterValue();
5078
+ return !!value && value.length > 0;
5079
+ }
5080
+ clearFilter() {
5081
+ this._textChange$.next('');
5082
+ }
5083
+ inputChanged(value) {
5084
+ this._textChange$.next(value);
5085
+ }
5086
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableStringFilter, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5087
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.6", type: ClrTreetableStringFilter, isStandalone: false, selector: "clr-tt-string-filter", inputs: { clrTtStringFilter: { classPropertyName: "clrTtStringFilter", publicName: "clrTtStringFilter", isSignal: true, isRequired: true, transformFunction: null }, clrTtFilterPlaceholder: { classPropertyName: "clrTtFilterPlaceholder", publicName: "clrTtFilterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, clrTtFilterLabel: { classPropertyName: "clrTtFilterLabel", publicName: "clrTtFilterLabel", isSignal: true, isRequired: false, transformFunction: null }, clrTtFilterValue: { classPropertyName: "clrTtFilterValue", publicName: "clrTtFilterValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clrTtFilterValue: "clrTtFilterValueChange" }, viewQueries: [{ propertyName: "_input", first: true, predicate: ["input"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: `
5088
+ <clr-tt-filter [clrTtFilter]="this">
5089
+ <button
5090
+ class="btn btn-sm btn-icon btn-link btn-trash"
5091
+ data-testId="clrTtStringFilterClearBtn"
5092
+ (click)="clearFilter()"
5093
+ >
5094
+ <cds-icon shape="trash"></cds-icon>
5095
+ </button>
5096
+ <clr-input-container>
5097
+ <label for="filter">{{ filterLabel() }}</label>
5098
+ <input
5099
+ #input
5100
+ clrInput
5101
+ id="filter"
5102
+ type="text"
5103
+ name="search"
5104
+ autocomplete="off"
5105
+ data-testId="clrTtStringFilterInput"
5106
+ [placeholder]="clrTtFilterPlaceholder()"
5107
+ [ngModel]="clrTtFilterValue()"
5108
+ (ngModelChange)="inputChanged($event)"
5109
+ />
5110
+ </clr-input-container>
5111
+ </clr-tt-filter>
5112
+ `, isInline: true, styles: [".btn-trash{position:absolute;top:10px;right:40px;padding:0}\n"], dependencies: [{ kind: "directive", type: i2.CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: i2.ClrLabel, selector: "label", inputs: ["id", "for"] }, { kind: "directive", type: i2.ClrInput, selector: "[clrInput]" }, { kind: "component", type: i2.ClrInputContainer, selector: "clr-input-container" }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClrTreetableFilter, selector: "clr-tt-filter", inputs: ["clrTtFilter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5113
+ }
5114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableStringFilter, decorators: [{
5115
+ type: Component,
5116
+ args: [{ selector: 'clr-tt-string-filter', template: `
5117
+ <clr-tt-filter [clrTtFilter]="this">
5118
+ <button
5119
+ class="btn btn-sm btn-icon btn-link btn-trash"
5120
+ data-testId="clrTtStringFilterClearBtn"
5121
+ (click)="clearFilter()"
5122
+ >
5123
+ <cds-icon shape="trash"></cds-icon>
5124
+ </button>
5125
+ <clr-input-container>
5126
+ <label for="filter">{{ filterLabel() }}</label>
5127
+ <input
5128
+ #input
5129
+ clrInput
5130
+ id="filter"
5131
+ type="text"
5132
+ name="search"
5133
+ autocomplete="off"
5134
+ data-testId="clrTtStringFilterInput"
5135
+ [placeholder]="clrTtFilterPlaceholder()"
5136
+ [ngModel]="clrTtFilterValue()"
5137
+ (ngModelChange)="inputChanged($event)"
5138
+ />
5139
+ </clr-input-container>
5140
+ </clr-tt-filter>
5141
+ `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, styles: [".btn-trash{position:absolute;top:10px;right:40px;padding:0}\n"] }]
5142
+ }], ctorParameters: () => [] });
5143
+
4598
5144
  /*
4599
5145
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
4600
5146
  * This software is released under MIT license.
@@ -4612,8 +5158,13 @@ const CLR_TREETABLE_DIRECTIVES = [
4612
5158
  TreetableRowRenderer,
4613
5159
  TreetableCellRenderer,
4614
5160
  TreetableItemsDirective,
5161
+ ClrTreetableFilter,
5162
+ ClrTreetableStringFilter,
4615
5163
  ];
4616
5164
  class ClrTreetableModule {
5165
+ constructor() {
5166
+ ClarityIcons.addIcons(angleIcon, arrowIcon, ellipsisVerticalIcon, filterGridCircleIcon, filterGridIcon);
5167
+ }
4617
5168
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
4618
5169
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableModule, declarations: [ClrTreetable,
4619
5170
  ClrTreetableRow,
@@ -4625,7 +5176,9 @@ class ClrTreetableModule {
4625
5176
  TreetableHeaderRenderer,
4626
5177
  TreetableRowRenderer,
4627
5178
  TreetableCellRenderer,
4628
- TreetableItemsDirective], imports: [CommonModule, ClarityModule, ReactiveFormsModule, FormsModule], exports: [ClrTreetable,
5179
+ TreetableItemsDirective,
5180
+ ClrTreetableFilter,
5181
+ ClrTreetableStringFilter, ClrTreetableRecursiveRows, ClrTreetableRowCheckbox], imports: [CommonModule, ClarityModule, ReactiveFormsModule, FormsModule], exports: [ClrTreetable,
4629
5182
  ClrTreetableRow,
4630
5183
  ClrTreetableCell,
4631
5184
  ClrTreetableColumn,
@@ -4635,17 +5188,31 @@ class ClrTreetableModule {
4635
5188
  TreetableHeaderRenderer,
4636
5189
  TreetableRowRenderer,
4637
5190
  TreetableCellRenderer,
4638
- TreetableItemsDirective] }); }
5191
+ TreetableItemsDirective,
5192
+ ClrTreetableFilter,
5193
+ ClrTreetableStringFilter] }); }
4639
5194
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableModule, imports: [CommonModule, ClarityModule, ReactiveFormsModule, FormsModule] }); }
4640
5195
  }
4641
5196
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ClrTreetableModule, decorators: [{
4642
5197
  type: NgModule,
4643
5198
  args: [{
4644
5199
  imports: [CommonModule, ClarityModule, ReactiveFormsModule, FormsModule],
4645
- declarations: [CLR_TREETABLE_DIRECTIVES],
5200
+ declarations: [CLR_TREETABLE_DIRECTIVES, ClrTreetableRecursiveRows, ClrTreetableRowCheckbox],
4646
5201
  exports: [CLR_TREETABLE_DIRECTIVES],
4647
5202
  }]
4648
- }] });
5203
+ }], ctorParameters: () => [] });
5204
+
5205
+ /*
5206
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
5207
+ * This software is released under MIT license.
5208
+ * The full license information can be found in LICENSE in the root directory of this project.
5209
+ */
5210
+
5211
+ /*
5212
+ * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
5213
+ * This software is released under MIT license.
5214
+ * The full license information can be found in LICENSE in the root directory of this project.
5215
+ */
4649
5216
 
4650
5217
  /*
4651
5218
  * Copyright (c) 2018-2025 Porsche Informatik. All Rights Reserved.
@@ -4866,7 +5433,7 @@ class ClrHistoryService {
4866
5433
  return of(historyEntry).pipe(tap(() => this.changingHistory$.next(true)), switchMap(entry => this.historyHttpService.addHistoryEntry(entry)), tap(() => this.changingHistory$.next(false)));
4867
5434
  }
4868
5435
  getHistory(username, tenantId) {
4869
- return this.changingHistory$.pipe(filter$1(changing => !changing), switchMap(() => this.historyHttpService.getHistory(username, tenantId)));
5436
+ return this.changingHistory$.pipe(filter$2(changing => !changing), switchMap(() => this.historyHttpService.getHistory(username, tenantId)));
4870
5437
  }
4871
5438
  removeFromHistory(historyEntry) {
4872
5439
  return of(historyEntry).pipe(tap(() => this.changingHistory$.next(true)), switchMap(entry => this.historyHttpService.removeFromHistory(entry)), tap(() => this.changingHistory$.next(false)));
@@ -11357,7 +11924,7 @@ class DatagridColumnReorderDirective {
11357
11924
  this.cdkDropList.sortPredicate = this.canBeSorted;
11358
11925
  this.cdkDropList.lockAxis = 'x';
11359
11926
  this.cdkDropList.dropped
11360
- .pipe(takeUntilDestroyed(this.destroyRef), filter$2(event => this.isDragItemDgColumn(event.item)))
11927
+ .pipe(takeUntilDestroyed(this.destroyRef), filter$1(event => this.isDragItemDgColumn(event.item)))
11361
11928
  .subscribe(event => this.updateColumnOrder(event.previousIndex, event.currentIndex));
11362
11929
  // do not allow reordering columns when detail view is open (only one column is shown anyways)
11363
11930
  this.datagrid.detailService.stateChange
@@ -11616,7 +12183,7 @@ class StatePersistenceKeyDirective {
11616
12183
  this.reorderDirective.columnOrderChanged
11617
12184
  .pipe(takeUntil(this.destroy$),
11618
12185
  // we skip the first value (init), because it's already coming from the local storage, so no need to save it again
11619
- filter$2(({ trigger }) => trigger !== 'init'))
12186
+ filter$1(({ trigger }) => trigger !== 'init'))
11620
12187
  .subscribe(({ columns }) => this.persistColumnOrder(state, columns));
11621
12188
  }
11622
12189
  initColumnOrder(savedState) {
@@ -15023,5 +15590,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImpor
15023
15590
  * Generated bundle index. Do not edit.
15024
15591
  */
15025
15592
 
15026
- export { ACShape, AcceptanceDateShape, AcceptedBrands, AccessoryPartsShape, AudiBrandShape, AwardWinnerPremiumShape, BIG_ENDIAN, BlocksGroupForwardShape, BundleForwardShape, BusinessCustomersCommercialShape, BusinessCustomersPrivateShape, BusinessPartnerWithCar, CLR_BLANK_OPTION, CONTENT_PROVIDER, CalculatorForwardShape, CaliforniaServiceShape, CampaignOutdatedShape, CampaignShape, CarOffSite, CarOnSite, CircleFilled, CircleHalfFilled, CircleQuarterFilled, CircleThreeQuartersFilled, ClrActionPanel, ClrActionPanelContainer, ClrActionPanelContainerContent, ClrActionPanelContainerFooter, ClrActionPanelModule, ClrActiveNotification, ClrAddonsLabel, ClrAddonsModule, ClrAutocompleteOff, ClrAutocompleteOffModule, ClrBackButton, ClrBackButtonModule, ClrBrandAvatar, ClrBrandAvatarModule, ClrBreadcrumb, ClrBreadcrumbModule, ClrBreadcrumbService, ClrCollapseExpandSection, ClrCollapseExpandSectionModule, ClrContentPanel, ClrContentPanelContainer, ClrContentPanelContainerContent, ClrContentPanelContainerFooter, ClrContentPanelModule, ClrContentRef, ClrDataListPredefinedValidatorDirective, ClrDataListValidatorModule, ClrDataListValidators, ClrDatagridColumnReorderModule, ClrDatagridStatePersistenceModule, ClrDateFilterComponent, ClrDateFilterModule, ClrDateTimeContainer, ClrDateTimeModule, ClrDaterangeMaxValidator, ClrDaterangeMinValidator, ClrDaterangeOrderValidator, ClrDaterangeRequiredValidator, ClrDaterangepickerContainerComponent, ClrDaterangepickerDirective, ClrDaterangepickerModule, ClrDotPager, ClrDotPagerModule, ClrDropdownOverflowDirective, ClrDropdownOverflowModule, ClrEnumFilterComponent, ClrEnumFilterModule, ClrExportDatagridButtonModule, ClrFlowBar, ClrFlowBarModule, ClrFormModule, ClrGenericQuickList, ClrGenericQuickListModule, ClrHistory, ClrHistoryModule, ClrHistoryPinned, ClrHistoryService, ClrIfDaterangeErrorDirective, ClrIfWarning, ClrIfWarningModule, ClrLetterAvatar, ClrLetterAvatarModule, ClrLocationBarModule, ClrMainNavGroup, ClrMainNavGroupItem, ClrMainNavGroupModule, ClrMaxNumeric, ClrMinNumeric, ClrMultilingualInput, ClrMultilingualInputValidators, ClrMultilingualModule, ClrMultilingualSelector, ClrMultilingualTextarea, ClrNotification, ClrNotificationModule, ClrNotificationRef, ClrNotificationService, ClrNumericField, ClrNumericFieldModule, ClrNumericFieldValidators, ClrPagedSearchResultList, ClrPagedSearchResultListModule, ClrPager, ClrPagerModule, ClrProgressSpinnerComponent, ClrProgressSpinnerModule, ClrQuickList, ClrQuickListModule, ClrReadonlyDirective, ClrReadonlyDirectiveModule, ClrRequiredAllMultilang, ClrRequiredOneMultilang, ClrSearchField, ClrSearchFieldModule, ClrTimeInput, ClrTreetable, ClrTreetableActionOverflow, ClrTreetableCell, ClrTreetableColumn, ClrTreetableModule, ClrTreetablePlaceholder, ClrTreetableRow, ClrTreetableSortOrder, ClrViewEditSection, ClrViewEditSectionModule, ColumnHiddenStatePersistenceDirective, CompletedByDateShape, CupraBrandShape, Customer, CustomerVip, CustomerVipCollection, CustomerWaiting, CustomerWaitingCollection, DATE, DELIMITER_REGEX, DWABrandShape, DatagridColumnReorderDirective, DatagridFieldDirective, DayModel, DeliveryDate, DieselShape, DollarBillForwardShape, DollarBillPartialShape, DynamicCellContentComponent, EnergyShape, ExportDatagridButtonComponent, ExportDatagridService, ExportTypeEnum, ExternalPartForwardShape, FirstRegistrationDate, GasCarsServiceShape, GasShape, HISTORY_NOTIFICATION_URL_PROVIDER, HISTORY_PROVIDER, HISTORY_TOKEN, HistoryProvider, InternalPartForwardShape, InvoiceReadyShape, InvoiceRecipient, InvoiceShape, Items, ItemsForwardShape, ItemsReceiveShape, LITTLE_ENDIAN, LITTLE_ENDIAN_REGEX, LocationBarComponent, LocationBarContentProvider, LocationBarNode, LogoCommissionModule, LogoCommissionModuleFavIcon, LogoCommissionModuleNegative, LogoCommissionModuleNegativeFavIcon, LogoCostApproval, LogoCostApprovalFavIcon, LogoCostApprovalNegative, LogoCostApprovalNegativeFavIcon, LogoCostControlling, LogoCostControllingFavIcon, LogoCostControllingNegative, LogoCostControllingNegativeFavIcon, LogoDigitalServiceReception, LogoDigitalServiceReceptionFavIcon, LogoDigitalServiceReceptionNegative, LogoDigitalServiceReceptionNegativeFavIcon, LogoDocFlow, LogoDocFlowFavIcon, LogoDocFlowNegative, LogoDocFlowNegativeFavIcon, LogoDocScan, LogoDocScanFavIcon, LogoDocScanNegative, LogoDocScanNegativeFavIcon, LogoDocStore, LogoDocStoreFavIcon, LogoDocStoreNegative, LogoDocStoreNegativeFavIcon, LogoEBilling, LogoEBillingFavIcon, LogoEBillingNegative, LogoEBillingNegativeFavIcon, LogoEPayment, LogoEPaymentFavIcon, LogoEPaymentNegative, LogoEPaymentNegativeFavIcon, LogoMobilityPlanner, LogoMobilityPlannerFavIcon, LogoMobilityPlannerNegative, LogoMobilityPlannerNegativeFavIcon, LogoPartsMobile, LogoPartsMobileFavIcon, LogoPartsMobileNegative, LogoPartsMobileNegativeFavIcon, LogoSBO, LogoSBOFavIcon, LogoSBONegative, LogoSBONegativeFavIcon, LogoServiceCube, LogoServiceCubeFavIcon, LogoServiceCubeNegative, LogoServiceCubeNegativeFavIcon, LogoWCP, LogoWCPFavIcon, LogoWCPNegative, LogoWCPNegativeFavIcon, LogoWorkshopOrderTracker, LogoWorkshopOrderTrackerFavIcon, LogoWorkshopOrderTrackerNegative, LogoWorkshopOrderTrackerNegativeFavIcon, MIDDLE_ENDIAN, MIDDLE_ENDIAN_REGEX, MONTH, Mechanic, NewCarUtilityVehicleShape, NodeId, Number0, Number1, Number10, Number11, Number12, Number13, Number14, Number15, Number16, Number17, Number18, Number19, Number2, Number20, Number3, Number4, Number5, Number6, Number7, Number8, Number9, OrderShape, OrderStatusShape, PaintMaterialForwardShape, PaintMaterialShape, ParkingLocation, PartAvailabilityInfoShape, PartAvailabilityNoShape, PartAvailabilityUnknownShape, PartAvailabilityWarningShape, PartAvailabilityYesShape, PartIdenticalPredecessorShape, PartIdenticalShape, PartIdenticalSuccessorShape, PartIdenticalSuccpredecessorShape, PartNonStockForwardShape, PartPredecessorShape, PartSuccessorPredecessorShape, PartSuccessorShape, PartsChangelocation, PartsForwardShape, PartsInventory, PartsNonStockShape, PartsPicking, PartsPickingPlus, PartsReceiving, PartsShape, PlusServiceShape, PopoverPositions, PorscheBrandShape, PriceTypeSwitchShape, RepeatRepairCollection, RepeatRepairShape, ReplacementVehicleCollection, ReplacementVehicleShape, ReturnDateShape, SEPARATOR_TEXT_DEFAULT, SeatBrandShape, Selection, ServiceAdvisor, SkodaBrandShape, Sort, StatePersistenceKeyDirective, TRANSLATIONS, TaskAndAppointment, TextForward, TimeModel, TopcardShape, TouaregServiceShape, TreetableCellRenderer, TreetableHeaderRenderer, TreetableItemsDirective, TreetableMainRenderer, TreetableRowRenderer, USER_INPUT_REGEX, VWBrandShape, VWNBrandShape, VWShape, VehicleConversionShape, VinShape, VsfSearchShape, VsfSearchShape48, WCPShape, WrenchForward, YEAR, acceleration, accelerationIcon, acceptanceDateIcon, accessories, accessoriesIcon, accessoryPartsIcon, adblueAppIcon, adblue_app, add, addIcon, airConditionerIcon, air_conditioning, alert, alertFilledAppIcon, alertIcon, alertNotificationFilledAppIcon, alert_filled_app, alert_notification_filled_app, allIcons, ambientLightAppIcon, ambient_light_app, amplifier, amplifierIcon, appConnectAppIcon, app_connect_app, archive, archiveIcon, arrowDownIcon, arrowLeftAlignedAppIcon, arrowLeftIcon, arrowRightIcon, arrowSliderAppIcon, arrowUpIcon, arrow_down, arrow_left, arrow_left_aligned_app, arrow_right, arrow_slider_app, arrow_up, attachment, attachmentIcon, audiBrandIcon, authentPlugChargeAppIcon, authentQrAppIcon, authentRfidAppIcon, authentTouchidAppIcon, authent_plug_charge_app, authent_qr_app, authent_rfid_app, authent_touch_id_app, automaticTempAppIcon, automatic_temp_app, awardWinnerPremiumIcon, award_winner_premium, back, backIcon, battery, batteryIcon, batterySocChargingAppIcon, batterySocDepartureAppIcon, batterySocDestinationAppIcon, battery_soc_charging_app, battery_soc_departure_app, battery_soc_destination_app, bin, binIcon, blocksGroupForwardIcon, bluetooth, bluetoothIcon, bookmark, bookmarkFilledIcon, bookmarkIcon, bookmark_filled, brakeAppIcon, brake_app, brochure, brochureIcon, bulletpointAppIcon, bulletpoint_app, bundleForwardIcon, businessCustomersCommercialIcon, businessCustomersPrivateIcon, businessPartnerWithCarIcon, business_customers_commercial, business_customers_private, calc, calcIcon, calculatorForwardIcon, calendar, calendarCustomIcon, californiaServiceIcon, californiaSpecialistIcon, california_specialist, cameraScanIcon, camera_scan, campaignIcon, campaignOutdatedIcon, carDocumentsIcon, carErrorAppIcon, carInsuranceIcon, carOffSite, carOnSite, carPickupServiceIcon, carPlusIcon, carSettingsIcon, carVerifiedAppIcon, carWashIcon, carWheelAppIcon, car_documents, car_error_app, car_insurance, car_pickup_service, car_plus, car_settings, car_verified_app, car_wheel_app, carwash, certifiedRepairIcon, certifiedRetailerIcon, certified_repair, certified_retailer, challengeAppIcon, challenge_app, charging, chargingIcon, chargingPduAppIcon, chargingStationIcon, chargingTarifOverviewAppIcon, charging_pdu_app, charging_station, charging_tarif_overview_app, chat, chatAppIcon, chatIcon, chat_app, checkboxCheckedAppIcon, checkboxCheckedIcon, checkboxUncheckedAppIcon, checkboxUncheckedIcon, checkbox_checked, checkbox_checked_app, checkbox_unchecked, checkbox_unchecked_app, checkmark, checkmarkAppIcon, checkmarkFilledAppIcon, checkmarkIcon, checkmark_app, checkmark_filled_app, chevronDownIcon, chevronLeftAlignedappIcon, chevronLeftIcon, chevronRightAlignedappIcon, chevronRightIcon, chevronSmallLeftAlignedappIcon, chevronSmallRightAlignedappIcon, chevronUpIcon, chevron_down, chevron_left, chevron_left_alignedapp, chevron_right, chevron_right_alignedapp, chevron_small_left_alignedapp, chevron_small_right_alignedapp, chevron_up, circleFilledIcon, circleHalfFilledIcon, circleQuarterFilledIcon, circleThreeQuartersFilledIcon, city, cityIcon, clearAppIcon, clearRightAlignedappIcon, clear_app, clear_right_alignedapp, clock, clockIcon, close, closeAppIcon, closeCircleIcon, closeIcon, closeLeftAlignedappIcon, closeRightAlignedappIcon, close_app, close_circle, close_left_alignedapp, close_right_alignedapp, clrIconSVG, coffeeFilledAppIcon, coffee_filled_app, compassAppIcon, compass_app, completedByDateIcon, configuratorCommercialIcon, configuratorPrivateIcon, configurator_commercial, configurator_private, construction, constructionIcon, consumptionFuelFilledAppIcon, consumptionIcon, consumption_fuel, consumption_fuel_filled_app, contact, contactDealerFilledAppIcon, contactDealerIcon, contactIcon, contact_dealer, contact_dealer_filled_app, countryRoadIcon, country_road, craft, craftIcon, cupraBrandIcon, customerIcon, customerVipIcon, customerWaitingIcon, customersCenterIcon, customers_center, dataCopyAppIcon, dataExpiredIcon, dataFilledIcon, dataInputIcon, dataPlugAppIcon, dataSearchIcon, dataTimeExtensionIcon, data_copy_app, data_expired, data_filled, data_input, data_plug_app, data_search, data_time_extension, defogDefrostAutoAppIcon, defogDefrostIcon, defog_defrost, defog_defrost_auto_app, deliveryDateIcon, destinationAppIcon, destination_app, dieselIcon, direction, directionIcon, dischargingAppIcon, discharging_app, discountAppIcon, discount_app, discoveryAppIcon, discovery_app, dollarBillForwardIcon, dollarBillPartialIcon, download, downloadCustomIcon, dragIndicatorIcon, drag_indicator, driversAssistanceIcon, drivers_assistance, dropFilledAppIcon, drop_filled_app, dwaBrandIcon, eco, ecoIcon, edit, editIcon, editSmallRightAlignedAppIcon, edit_small_right_aligned_app, efficiency, efficiencyIcon, electricCarsIcon, electricCarsServiceIcon, electric_cars, electric_cars_service, electricity, electricityFilledAppIcon, electricityIcon, electricity_filled_app, emergency, emergencyIcon, emission, emissionIcon, energyIcon, engine, engineIcon, entertainment, entertainmentIcon, escapeHtml, escapeRegex, exportAppIcon, export_app, expressServiceIcon, express_service, exterior, exterior360Icon, exteriorIcon, exterior_360, externalPartForwardIcon, faq, faqIcon, fastForwardIcon, fast_forward, fax, faxIcon, filter, filterIcon, findACarIcon, findADealerIcon, find_a_car, find_a_dealer, firstRegistrationDateIcon, fleetServiceCommercialIcon, fleetServicePrivateIcon, fleet_service_commercial, fleet_service_private, folderFilledAppIcon, folder_filled_app, foodFilledAppIcon, food_filled_app, formatNumber, fullscreenEnterIcon, fullscreenExitIcon, fullscreen_enter, fullscreen_exit, gallery, galleryIcon, garageAppIcon, garage_app, gasAppIcon, gasCarsServiceIcon, gasIcon, gas_app, glassDamageAppIcon, glass_damage_app, gte, gteIcon, heart, heartFilledAppIcon, heartIcon, heart_filled_app, heightAppIcon, height_app, highwayRoadIcon, highway_road, history, historyIcon, homeAppIcon, homeEnergyAppIcon, homeFilledAppIcon, home_app, home_energy_app, home_filled_app, hornAppIcon, hornFilledAppIcon, horn_app, horn_filled_app, hybrid, hybridIcon, immediateChargingAppIcon, immediate_charging_app, info, infoFilledIcon, infoIcon, info_filled, inputHideIcon, inputShowIcon, input_hide, input_show, interior, interior360Icon, interiorIcon, interior_360, internalPartForwardIcon, internet, internetIcon, invitationAppIcon, invitation_app, invoiceIcon, invoiceReadyIcon, invoiceRecipientIcon, itemsForwardIcon, itemsRecieveIcon, jobportal, jobportalIcon, keyAppIcon, keyCardAppIcon, keyDigitalAppIcon, key_app, key_card_app, key_digital_app, keyboardAppIcon, keyboard_app, layerCollapseAppIcon, layerExpandAppIcon, layer_collapse_app, layer_expand_app, layersAppIcon, layers_app, legalTermsAndConditionsAppIcon, legal_terms_and_conditions_app, licencePlateAppIcon, licence_plate_app, lightAssistappIcon, light_assistapp, lightingAppIcon, lighting_app, linkExternAppIcon, link_extern_app, list, listIcon, loadingVolumeIcon, loading_volume, localBusinessIcon, local_business, locate, locateIcon, lock, lockIcon, lockOpenIcon, lock_open, login, loginIcon, logistic, logisticIcon, logoCommissionModuleFavIcon, logoCommissionModuleIcon, logoCommissionModuleNegativeFavIcon, logoCommissionModuleNegativeIcon, logoCostApprovalFavIcon, logoCostApprovalIcon, logoCostApprovalNegativeFavIcon, logoCostApprovalNegativeIcon, logoCrossControllingFavIcon, logoCrossControllingIcon, logoCrossControllingNegativeFavIcon, logoCrossControllingNegativeIcon, logoDigitalServiceReceptionFavIcon, logoDigitalServiceReceptionIcon, logoDigitalServiceReceptionNegativeFavIcon, logoDigitalServiceReceptionNegativeIcon, logoDocFlowFavIcon, logoDocFlowIcon, logoDocFlowNegativeFavIcon, logoDocFlowNegativeIcon, logoDocScanFavIcon, logoDocScanIcon, logoDocScanNegativeFavIcon, logoDocScanNegativeIcon, logoDocStoreFavIcon, logoDocStoreIcon, logoDocStoreNegativeFavIcon, logoDocStoreNegativeIcon, logoEBillingFavIcon, logoEBillingIcon, logoEBillingNegativeFavIcon, logoEBillingNegativeIcon, logoEPaymentFavIcon, logoEPaymentIcon, logoEPaymentNegativeFavIcon, logoEPaymentNegativeIcon, logoMobilityPlannerFavIcon, logoMobilityPlannerIcon, logoMobilityPlannerNegativeFavIcon, logoMobilityPlannerNegativeIcon, logoPartsMobileFavIcon, logoPartsMobileIcon, logoPartsMobileNegativeFavIcon, logoPartsMobileNegativeIcon, logoSBOFavIcon, logoSBOIcon, logoSBONegativeFavIcon, logoSBONegativeIcon, logoServiceCubeFavIcon, logoServiceCubeIcon, logoServiceCubeNegativeFavIcon, logoServiceCubeNegativeIcon, logoWCPFavIcon, logoWCPIcon, logoWCPNegativeFavIcon, logoWCPNegativeIcon, logoWorkshopOrderTrackerFavIcon, logoWorkshopOrderTrackerIcon, logoWorkshopOrderTrackerNegativeFavIcon, logoWorkshopOrderTrackerNegativeIcon, logout, logoutIcon, magnifier, magnifierIcon, magnifierMinusIcon, magnifierPlusIcon, magnifier_minus, magnifier_plus, mail, mailIcon, mailResendAppIcon, mail_resend_app, manual, manualIcon, map, mapIcon, mechanicIcon, media, mediaIcon, menu, menuAppAppIcon, menuIcon, menu_app_app, microphoneAppIcon, microphone_app, mobile, mobileIcon, moreAppIcon, moreAppbarAppIcon, more_app, more_appbar_app, mot, motIcon, motability, motabilityIcon, navigate, navigateFilledAppIcon, navigateIcon, navigate_filled_app, newCarCommercialIcon, newCarPrivateFilledAppIcon, newCarPrivateIcon, newCarUtilityVehicleIcon, new_car_commercial, new_car_private, new_car_private_filled_app, nightServiceIcon, night_service, notification, notificationFilledIcon, notificationIcon, notification_filled, number0Icon, number10Icon, number11Icon, number12Icon, number13Icon, number14Icon, number15Icon, number16Icon, number17Icon, number18Icon, number19Icon, number1Icon, number20Icon, number2Icon, number3Icon, number4Icon, number5Icon, number6Icon, number7Icon, number8Icon, number9Icon, offers, offersFilledAppIcon, offersIcon, offers_filled_app, officeAppIcon, officeFilledAppIcon, office_app, office_filled_app, oilLevelIcon, oilLevelWarningIcon, oilTemperatureAppIcon, oil_level, oil_level_warning, oil_temperature_app, onCallDutyIcon, on_call_duty, openSatIcon, open_sat, orderIcon, orderStatusIcon, paintMaterialForwardIcon, paintMaterialIcon, paintShopIcon, paint_shop, paragraphAppIcon, paragraph_app, parkHeaterAppIcon, park_heater_app, parking, parkingFilledAppIcon, parkingGarageAppIcon, parkingIcon, parkingLocationIcon, parkingRouteAppIcon, parkingValetAppIcon, parking_filled_app, parking_garage_app, parking_route_app, parking_valet_app, partAvailabilityInfoIcon, partAvailabilityNoIcon, partAvailabilityUnknownIcon, partAvailabilityWarningIcon, partAvailabilityYesIcon, partIdenticalIcon, partIdenticalPredecessorIcon, partIdenticalSuccessorIcon, partIdenticalSuccpredecessorIcon, partPredecessorIcon, partSuccessorIcon, partSuccessorPredecessorIcon, partsChangelocationIcon, partsForwardIcon, partsIcon, partsInventoryIcon, partsNonStockForwardIcon, partsNonStockIcon, partsPickingIcon, partsPickingPlusIcon, partsReceivingIcon, pause, pauseIcon, payload, payloadIcon, paymentAppIcon, paymentCashAppIcon, paymentChargingCardAppIcon, paymentCreditcardAppIcon, paymentMachineAppIcon, payment_app, payment_cash_app, payment_charging_card_app, payment_creditcard_app, payment_machine_app, performance, performanceIcon, petrol, petrolIcon, phone, phoneIcon, pin, pinFilledAppIcon, pinGenericFilledAppIcon, pinIcon, pin_filled_app, pin_generic_filled_app, play, playIcon, plugCcsAppIcon, plugChademoAppIcon, plugChargeAppIcon, plugGenericAppIcon, plugSchukoAppIcon, plugType1AppIcon, plugType2AppIcon, plug_ccs_app, plug_chademo_app, plug_charge_app, plug_generic_app, plug_schuko_app, plug_type1_app, plug_type2_app, plusServiceIcon, porscheBrandIcon, power, powerIcon, powerTrainIcon, powertrain, preHeaterAppIcon, pre_heater_app, preciseLaneNavigationAppIcon, precise_lane_navigation_app, presentAppIcon, present_app, priceTypeSwitchIcon, printer, printerIcon, privacyAppIcon, privacy_app, profile, profileIcon, profileRegisterAppIcon, profileVerifiedIcon, profile_register_app, profile_verified, publicServiceIcon, publicTransportAppIcon, public_service, public_transport_app, qualifiedWorkshopIcon, qualified_workshop, questionnaireAppIcon, questionnaire_app, radio, radioButtonInselectedIcon, radioButtonSelectedForDefIcon, radioButtonSelectedIcon, radioIcon, radio_button_inselected, radio_button_selected, radio_button_selected_for_development, range, rangeIcon, reload, reloadIcon, remove, removeIcon, repeat, repeatIcon, repeatRepairIcon, replacementVehicleIcon, returnDateIcon, rewind, rewindIcon, roadsideAssistanceIcon, roadside_assistance, route, routeArrowAppIcon, routeIcon, route_arrow_app, routesHistoryAppIcon, routes_history_app, rss, rssIcon, safety, safetyIcon, save, saveAppIcon, saveIcon, save_app, seat, seatAirIcon, seatBrandIcon, seatIcon, seat_air, secretTipAppIcon, secretTipFilledAppIcon, secret_tip_app, secret_tip_filled_app, selected, selectedIcon, selectedPartnerNetworkAppIcon, selected_partner_network_app, sendToCarAppIcon, send_to_car_app, service, serviceAdvisorIcon, serviceBellIcon, serviceFilledAppIcon, serviceIcon, service_bell, service_filled_app, settings, settingsIcon, shareAndroidIcon, shareIosIcon, share_android, share_ios, shoppingCartFilledAppIcon, shoppingCartIcon, shopping_cart, shopping_cart_filled_app, shuffle, shuffleIcon, size, sizeIcon, skillAppIcon, skill_app, skipBackwardIcon, skipForwardIcon, skip_backward, skip_forward, skodaBrandIcon, softwareDownloadAppIcon, software_download_app, sortingAppIcon, sorting_app, sound, soundIcon, standardEquipmentIcon, standard_equipment, starFilledIcon, starOutlineIcon, star_filled, star_outline, statisticAppIcon, statistic_app, stockLocatorCommercialIcon, stockLocatorPrivateIcon, stock_locator_commercial, stock_locator_private, stop, stopIcon, strip, switchPositionAppIcon, switch_position_app, syncAppIcon, sync_app, taskAndAppointmentIcon, taxiDealerIcon, taxi_dealer, technicalSpecificationIcon, technical_specification, temperatureAppIcon, temperature_app, testDriveIcon, test_drive, textForwardIcon, thumbsdownAppIcon, thumbsdownFilledAppIcon, thumbsdown_app, thumbsdown_filled_app, thumbsupAppIcon, thumbsupFilledAppIcon, thumbsup_app, thumbsup_filled_app, timeClimatisationAppIcon, timePreferredAppIcon, time_climatisation_app, time_preferred_app, timer, timerIcon, topcardIcon, touaregServiceIcon, transcriptDownloadIcon, transcript_download, transmissionAutomaticIcon, transmissionManualIcon, transmission_automatic, transmission_manual, tripAppIcon, tripLongAppIcon, tripPartedAppIcon, tripShortAppIcon, trip_app, trip_long_app, trip_parted_app, trip_short_app, turnSignalsIcon, turn_signals, unselected, unselectedIcon, updateRefreshAppIcon, update_refresh_app, upload, uploadAppIcon, uploadCustomIcon, upload_app, usedCarCommercialIcon, usedCarPrivateIcon, used_car_commercial, used_car_private, vehicleAmarokIcon, vehicleCaddyIcon, vehicleConversionIcon, vehicleCrafterIcon, vehicleHightIcon, vehicleIdBuzzIcon, vehicleMultivanIcon, vehicleTransporterIcon, vehicle_amarok, vehicle_caddy, vehicle_crafter, vehicle_hight, vehicle_idbuzz, vehicle_multivan, vehicle_transporter, videoChatIcon, video_chat, view360Icon, view_360, vinIcon, virtualRealityIcon, virtual_reality, voiceMessageAppIcon, voice_message_app, volkswagenAppIcon, volkswagenIcon, volkswagen_app, volumeMaximumIcon, volumeMediumIcon, volumeMuteIcon, volume_maximum, volume_medium, volume_mute, vsfSearch48Icon, vsfSearchIcon, vwBrandIcon, vwConnectLicenseAppIcon, vw_connect_license_app, vwnBrandIcon, walkingAppIcon, walkingFilledAppIcon, walking_app, walking_filled_app, wallbox, wallboxIcon, wcAppIcon, wc_app, wcpIcon, weAssistAppIcon, weChargeAppIcon, weDeliverAppIcon, weExperienceAppIcon, weParkAppIcon, weUpgradeAppIcon, we_assist_app, we_charge_app, we_deliver_app, we_experience_app, we_park_app, we_upgrade_app, weatherSunAppIcon, weather_sun_app, wheelToWheelIcon, wheel_to_wheel, windscreenWashIcon, windscreen_wash, wlanHotspotIcon, wlan_hotspot, wrenchForwardIcon };
15593
+ export { ACShape, AcceptanceDateShape, AcceptedBrands, AccessoryPartsShape, AudiBrandShape, AwardWinnerPremiumShape, BIG_ENDIAN, BlocksGroupForwardShape, BundleForwardShape, BusinessCustomersCommercialShape, BusinessCustomersPrivateShape, BusinessPartnerWithCar, CLR_BLANK_OPTION, CONTENT_PROVIDER, CalculatorForwardShape, CaliforniaServiceShape, CampaignOutdatedShape, CampaignShape, CarOffSite, CarOnSite, CircleFilled, CircleHalfFilled, CircleQuarterFilled, CircleThreeQuartersFilled, ClrActionPanel, ClrActionPanelContainer, ClrActionPanelContainerContent, ClrActionPanelContainerFooter, ClrActionPanelModule, ClrActiveNotification, ClrAddonsLabel, ClrAddonsModule, ClrAutocompleteOff, ClrAutocompleteOffModule, ClrBackButton, ClrBackButtonModule, ClrBrandAvatar, ClrBrandAvatarModule, ClrBreadcrumb, ClrBreadcrumbModule, ClrBreadcrumbService, ClrCollapseExpandSection, ClrCollapseExpandSectionModule, ClrContentPanel, ClrContentPanelContainer, ClrContentPanelContainerContent, ClrContentPanelContainerFooter, ClrContentPanelModule, ClrContentRef, ClrDataListPredefinedValidatorDirective, ClrDataListValidatorModule, ClrDataListValidators, ClrDatagridColumnReorderModule, ClrDatagridStatePersistenceModule, ClrDateFilterComponent, ClrDateFilterModule, ClrDateTimeContainer, ClrDateTimeModule, ClrDaterangeMaxValidator, ClrDaterangeMinValidator, ClrDaterangeOrderValidator, ClrDaterangeRequiredValidator, ClrDaterangepickerContainerComponent, ClrDaterangepickerDirective, ClrDaterangepickerModule, ClrDotPager, ClrDotPagerModule, ClrDropdownOverflowDirective, ClrDropdownOverflowModule, ClrEnumFilterComponent, ClrEnumFilterModule, ClrExportDatagridButtonModule, ClrFlowBar, ClrFlowBarModule, ClrFormModule, ClrGenericQuickList, ClrGenericQuickListModule, ClrHistory, ClrHistoryModule, ClrHistoryPinned, ClrHistoryService, ClrIfDaterangeErrorDirective, ClrIfWarning, ClrIfWarningModule, ClrLetterAvatar, ClrLetterAvatarModule, ClrLocationBarModule, ClrMainNavGroup, ClrMainNavGroupItem, ClrMainNavGroupModule, ClrMaxNumeric, ClrMinNumeric, ClrMultilingualInput, ClrMultilingualInputValidators, ClrMultilingualModule, ClrMultilingualSelector, ClrMultilingualTextarea, ClrNotification, ClrNotificationModule, ClrNotificationRef, ClrNotificationService, ClrNumericField, ClrNumericFieldModule, ClrNumericFieldValidators, ClrPagedSearchResultList, ClrPagedSearchResultListModule, ClrPager, ClrPagerModule, ClrProgressSpinnerComponent, ClrProgressSpinnerModule, ClrQuickList, ClrQuickListModule, ClrReadonlyDirective, ClrReadonlyDirectiveModule, ClrRequiredAllMultilang, ClrRequiredOneMultilang, ClrSearchField, ClrSearchFieldModule, ClrTimeInput, ClrTreetable, ClrTreetableActionOverflow, ClrTreetableCell, ClrTreetableColumn, ClrTreetableFilter, ClrTreetableModule, ClrTreetablePlaceholder, ClrTreetableRow, ClrTreetableSortOrder, ClrTreetableStringFilter, ClrTreetableTreeNode, ClrViewEditSection, ClrViewEditSectionModule, ColumnHiddenStatePersistenceDirective, CompletedByDateShape, CupraBrandShape, Customer, CustomerVip, CustomerVipCollection, CustomerWaiting, CustomerWaitingCollection, DATE, DELIMITER_REGEX, DWABrandShape, DatagridColumnReorderDirective, DatagridFieldDirective, DayModel, DeliveryDate, DieselShape, DollarBillForwardShape, DollarBillPartialShape, DynamicCellContentComponent, EnergyShape, ExportDatagridButtonComponent, ExportDatagridService, ExportTypeEnum, ExternalPartForwardShape, FirstRegistrationDate, GasCarsServiceShape, GasShape, HISTORY_NOTIFICATION_URL_PROVIDER, HISTORY_PROVIDER, HISTORY_TOKEN, HistoryProvider, InternalPartForwardShape, InvoiceReadyShape, InvoiceRecipient, InvoiceShape, ItemsForwardShape, ItemsReceiveShape, LITTLE_ENDIAN, LITTLE_ENDIAN_REGEX, LocationBarComponent, LocationBarContentProvider, LocationBarNode, LogoCommissionModule, LogoCommissionModuleFavIcon, LogoCommissionModuleNegative, LogoCommissionModuleNegativeFavIcon, LogoCostApproval, LogoCostApprovalFavIcon, LogoCostApprovalNegative, LogoCostApprovalNegativeFavIcon, LogoCostControlling, LogoCostControllingFavIcon, LogoCostControllingNegative, LogoCostControllingNegativeFavIcon, LogoDigitalServiceReception, LogoDigitalServiceReceptionFavIcon, LogoDigitalServiceReceptionNegative, LogoDigitalServiceReceptionNegativeFavIcon, LogoDocFlow, LogoDocFlowFavIcon, LogoDocFlowNegative, LogoDocFlowNegativeFavIcon, LogoDocScan, LogoDocScanFavIcon, LogoDocScanNegative, LogoDocScanNegativeFavIcon, LogoDocStore, LogoDocStoreFavIcon, LogoDocStoreNegative, LogoDocStoreNegativeFavIcon, LogoEBilling, LogoEBillingFavIcon, LogoEBillingNegative, LogoEBillingNegativeFavIcon, LogoEPayment, LogoEPaymentFavIcon, LogoEPaymentNegative, LogoEPaymentNegativeFavIcon, LogoMobilityPlanner, LogoMobilityPlannerFavIcon, LogoMobilityPlannerNegative, LogoMobilityPlannerNegativeFavIcon, LogoPartsMobile, LogoPartsMobileFavIcon, LogoPartsMobileNegative, LogoPartsMobileNegativeFavIcon, LogoSBO, LogoSBOFavIcon, LogoSBONegative, LogoSBONegativeFavIcon, LogoServiceCube, LogoServiceCubeFavIcon, LogoServiceCubeNegative, LogoServiceCubeNegativeFavIcon, LogoWCP, LogoWCPFavIcon, LogoWCPNegative, LogoWCPNegativeFavIcon, LogoWorkshopOrderTracker, LogoWorkshopOrderTrackerFavIcon, LogoWorkshopOrderTrackerNegative, LogoWorkshopOrderTrackerNegativeFavIcon, MIDDLE_ENDIAN, MIDDLE_ENDIAN_REGEX, MONTH, Mechanic, NewCarUtilityVehicleShape, NodeId, Number0, Number1, Number10, Number11, Number12, Number13, Number14, Number15, Number16, Number17, Number18, Number19, Number2, Number20, Number3, Number4, Number5, Number6, Number7, Number8, Number9, OrderShape, OrderStatusShape, PaintMaterialForwardShape, PaintMaterialShape, ParkingLocation, PartAvailabilityInfoShape, PartAvailabilityNoShape, PartAvailabilityUnknownShape, PartAvailabilityWarningShape, PartAvailabilityYesShape, PartIdenticalPredecessorShape, PartIdenticalShape, PartIdenticalSuccessorShape, PartIdenticalSuccpredecessorShape, PartNonStockForwardShape, PartPredecessorShape, PartSuccessorPredecessorShape, PartSuccessorShape, PartsChangelocation, PartsForwardShape, PartsInventory, PartsNonStockShape, PartsPicking, PartsPickingPlus, PartsReceiving, PartsShape, PlusServiceShape, PopoverPositions, PorscheBrandShape, PriceTypeSwitchShape, RepeatRepairCollection, RepeatRepairShape, ReplacementVehicleCollection, ReplacementVehicleShape, ReturnDateShape, SEPARATOR_TEXT_DEFAULT, SeatBrandShape, ServiceAdvisor, SkodaBrandShape, Sort, StatePersistenceKeyDirective, TRANSLATIONS, TaskAndAppointment, TextForward, TimeModel, TopcardShape, TouaregServiceShape, TreetableCellRenderer, TreetableDataStateService, TreetableHeaderRenderer, TreetableItemsDirective, TreetableMainRenderer, TreetableRowRenderer, USER_INPUT_REGEX, VWBrandShape, VWNBrandShape, VWShape, VehicleConversionShape, VinShape, VsfSearchShape, VsfSearchShape48, WCPShape, WrenchForward, YEAR, acceleration, accelerationIcon, acceptanceDateIcon, accessories, accessoriesIcon, accessoryPartsIcon, adblueAppIcon, adblue_app, add, addIcon, airConditionerIcon, air_conditioning, alert, alertFilledAppIcon, alertIcon, alertNotificationFilledAppIcon, alert_filled_app, alert_notification_filled_app, allIcons, ambientLightAppIcon, ambient_light_app, amplifier, amplifierIcon, appConnectAppIcon, app_connect_app, archive, archiveIcon, arrowDownIcon, arrowLeftAlignedAppIcon, arrowLeftIcon, arrowRightIcon, arrowSliderAppIcon, arrowUpIcon, arrow_down, arrow_left, arrow_left_aligned_app, arrow_right, arrow_slider_app, arrow_up, attachment, attachmentIcon, audiBrandIcon, authentPlugChargeAppIcon, authentQrAppIcon, authentRfidAppIcon, authentTouchidAppIcon, authent_plug_charge_app, authent_qr_app, authent_rfid_app, authent_touch_id_app, automaticTempAppIcon, automatic_temp_app, awardWinnerPremiumIcon, award_winner_premium, back, backIcon, battery, batteryIcon, batterySocChargingAppIcon, batterySocDepartureAppIcon, batterySocDestinationAppIcon, battery_soc_charging_app, battery_soc_departure_app, battery_soc_destination_app, bin, binIcon, blocksGroupForwardIcon, bluetooth, bluetoothIcon, bookmark, bookmarkFilledIcon, bookmarkIcon, bookmark_filled, brakeAppIcon, brake_app, brochure, brochureIcon, bulletpointAppIcon, bulletpoint_app, bundleForwardIcon, businessCustomersCommercialIcon, businessCustomersPrivateIcon, businessPartnerWithCarIcon, business_customers_commercial, business_customers_private, calc, calcIcon, calculatorForwardIcon, calendar, calendarCustomIcon, californiaServiceIcon, californiaSpecialistIcon, california_specialist, cameraScanIcon, camera_scan, campaignIcon, campaignOutdatedIcon, carDocumentsIcon, carErrorAppIcon, carInsuranceIcon, carOffSite, carOnSite, carPickupServiceIcon, carPlusIcon, carSettingsIcon, carVerifiedAppIcon, carWashIcon, carWheelAppIcon, car_documents, car_error_app, car_insurance, car_pickup_service, car_plus, car_settings, car_verified_app, car_wheel_app, carwash, certifiedRepairIcon, certifiedRetailerIcon, certified_repair, certified_retailer, challengeAppIcon, challenge_app, charging, chargingIcon, chargingPduAppIcon, chargingStationIcon, chargingTarifOverviewAppIcon, charging_pdu_app, charging_station, charging_tarif_overview_app, chat, chatAppIcon, chatIcon, chat_app, checkboxCheckedAppIcon, checkboxCheckedIcon, checkboxUncheckedAppIcon, checkboxUncheckedIcon, checkbox_checked, checkbox_checked_app, checkbox_unchecked, checkbox_unchecked_app, checkmark, checkmarkAppIcon, checkmarkFilledAppIcon, checkmarkIcon, checkmark_app, checkmark_filled_app, chevronDownIcon, chevronLeftAlignedappIcon, chevronLeftIcon, chevronRightAlignedappIcon, chevronRightIcon, chevronSmallLeftAlignedappIcon, chevronSmallRightAlignedappIcon, chevronUpIcon, chevron_down, chevron_left, chevron_left_alignedapp, chevron_right, chevron_right_alignedapp, chevron_small_left_alignedapp, chevron_small_right_alignedapp, chevron_up, circleFilledIcon, circleHalfFilledIcon, circleQuarterFilledIcon, circleThreeQuartersFilledIcon, city, cityIcon, clearAppIcon, clearRightAlignedappIcon, clear_app, clear_right_alignedapp, clock, clockIcon, close, closeAppIcon, closeCircleIcon, closeIcon, closeLeftAlignedappIcon, closeRightAlignedappIcon, close_app, close_circle, close_left_alignedapp, close_right_alignedapp, clrIconSVG, coffeeFilledAppIcon, coffee_filled_app, compassAppIcon, compass_app, completedByDateIcon, configuratorCommercialIcon, configuratorPrivateIcon, configurator_commercial, configurator_private, construction, constructionIcon, consumptionFuelFilledAppIcon, consumptionIcon, consumption_fuel, consumption_fuel_filled_app, contact, contactDealerFilledAppIcon, contactDealerIcon, contactIcon, contact_dealer, contact_dealer_filled_app, countryRoadIcon, country_road, craft, craftIcon, cupraBrandIcon, customerIcon, customerVipIcon, customerWaitingIcon, customersCenterIcon, customers_center, dataCopyAppIcon, dataExpiredIcon, dataFilledIcon, dataInputIcon, dataPlugAppIcon, dataSearchIcon, dataTimeExtensionIcon, data_copy_app, data_expired, data_filled, data_input, data_plug_app, data_search, data_time_extension, defogDefrostAutoAppIcon, defogDefrostIcon, defog_defrost, defog_defrost_auto_app, deliveryDateIcon, destinationAppIcon, destination_app, dieselIcon, direction, directionIcon, dischargingAppIcon, discharging_app, discountAppIcon, discount_app, discoveryAppIcon, discovery_app, dollarBillForwardIcon, dollarBillPartialIcon, download, downloadCustomIcon, dragIndicatorIcon, drag_indicator, driversAssistanceIcon, drivers_assistance, dropFilledAppIcon, drop_filled_app, dwaBrandIcon, eco, ecoIcon, edit, editIcon, editSmallRightAlignedAppIcon, edit_small_right_aligned_app, efficiency, efficiencyIcon, electricCarsIcon, electricCarsServiceIcon, electric_cars, electric_cars_service, electricity, electricityFilledAppIcon, electricityIcon, electricity_filled_app, emergency, emergencyIcon, emission, emissionIcon, energyIcon, engine, engineIcon, entertainment, entertainmentIcon, escapeHtml, escapeRegex, exportAppIcon, export_app, expressServiceIcon, express_service, exterior, exterior360Icon, exteriorIcon, exterior_360, externalPartForwardIcon, faq, faqIcon, fastForwardIcon, fast_forward, fax, faxIcon, filter, filterIcon, findACarIcon, findADealerIcon, find_a_car, find_a_dealer, firstRegistrationDateIcon, fleetServiceCommercialIcon, fleetServicePrivateIcon, fleet_service_commercial, fleet_service_private, folderFilledAppIcon, folder_filled_app, foodFilledAppIcon, food_filled_app, formatNumber, fullscreenEnterIcon, fullscreenExitIcon, fullscreen_enter, fullscreen_exit, gallery, galleryIcon, garageAppIcon, garage_app, gasAppIcon, gasCarsServiceIcon, gasIcon, gas_app, glassDamageAppIcon, glass_damage_app, gte, gteIcon, heart, heartFilledAppIcon, heartIcon, heart_filled_app, heightAppIcon, height_app, highwayRoadIcon, highway_road, history, historyIcon, homeAppIcon, homeEnergyAppIcon, homeFilledAppIcon, home_app, home_energy_app, home_filled_app, hornAppIcon, hornFilledAppIcon, horn_app, horn_filled_app, hybrid, hybridIcon, immediateChargingAppIcon, immediate_charging_app, info, infoFilledIcon, infoIcon, info_filled, inputHideIcon, inputShowIcon, input_hide, input_show, interior, interior360Icon, interiorIcon, interior_360, internalPartForwardIcon, internet, internetIcon, invitationAppIcon, invitation_app, invoiceIcon, invoiceReadyIcon, invoiceRecipientIcon, itemsForwardIcon, itemsRecieveIcon, jobportal, jobportalIcon, keyAppIcon, keyCardAppIcon, keyDigitalAppIcon, key_app, key_card_app, key_digital_app, keyboardAppIcon, keyboard_app, layerCollapseAppIcon, layerExpandAppIcon, layer_collapse_app, layer_expand_app, layersAppIcon, layers_app, legalTermsAndConditionsAppIcon, legal_terms_and_conditions_app, licencePlateAppIcon, licence_plate_app, lightAssistappIcon, light_assistapp, lightingAppIcon, lighting_app, linkExternAppIcon, link_extern_app, list, listIcon, loadingVolumeIcon, loading_volume, localBusinessIcon, local_business, locate, locateIcon, lock, lockIcon, lockOpenIcon, lock_open, login, loginIcon, logistic, logisticIcon, logoCommissionModuleFavIcon, logoCommissionModuleIcon, logoCommissionModuleNegativeFavIcon, logoCommissionModuleNegativeIcon, logoCostApprovalFavIcon, logoCostApprovalIcon, logoCostApprovalNegativeFavIcon, logoCostApprovalNegativeIcon, logoCrossControllingFavIcon, logoCrossControllingIcon, logoCrossControllingNegativeFavIcon, logoCrossControllingNegativeIcon, logoDigitalServiceReceptionFavIcon, logoDigitalServiceReceptionIcon, logoDigitalServiceReceptionNegativeFavIcon, logoDigitalServiceReceptionNegativeIcon, logoDocFlowFavIcon, logoDocFlowIcon, logoDocFlowNegativeFavIcon, logoDocFlowNegativeIcon, logoDocScanFavIcon, logoDocScanIcon, logoDocScanNegativeFavIcon, logoDocScanNegativeIcon, logoDocStoreFavIcon, logoDocStoreIcon, logoDocStoreNegativeFavIcon, logoDocStoreNegativeIcon, logoEBillingFavIcon, logoEBillingIcon, logoEBillingNegativeFavIcon, logoEBillingNegativeIcon, logoEPaymentFavIcon, logoEPaymentIcon, logoEPaymentNegativeFavIcon, logoEPaymentNegativeIcon, logoMobilityPlannerFavIcon, logoMobilityPlannerIcon, logoMobilityPlannerNegativeFavIcon, logoMobilityPlannerNegativeIcon, logoPartsMobileFavIcon, logoPartsMobileIcon, logoPartsMobileNegativeFavIcon, logoPartsMobileNegativeIcon, logoSBOFavIcon, logoSBOIcon, logoSBONegativeFavIcon, logoSBONegativeIcon, logoServiceCubeFavIcon, logoServiceCubeIcon, logoServiceCubeNegativeFavIcon, logoServiceCubeNegativeIcon, logoWCPFavIcon, logoWCPIcon, logoWCPNegativeFavIcon, logoWCPNegativeIcon, logoWorkshopOrderTrackerFavIcon, logoWorkshopOrderTrackerIcon, logoWorkshopOrderTrackerNegativeFavIcon, logoWorkshopOrderTrackerNegativeIcon, logout, logoutIcon, magnifier, magnifierIcon, magnifierMinusIcon, magnifierPlusIcon, magnifier_minus, magnifier_plus, mail, mailIcon, mailResendAppIcon, mail_resend_app, manual, manualIcon, map, mapIcon, mapToInternalTree, mechanicIcon, media, mediaIcon, menu, menuAppAppIcon, menuIcon, menu_app_app, microphoneAppIcon, microphone_app, mobile, mobileIcon, moreAppIcon, moreAppbarAppIcon, more_app, more_appbar_app, mot, motIcon, motability, motabilityIcon, navigate, navigateFilledAppIcon, navigateIcon, navigate_filled_app, newCarCommercialIcon, newCarPrivateFilledAppIcon, newCarPrivateIcon, newCarUtilityVehicleIcon, new_car_commercial, new_car_private, new_car_private_filled_app, nightServiceIcon, night_service, notification, notificationFilledIcon, notificationIcon, notification_filled, number0Icon, number10Icon, number11Icon, number12Icon, number13Icon, number14Icon, number15Icon, number16Icon, number17Icon, number18Icon, number19Icon, number1Icon, number20Icon, number2Icon, number3Icon, number4Icon, number5Icon, number6Icon, number7Icon, number8Icon, number9Icon, offers, offersFilledAppIcon, offersIcon, offers_filled_app, officeAppIcon, officeFilledAppIcon, office_app, office_filled_app, oilLevelIcon, oilLevelWarningIcon, oilTemperatureAppIcon, oil_level, oil_level_warning, oil_temperature_app, onCallDutyIcon, on_call_duty, openSatIcon, open_sat, orderIcon, orderStatusIcon, paintMaterialForwardIcon, paintMaterialIcon, paintShopIcon, paint_shop, paragraphAppIcon, paragraph_app, parkHeaterAppIcon, park_heater_app, parking, parkingFilledAppIcon, parkingGarageAppIcon, parkingIcon, parkingLocationIcon, parkingRouteAppIcon, parkingValetAppIcon, parking_filled_app, parking_garage_app, parking_route_app, parking_valet_app, partAvailabilityInfoIcon, partAvailabilityNoIcon, partAvailabilityUnknownIcon, partAvailabilityWarningIcon, partAvailabilityYesIcon, partIdenticalIcon, partIdenticalPredecessorIcon, partIdenticalSuccessorIcon, partIdenticalSuccpredecessorIcon, partPredecessorIcon, partSuccessorIcon, partSuccessorPredecessorIcon, partsChangelocationIcon, partsForwardIcon, partsIcon, partsInventoryIcon, partsNonStockForwardIcon, partsNonStockIcon, partsPickingIcon, partsPickingPlusIcon, partsReceivingIcon, pause, pauseIcon, payload, payloadIcon, paymentAppIcon, paymentCashAppIcon, paymentChargingCardAppIcon, paymentCreditcardAppIcon, paymentMachineAppIcon, payment_app, payment_cash_app, payment_charging_card_app, payment_creditcard_app, payment_machine_app, performance, performanceIcon, petrol, petrolIcon, phone, phoneIcon, pin, pinFilledAppIcon, pinGenericFilledAppIcon, pinIcon, pin_filled_app, pin_generic_filled_app, play, playIcon, plugCcsAppIcon, plugChademoAppIcon, plugChargeAppIcon, plugGenericAppIcon, plugSchukoAppIcon, plugType1AppIcon, plugType2AppIcon, plug_ccs_app, plug_chademo_app, plug_charge_app, plug_generic_app, plug_schuko_app, plug_type1_app, plug_type2_app, plusServiceIcon, porscheBrandIcon, power, powerIcon, powerTrainIcon, powertrain, preHeaterAppIcon, pre_heater_app, preciseLaneNavigationAppIcon, precise_lane_navigation_app, presentAppIcon, present_app, priceTypeSwitchIcon, printer, printerIcon, privacyAppIcon, privacy_app, profile, profileIcon, profileRegisterAppIcon, profileVerifiedIcon, profile_register_app, profile_verified, publicServiceIcon, publicTransportAppIcon, public_service, public_transport_app, qualifiedWorkshopIcon, qualified_workshop, questionnaireAppIcon, questionnaire_app, radio, radioButtonInselectedIcon, radioButtonSelectedForDefIcon, radioButtonSelectedIcon, radioIcon, radio_button_inselected, radio_button_selected, radio_button_selected_for_development, range, rangeIcon, reload, reloadIcon, remove, removeIcon, repeat, repeatIcon, repeatRepairIcon, replacementVehicleIcon, returnDateIcon, rewind, rewindIcon, roadsideAssistanceIcon, roadside_assistance, route, routeArrowAppIcon, routeIcon, route_arrow_app, routesHistoryAppIcon, routes_history_app, rss, rssIcon, safety, safetyIcon, save, saveAppIcon, saveIcon, save_app, seat, seatAirIcon, seatBrandIcon, seatIcon, seat_air, secretTipAppIcon, secretTipFilledAppIcon, secret_tip_app, secret_tip_filled_app, selected, selectedIcon, selectedPartnerNetworkAppIcon, selected_partner_network_app, sendToCarAppIcon, send_to_car_app, service, serviceAdvisorIcon, serviceBellIcon, serviceFilledAppIcon, serviceIcon, service_bell, service_filled_app, settings, settingsIcon, shareAndroidIcon, shareIosIcon, share_android, share_ios, shoppingCartFilledAppIcon, shoppingCartIcon, shopping_cart, shopping_cart_filled_app, shuffle, shuffleIcon, size, sizeIcon, skillAppIcon, skill_app, skipBackwardIcon, skipForwardIcon, skip_backward, skip_forward, skodaBrandIcon, softwareDownloadAppIcon, software_download_app, sortingAppIcon, sorting_app, sound, soundIcon, standardEquipmentIcon, standard_equipment, starFilledIcon, starOutlineIcon, star_filled, star_outline, statisticAppIcon, statistic_app, stockLocatorCommercialIcon, stockLocatorPrivateIcon, stock_locator_commercial, stock_locator_private, stop, stopIcon, strip, switchPositionAppIcon, switch_position_app, syncAppIcon, sync_app, taskAndAppointmentIcon, taxiDealerIcon, taxi_dealer, technicalSpecificationIcon, technical_specification, temperatureAppIcon, temperature_app, testDriveIcon, test_drive, textForwardIcon, thumbsdownAppIcon, thumbsdownFilledAppIcon, thumbsdown_app, thumbsdown_filled_app, thumbsupAppIcon, thumbsupFilledAppIcon, thumbsup_app, thumbsup_filled_app, timeClimatisationAppIcon, timePreferredAppIcon, time_climatisation_app, time_preferred_app, timer, timerIcon, topcardIcon, touaregServiceIcon, transcriptDownloadIcon, transcript_download, transmissionAutomaticIcon, transmissionManualIcon, transmission_automatic, transmission_manual, tripAppIcon, tripLongAppIcon, tripPartedAppIcon, tripShortAppIcon, trip_app, trip_long_app, trip_parted_app, trip_short_app, turnSignalsIcon, turn_signals, unselected, unselectedIcon, updateRefreshAppIcon, update_refresh_app, upload, uploadAppIcon, uploadCustomIcon, upload_app, usedCarCommercialIcon, usedCarPrivateIcon, used_car_commercial, used_car_private, vehicleAmarokIcon, vehicleCaddyIcon, vehicleConversionIcon, vehicleCrafterIcon, vehicleHightIcon, vehicleIdBuzzIcon, vehicleMultivanIcon, vehicleTransporterIcon, vehicle_amarok, vehicle_caddy, vehicle_crafter, vehicle_hight, vehicle_idbuzz, vehicle_multivan, vehicle_transporter, videoChatIcon, video_chat, view360Icon, view_360, vinIcon, virtualRealityIcon, virtual_reality, voiceMessageAppIcon, voice_message_app, volkswagenAppIcon, volkswagenIcon, volkswagen_app, volumeMaximumIcon, volumeMediumIcon, volumeMuteIcon, volume_maximum, volume_medium, volume_mute, vsfSearch48Icon, vsfSearchIcon, vwBrandIcon, vwConnectLicenseAppIcon, vw_connect_license_app, vwnBrandIcon, walkingAppIcon, walkingFilledAppIcon, walking_app, walking_filled_app, wallbox, wallboxIcon, wcAppIcon, wc_app, wcpIcon, weAssistAppIcon, weChargeAppIcon, weDeliverAppIcon, weExperienceAppIcon, weParkAppIcon, weUpgradeAppIcon, we_assist_app, we_charge_app, we_deliver_app, we_experience_app, we_park_app, we_upgrade_app, weatherSunAppIcon, weather_sun_app, wheelToWheelIcon, wheel_to_wheel, windscreenWashIcon, windscreen_wash, wlanHotspotIcon, wlan_hotspot, wrenchForwardIcon };
15027
15594
  //# sourceMappingURL=clr-addons.mjs.map