@cqa-lib/cqa-ui 1.1.555 → 1.1.556

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.
@@ -11501,6 +11501,12 @@ class MoveTestSuiteDialogComponent {
11501
11501
  this.pickedFolderIdChange = new EventEmitter();
11502
11502
  this.submitted = new EventEmitter();
11503
11503
  this.cancelled = new EventEmitter();
11504
+ /** Fires when a folder needs its children fetched. Emitted by `pick` (row
11505
+ * click) and `toggleExpanded` (chevron click) when the target node has
11506
+ * `hasChildren = true` but `loadedPages == null` and is not already fetching.
11507
+ * Hosts subscribe and call their paginated fetch, mutating the FolderNode
11508
+ * in place (set `children`, `loadedPages`, `childrenLoading`). */
11509
+ this.folderChildrenRequested = new EventEmitter();
11504
11510
  /** Bubble cqa-custom-input focus/blur events up to hosts. Useful when
11505
11511
  * `fieldsDisabled = false` and the host wants to react to interaction. */
11506
11512
  this.currentFieldFocus = new EventEmitter();
@@ -11512,6 +11518,11 @@ class MoveTestSuiteDialogComponent {
11512
11518
  * suite starts in Unorganized (`currentFolderId = null`) so a fresh dialog
11513
11519
  * doesn't appear valid just because `pickedFolderId` also defaults to null. */
11514
11520
  this.pickedTouched = false;
11521
+ /** Folder ids currently expanded in the inlined picker. Managed entirely
11522
+ * inside this component (no external Input) so it survives the host pushing
11523
+ * a new `folders` reference after each lazy-fetch resolves. */
11524
+ this.expandedIds = new Set();
11525
+ this.trackById = (_, row) => row.id;
11515
11526
  }
11516
11527
  set folders(value) {
11517
11528
  this._folders = value || [];
@@ -11528,18 +11539,79 @@ class MoveTestSuiteDialogComponent {
11528
11539
  this.cdr.markForCheck();
11529
11540
  }
11530
11541
  get testSuiteLabels() { return this._testSuiteLabels; }
11531
- onParentPicked(id) {
11532
- let next = null;
11533
- if (id != null) {
11534
- const coerced = typeof id === 'number' ? id : Number(id);
11535
- if (Number.isFinite(coerced))
11536
- next = coerced;
11542
+ ngOnInit() {
11543
+ this.seedExpandedIds();
11544
+ }
11545
+ ngOnChanges(changes) {
11546
+ // Re-seed only when expansion-intent inputs change. NEVER on `folders` —
11547
+ // the host pushes a new top-level reference after every lazy fetch and a
11548
+ // reseed there would collapse the folder the user just expanded.
11549
+ if (changes['currentFolderId'] || changes['pickedFolderId']) {
11550
+ this.seedExpandedIds();
11537
11551
  }
11538
- this.pickedFolderId = next;
11552
+ }
11553
+ /** Folder-row click handler. Selects the folder as the destination and, when
11554
+ * the folder has unloaded children, auto-expands it and asks the host to
11555
+ * fetch its children. */
11556
+ pick(id) {
11557
+ this.pickedFolderId = id;
11539
11558
  this.pickedTouched = true;
11540
- this.pickedFolderIdChange.emit(next);
11559
+ this.pickedFolderIdChange.emit(id);
11560
+ if (id != null) {
11561
+ this.expandedIds.add(id);
11562
+ this.requestChildrenIfMissing(id);
11563
+ }
11564
+ this.cdr.markForCheck();
11565
+ }
11566
+ /** Chevron click handler. Toggles expansion locally; on expand path, asks
11567
+ * the host to fetch children when not already loaded. */
11568
+ toggleExpanded(id, event) {
11569
+ event.stopPropagation();
11570
+ if (this.expandedIds.has(id)) {
11571
+ this.expandedIds.delete(id);
11572
+ }
11573
+ else {
11574
+ this.expandedIds.add(id);
11575
+ this.requestChildrenIfMissing(id);
11576
+ }
11541
11577
  this.cdr.markForCheck();
11542
11578
  }
11579
+ isPicked(id) {
11580
+ return this.pickedFolderId === id;
11581
+ }
11582
+ /** "Unorganized" row is disabled when the suite is already in Unorganized. */
11583
+ get isUnorganizedDisabled() {
11584
+ return this.currentFolderId == null;
11585
+ }
11586
+ /** Flattened, depth-indented row descriptors fed into the template `*ngFor`.
11587
+ * Walks `_folders`, derives chevron / loading / expanded state per node. */
11588
+ get flatRows() {
11589
+ const out = [];
11590
+ const walk = (nodes, depth) => {
11591
+ for (const n of nodes || []) {
11592
+ // Drive the chevron from the backend's authoritative `hasChildren` so
11593
+ // it shows BEFORE children are loaded — required for lazy-load.
11594
+ const hasChildren = !!n.hasChildren;
11595
+ const expanded = this.expandedIds.has(n.id);
11596
+ const childrenLoading = !!n.childrenLoading;
11597
+ const childrenLoaded = !!(n.children && n.children.length);
11598
+ out.push({
11599
+ id: n.id,
11600
+ name: n.name,
11601
+ depth,
11602
+ disabled: n.id === this.currentFolderId,
11603
+ hasChildren,
11604
+ expanded,
11605
+ childrenLoading,
11606
+ showLoadingPlaceholder: expanded && childrenLoading && !childrenLoaded,
11607
+ });
11608
+ if (expanded && childrenLoaded)
11609
+ walk(n.children, depth + 1);
11610
+ }
11611
+ };
11612
+ walk(this._folders, 0);
11613
+ return out;
11614
+ }
11543
11615
  /** True once the user has picked a destination via the embedded tree. Drives
11544
11616
  * the destination-readout styling (indigo when picked, muted when not). */
11545
11617
  get hasPick() {
@@ -11608,6 +11680,46 @@ class MoveTestSuiteDialogComponent {
11608
11680
  onDestinationFieldBlurred(event) {
11609
11681
  this.destinationFieldBlur.emit(event);
11610
11682
  }
11683
+ requestChildrenIfMissing(id) {
11684
+ const node = this.findNode(this._folders, id);
11685
+ if (!node)
11686
+ return;
11687
+ if (node.hasChildren && node.loadedPages == null && !node.childrenLoading) {
11688
+ this.folderChildrenRequested.emit(id);
11689
+ }
11690
+ }
11691
+ seedExpandedIds() {
11692
+ this.expandedIds = new Set();
11693
+ const seed = this.currentFolderId != null ? this.currentFolderId : this.pickedFolderId;
11694
+ if (seed != null) {
11695
+ const trail = [];
11696
+ this.collectAncestors(this._folders, seed, trail);
11697
+ trail.forEach((id) => this.expandedIds.add(id));
11698
+ }
11699
+ }
11700
+ collectAncestors(nodes, targetId, acc) {
11701
+ for (const n of nodes || []) {
11702
+ acc.push(n.id);
11703
+ if (n.id === targetId)
11704
+ return true;
11705
+ if (n.children && this.collectAncestors(n.children, targetId, acc))
11706
+ return true;
11707
+ acc.pop();
11708
+ }
11709
+ return false;
11710
+ }
11711
+ findNode(nodes, id) {
11712
+ for (const n of nodes || []) {
11713
+ if (n.id === id)
11714
+ return n;
11715
+ if (n.children?.length) {
11716
+ const hit = this.findNode(n.children, id);
11717
+ if (hit)
11718
+ return hit;
11719
+ }
11720
+ }
11721
+ return null;
11722
+ }
11611
11723
  findFolderName(nodes, id) {
11612
11724
  for (const n of nodes || []) {
11613
11725
  if (n.id === id)
@@ -11622,7 +11734,7 @@ class MoveTestSuiteDialogComponent {
11622
11734
  }
11623
11735
  }
11624
11736
  MoveTestSuiteDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: MoveTestSuiteDialogComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
11625
- MoveTestSuiteDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: MoveTestSuiteDialogComponent, selector: "cqa-move-test-suite-dialog", inputs: { folders: "folders", labels: "labels", testSuiteLabels: "testSuiteLabels", currentFolderId: "currentFolderId", currentFolderName: "currentFolderName", suiteName: "suiteName", pickedFolderId: "pickedFolderId", pickerHeight: "pickerHeight", fieldsDisabled: "fieldsDisabled" }, outputs: { pickedFolderIdChange: "pickedFolderIdChange", submitted: "submitted", cancelled: "cancelled", currentFieldFocus: "currentFieldFocus", currentFieldBlur: "currentFieldBlur", destinationFieldFocus: "destinationFieldFocus", destinationFieldBlur: "destinationFieldBlur" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: `
11737
+ MoveTestSuiteDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: MoveTestSuiteDialogComponent, selector: "cqa-move-test-suite-dialog", inputs: { folders: "folders", labels: "labels", testSuiteLabels: "testSuiteLabels", currentFolderId: "currentFolderId", currentFolderName: "currentFolderName", suiteName: "suiteName", pickedFolderId: "pickedFolderId", pickerHeight: "pickerHeight", fieldsDisabled: "fieldsDisabled" }, outputs: { pickedFolderIdChange: "pickedFolderIdChange", submitted: "submitted", cancelled: "cancelled", folderChildrenRequested: "folderChildrenRequested", currentFieldFocus: "currentFieldFocus", currentFieldBlur: "currentFieldBlur", destinationFieldFocus: "destinationFieldFocus", destinationFieldBlur: "destinationFieldBlur" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: `
11626
11738
  <div class="cqa-flex cqa-flex-col cqa-gap-2 cqa-w-full">
11627
11739
  <!-- Test suite name (read-only display; surfaces which suite is being moved) -->
11628
11740
  <cqa-custom-input
@@ -11655,17 +11767,84 @@ MoveTestSuiteDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12
11655
11767
  (blurred)="onDestinationFieldBlurred($event)"
11656
11768
  ></cqa-custom-input>
11657
11769
 
11658
- <!-- Folder tree picker -->
11659
- <cqa-move-to-folder-dialog
11660
- [folders]="folders"
11661
- [labels]="labels"
11662
- [currentFolderId]="currentFolderId"
11663
- [pickedFolderId]="pickedFolderId"
11664
- [pickerHeight]="pickerHeight"
11665
- (pickedFolderIdChange)="onParentPicked($event)"
11666
- ></cqa-move-to-folder-dialog>
11770
+ <!-- Folder tree picker (inlined; takes reference from cqa-move-to-folder-dialog
11771
+ but does not embed it, so the lazy-fetch wiring and expansion state stay
11772
+ local to this dialog). -->
11773
+ <ng-template #folderIconTpl>
11774
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-flex-shrink-0">
11775
+ <path d="M15.6375 12.6377C15.6375 13.0355 15.4794 13.4171 15.1981 13.6984C14.9168 13.9797 14.5353 14.1377 14.1375 14.1377H2.13745C1.73963 14.1377 1.3581 13.9797 1.07679 13.6984C0.795486 13.4171 0.637451 13.0355 0.637451 12.6377V2.1377C0.637451 1.73987 0.795486 1.35834 1.07679 1.07704C1.3581 0.795731 1.73963 0.637695 2.13745 0.637695H5.88745L7.38745 2.8877H14.1375C14.5353 2.8877 14.9168 3.04573 15.1981 3.32704C15.4794 3.60834 15.6375 3.98987 15.6375 4.3877V12.6377Z" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
11776
+ </svg>
11777
+ </ng-template>
11778
+
11779
+ <ng-template #unorganizedIconTpl>
11780
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-flex-shrink-0">
11781
+ <path d="M14.6875 5.5V12.5C14.6875 13.3 14.0375 14 13.1875 14H3.8125C2.9625 14 2.3125 13.3 2.3125 12.5V5.5M14.6875 5.5L12.7875 1.7C12.5375 1.2 12.0875 1 11.5875 1H5.4125C4.9125 1 4.4625 1.2 4.2125 1.7L2.3125 5.5M14.6875 5.5H2.3125M6.1875 8.5H10.8125" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
11782
+ </svg>
11783
+ </ng-template>
11784
+
11785
+ <div class="cqa-flex cqa-flex-col cqa-border-solid cqa-border cqa-border-[#E2E2E3] cqa-rounded-[10px] cqa-py-2 cqa-w-full cqa-overflow-y-auto cqa-bg-white cqa-scrollbar-thin" [style.height]="pickerHeight">
11786
+ <div
11787
+ role="button"
11788
+ tabindex="0"
11789
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-px-4 cqa-py-2 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
11790
+ [ngClass]="isPicked(null) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
11791
+ [class.cqa-opacity-40]="isUnorganizedDisabled"
11792
+ [class.cqa-cursor-not-allowed]="isUnorganizedDisabled"
11793
+ [attr.aria-disabled]="isUnorganizedDisabled || null"
11794
+ (click)="!isUnorganizedDisabled && pick(null)"
11795
+ (keydown.enter)="!isUnorganizedDisabled && pick(null)"
11796
+ (keydown.space)="$event.preventDefault(); !isUnorganizedDisabled && pick(null)"
11797
+ >
11798
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-flex-shrink-0"></span>
11799
+ <ng-container *ngTemplateOutlet="unorganizedIconTpl"></ng-container>
11800
+ <span>{{ labels.moveDialogRoot }}</span>
11801
+ </div>
11802
+
11803
+ <ng-container *ngFor="let row of flatRows; trackBy: trackById">
11804
+ <div
11805
+ role="button"
11806
+ tabindex="0"
11807
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-py-2 cqa-pr-4 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
11808
+ [ngClass]="isPicked(row.id) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
11809
+ [class.cqa-opacity-40]="row.disabled"
11810
+ [class.cqa-cursor-not-allowed]="row.disabled"
11811
+ [style.paddingLeft.px]="16 + row.depth * 24"
11812
+ (click)="!row.disabled && pick(row.id)"
11813
+ (keydown.enter)="!row.disabled && pick(row.id)"
11814
+ (keydown.space)="!row.disabled && $event.preventDefault(); !row.disabled && pick(row.id)"
11815
+ >
11816
+ <button
11817
+ *ngIf="row.hasChildren; else chevronPlaceholder"
11818
+ type="button"
11819
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-5 cqa-h-5 cqa-flex-shrink-0 cqa-rounded cqa-text-neutral-600 hover:cqa-bg-neutral-100 hover:cqa-text-neutral-900"
11820
+ [attr.aria-label]="row.expanded ? 'Collapse ' + row.name : 'Expand ' + row.name"
11821
+ (click)="toggleExpanded(row.id!, $event)"
11822
+ >
11823
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
11824
+ [class.cqa-rotate-90]="row.expanded" style="transition: transform 120ms ease;">
11825
+ <path d="M5 3L9 7L5 11" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
11826
+ </svg>
11827
+ </button>
11828
+ <ng-template #chevronPlaceholder>
11829
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-flex-shrink-0"></span>
11830
+ </ng-template>
11831
+
11832
+ <ng-container *ngTemplateOutlet="folderIconTpl"></ng-container>
11833
+ <span class="cqa-truncate">{{ row.name }}</span>
11834
+ </div>
11835
+
11836
+ <div
11837
+ *ngIf="row.showLoadingPlaceholder"
11838
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-py-2 cqa-pr-4 cqa-text-sm cqa-text-neutral-500 cqa-italic"
11839
+ [style.paddingLeft.px]="16 + (row.depth + 1) * 24"
11840
+ >
11841
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-flex-shrink-0"></span>
11842
+ <span>Loading…</span>
11843
+ </div>
11844
+ </ng-container>
11845
+ </div>
11667
11846
  </div>
11668
- `, isInline: true, components: [{ type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["inputId", "label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: MoveToFolderDialogComponent, selector: "cqa-move-to-folder-dialog", inputs: ["folders", "labels", "currentFolderId", "pickedFolderId", "initialExpandedIds", "rootDisabled", "pickerHeight"], outputs: ["folderPicked", "pickedFolderIdChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11847
+ `, isInline: true, components: [{ type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["inputId", "label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }], directives: [{ type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11669
11848
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: MoveTestSuiteDialogComponent, decorators: [{
11670
11849
  type: Component,
11671
11850
  args: [{ selector: 'cqa-move-test-suite-dialog', template: `
@@ -11701,15 +11880,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
11701
11880
  (blurred)="onDestinationFieldBlurred($event)"
11702
11881
  ></cqa-custom-input>
11703
11882
 
11704
- <!-- Folder tree picker -->
11705
- <cqa-move-to-folder-dialog
11706
- [folders]="folders"
11707
- [labels]="labels"
11708
- [currentFolderId]="currentFolderId"
11709
- [pickedFolderId]="pickedFolderId"
11710
- [pickerHeight]="pickerHeight"
11711
- (pickedFolderIdChange)="onParentPicked($event)"
11712
- ></cqa-move-to-folder-dialog>
11883
+ <!-- Folder tree picker (inlined; takes reference from cqa-move-to-folder-dialog
11884
+ but does not embed it, so the lazy-fetch wiring and expansion state stay
11885
+ local to this dialog). -->
11886
+ <ng-template #folderIconTpl>
11887
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-flex-shrink-0">
11888
+ <path d="M15.6375 12.6377C15.6375 13.0355 15.4794 13.4171 15.1981 13.6984C14.9168 13.9797 14.5353 14.1377 14.1375 14.1377H2.13745C1.73963 14.1377 1.3581 13.9797 1.07679 13.6984C0.795486 13.4171 0.637451 13.0355 0.637451 12.6377V2.1377C0.637451 1.73987 0.795486 1.35834 1.07679 1.07704C1.3581 0.795731 1.73963 0.637695 2.13745 0.637695H5.88745L7.38745 2.8877H14.1375C14.5353 2.8877 14.9168 3.04573 15.1981 3.32704C15.4794 3.60834 15.6375 3.98987 15.6375 4.3877V12.6377Z" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
11889
+ </svg>
11890
+ </ng-template>
11891
+
11892
+ <ng-template #unorganizedIconTpl>
11893
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-flex-shrink-0">
11894
+ <path d="M14.6875 5.5V12.5C14.6875 13.3 14.0375 14 13.1875 14H3.8125C2.9625 14 2.3125 13.3 2.3125 12.5V5.5M14.6875 5.5L12.7875 1.7C12.5375 1.2 12.0875 1 11.5875 1H5.4125C4.9125 1 4.4625 1.2 4.2125 1.7L2.3125 5.5M14.6875 5.5H2.3125M6.1875 8.5H10.8125" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
11895
+ </svg>
11896
+ </ng-template>
11897
+
11898
+ <div class="cqa-flex cqa-flex-col cqa-border-solid cqa-border cqa-border-[#E2E2E3] cqa-rounded-[10px] cqa-py-2 cqa-w-full cqa-overflow-y-auto cqa-bg-white cqa-scrollbar-thin" [style.height]="pickerHeight">
11899
+ <div
11900
+ role="button"
11901
+ tabindex="0"
11902
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-px-4 cqa-py-2 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
11903
+ [ngClass]="isPicked(null) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
11904
+ [class.cqa-opacity-40]="isUnorganizedDisabled"
11905
+ [class.cqa-cursor-not-allowed]="isUnorganizedDisabled"
11906
+ [attr.aria-disabled]="isUnorganizedDisabled || null"
11907
+ (click)="!isUnorganizedDisabled && pick(null)"
11908
+ (keydown.enter)="!isUnorganizedDisabled && pick(null)"
11909
+ (keydown.space)="$event.preventDefault(); !isUnorganizedDisabled && pick(null)"
11910
+ >
11911
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-flex-shrink-0"></span>
11912
+ <ng-container *ngTemplateOutlet="unorganizedIconTpl"></ng-container>
11913
+ <span>{{ labels.moveDialogRoot }}</span>
11914
+ </div>
11915
+
11916
+ <ng-container *ngFor="let row of flatRows; trackBy: trackById">
11917
+ <div
11918
+ role="button"
11919
+ tabindex="0"
11920
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-py-2 cqa-pr-4 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
11921
+ [ngClass]="isPicked(row.id) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
11922
+ [class.cqa-opacity-40]="row.disabled"
11923
+ [class.cqa-cursor-not-allowed]="row.disabled"
11924
+ [style.paddingLeft.px]="16 + row.depth * 24"
11925
+ (click)="!row.disabled && pick(row.id)"
11926
+ (keydown.enter)="!row.disabled && pick(row.id)"
11927
+ (keydown.space)="!row.disabled && $event.preventDefault(); !row.disabled && pick(row.id)"
11928
+ >
11929
+ <button
11930
+ *ngIf="row.hasChildren; else chevronPlaceholder"
11931
+ type="button"
11932
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-5 cqa-h-5 cqa-flex-shrink-0 cqa-rounded cqa-text-neutral-600 hover:cqa-bg-neutral-100 hover:cqa-text-neutral-900"
11933
+ [attr.aria-label]="row.expanded ? 'Collapse ' + row.name : 'Expand ' + row.name"
11934
+ (click)="toggleExpanded(row.id!, $event)"
11935
+ >
11936
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
11937
+ [class.cqa-rotate-90]="row.expanded" style="transition: transform 120ms ease;">
11938
+ <path d="M5 3L9 7L5 11" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
11939
+ </svg>
11940
+ </button>
11941
+ <ng-template #chevronPlaceholder>
11942
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-flex-shrink-0"></span>
11943
+ </ng-template>
11944
+
11945
+ <ng-container *ngTemplateOutlet="folderIconTpl"></ng-container>
11946
+ <span class="cqa-truncate">{{ row.name }}</span>
11947
+ </div>
11948
+
11949
+ <div
11950
+ *ngIf="row.showLoadingPlaceholder"
11951
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-py-2 cqa-pr-4 cqa-text-sm cqa-text-neutral-500 cqa-italic"
11952
+ [style.paddingLeft.px]="16 + (row.depth + 1) * 24"
11953
+ >
11954
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-flex-shrink-0"></span>
11955
+ <span>Loading…</span>
11956
+ </div>
11957
+ </ng-container>
11958
+ </div>
11713
11959
  </div>
11714
11960
  `, host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [] }]
11715
11961
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { folders: [{
@@ -11736,6 +11982,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
11736
11982
  type: Output
11737
11983
  }], cancelled: [{
11738
11984
  type: Output
11985
+ }], folderChildrenRequested: [{
11986
+ type: Output
11739
11987
  }], currentFieldFocus: [{
11740
11988
  type: Output
11741
11989
  }], currentFieldBlur: [{