@cqa-lib/cqa-ui 1.0.93 → 1.0.95
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.
- package/esm2020/lib/dynamic-select/dynamic-select-field.component.mjs +31 -6
- package/fesm2015/cqa-lib-cqa-ui.mjs +39 -14
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +30 -5
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/dynamic-select/dynamic-select-field.component.d.ts +10 -0
- package/package.json +1 -1
|
@@ -1532,8 +1532,14 @@ class DynamicSelectFieldComponent {
|
|
|
1532
1532
|
this.searchTextByKey = {};
|
|
1533
1533
|
this.lastOptionsLength = 0;
|
|
1534
1534
|
this.loadingMore = false;
|
|
1535
|
+
/**
|
|
1536
|
+
* Guard to ensure load-more is only triggered after the user has scrolled
|
|
1537
|
+
* at least once since opening the panel. Prevents auto-load on open.
|
|
1538
|
+
*/
|
|
1539
|
+
this.hasScrolledSinceOpen = false;
|
|
1535
1540
|
this.onPanelScroll = () => {
|
|
1536
1541
|
var _a, _b, _c, _d;
|
|
1542
|
+
this.hasScrolledSinceOpen = true;
|
|
1537
1543
|
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.hasMore) || this.loadingMore)
|
|
1538
1544
|
return;
|
|
1539
1545
|
const el = this.panelScrollEl;
|
|
@@ -1569,7 +1575,7 @@ class DynamicSelectFieldComponent {
|
|
|
1569
1575
|
return this.hasExistingValue(controlValue) ? undefined : (_d = this.config) === null || _d === void 0 ? void 0 : _d.placeholder;
|
|
1570
1576
|
}
|
|
1571
1577
|
ngOnChanges(changes) {
|
|
1572
|
-
var _a, _b, _c;
|
|
1578
|
+
var _a, _b, _c, _d;
|
|
1573
1579
|
if ('config' in changes) {
|
|
1574
1580
|
// When config changes (including toggling multiple), ensure control value shape matches
|
|
1575
1581
|
this.syncControlValueForMultipleMode();
|
|
@@ -1580,8 +1586,19 @@ class DynamicSelectFieldComponent {
|
|
|
1580
1586
|
this.loadingMore = false;
|
|
1581
1587
|
}
|
|
1582
1588
|
this.lastOptionsLength = len;
|
|
1589
|
+
// If consumer indicates no more results, clear loading state and any observers
|
|
1590
|
+
if (!((_b = this.config) === null || _b === void 0 ? void 0 : _b.hasMore)) {
|
|
1591
|
+
this.loadingMore = false;
|
|
1592
|
+
if (this.loadMoreObserver) {
|
|
1593
|
+
try {
|
|
1594
|
+
this.loadMoreObserver.disconnect();
|
|
1595
|
+
}
|
|
1596
|
+
catch (_e) { }
|
|
1597
|
+
this.loadMoreObserver = undefined;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1583
1600
|
// If panel is open and hasMore is true, ensure the sentinel is being observed.
|
|
1584
|
-
if (((
|
|
1601
|
+
if (((_c = this.selectRef) === null || _c === void 0 ? void 0 : _c.panelOpen) && ((_d = this.config) === null || _d === void 0 ? void 0 : _d.hasMore)) {
|
|
1585
1602
|
setTimeout(() => this.setupLoadMoreObserver(), 0);
|
|
1586
1603
|
}
|
|
1587
1604
|
}
|
|
@@ -1747,14 +1764,20 @@ class DynamicSelectFieldComponent {
|
|
|
1747
1764
|
catch (_b) { }
|
|
1748
1765
|
}
|
|
1749
1766
|
onSelectOpenedChange(opened, _select) {
|
|
1750
|
-
var _a, _b, _c, _d, _e;
|
|
1767
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1751
1768
|
if (opened) {
|
|
1752
1769
|
// Emit click event when select is opened (clicked)
|
|
1753
1770
|
this.selectClick.emit();
|
|
1771
|
+
// Reset loadingMore when opening if options already exist (don't show loader on initial open)
|
|
1772
|
+
if ((((_a = this.config) === null || _a === void 0 ? void 0 : _a.options) || []).length > 0) {
|
|
1773
|
+
this.loadingMore = false;
|
|
1774
|
+
}
|
|
1775
|
+
// Ensure we only trigger load-more after a real user scroll
|
|
1776
|
+
this.hasScrolledSinceOpen = false;
|
|
1754
1777
|
}
|
|
1755
1778
|
if (!opened) {
|
|
1756
1779
|
// Reset search text on close so the next open shows full list
|
|
1757
|
-
if ((
|
|
1780
|
+
if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.key) {
|
|
1758
1781
|
this.searchTextByKey[this.config.key] = '';
|
|
1759
1782
|
}
|
|
1760
1783
|
// Ensure any previous custom listeners are cleared (legacy compatibility)
|
|
@@ -1767,7 +1790,7 @@ class DynamicSelectFieldComponent {
|
|
|
1767
1790
|
try {
|
|
1768
1791
|
this.loadMoreObserver.disconnect();
|
|
1769
1792
|
}
|
|
1770
|
-
catch (
|
|
1793
|
+
catch (_h) { }
|
|
1771
1794
|
this.loadMoreObserver = undefined;
|
|
1772
1795
|
}
|
|
1773
1796
|
// Remove scroll listener if attached
|
|
@@ -1775,26 +1798,28 @@ class DynamicSelectFieldComponent {
|
|
|
1775
1798
|
try {
|
|
1776
1799
|
this.panelScrollEl.removeEventListener('scroll', this.onPanelScroll);
|
|
1777
1800
|
}
|
|
1778
|
-
catch (
|
|
1801
|
+
catch (_j) { }
|
|
1779
1802
|
this.panelScrollEl = undefined;
|
|
1780
1803
|
}
|
|
1804
|
+
// Reset loadingMore when closing
|
|
1805
|
+
this.loadingMore = false;
|
|
1781
1806
|
return;
|
|
1782
1807
|
}
|
|
1783
1808
|
// Focus the search box if enabled
|
|
1784
|
-
if ((
|
|
1809
|
+
if ((_c = this.config) === null || _c === void 0 ? void 0 : _c.searchable) {
|
|
1785
1810
|
setTimeout(() => {
|
|
1786
1811
|
const input = document.querySelector('.ts-select-search-input');
|
|
1787
1812
|
input === null || input === void 0 ? void 0 : input.focus();
|
|
1788
1813
|
}, 0);
|
|
1789
1814
|
}
|
|
1790
|
-
//
|
|
1791
|
-
if ((
|
|
1815
|
+
// Optional: only trigger initial fetch on open when explicitly requested.
|
|
1816
|
+
if (((_d = this.config) === null || _d === void 0 ? void 0 : _d.serverSearch) && this.toBoolean((_e = this.config) === null || _e === void 0 ? void 0 : _e.initialFetchOnOpen)) {
|
|
1792
1817
|
const key = this.config.key;
|
|
1793
1818
|
const q = this.searchTextByKey[key] || '';
|
|
1794
1819
|
try {
|
|
1795
|
-
(
|
|
1820
|
+
(_g = (_f = this.config).onSearch) === null || _g === void 0 ? void 0 : _g.call(_f, q);
|
|
1796
1821
|
}
|
|
1797
|
-
catch (
|
|
1822
|
+
catch (_k) { }
|
|
1798
1823
|
this.searchChange.emit({ key, query: q });
|
|
1799
1824
|
}
|
|
1800
1825
|
// Setup infinite scroll observer on sentinel
|
|
@@ -1987,7 +2012,7 @@ class DynamicSelectFieldComponent {
|
|
|
1987
2012
|
for (const entry of entries) {
|
|
1988
2013
|
if (entry.isIntersecting) {
|
|
1989
2014
|
// Request more only if not currently loading and hasMore still true
|
|
1990
|
-
if (!this.loadingMore && ((_a = this.config) === null || _a === void 0 ? void 0 : _a.hasMore)) {
|
|
2015
|
+
if (this.hasScrolledSinceOpen && !this.loadingMore && ((_a = this.config) === null || _a === void 0 ? void 0 : _a.hasMore)) {
|
|
1991
2016
|
this.loadingMore = true;
|
|
1992
2017
|
const key = ((_b = this.config) === null || _b === void 0 ? void 0 : _b.key) || '';
|
|
1993
2018
|
const q = this.searchTextByKey[key] || '';
|
|
@@ -2008,10 +2033,10 @@ class DynamicSelectFieldComponent {
|
|
|
2008
2033
|
}
|
|
2009
2034
|
}
|
|
2010
2035
|
DynamicSelectFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DynamicSelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2011
|
-
DynamicSelectFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: { form: "form", config: "config" }, outputs: { selectionChange: "selectionChange", selectClick: "selectClick", searchChange: "searchChange", loadMore: "loadMore" }, host: { listeners: { "document:click": "handleDocumentClick($event)" } }, viewQueries: [{ propertyName: "selectRef", first: true, predicate: ["selectRef"], descendants: true }, { propertyName: "hostEl", first: true, predicate: ["host"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\">\n <ng-container [formGroup]=\"form\">\n <label *ngIf=\"config.label\"\n class=\"form-label cqa-text-[#374151] cqa-text-[14px] cqa-font-medium cqa-block cqa-leading-[1.4] cqa-mb-2\">{{\n config.label }}</label>\n <mat-form-field #host class=\"mat-select-custom cqa-w-full\" appearance=\"fill\">\n <mat-select #selectRef=\"matSelect\" [placeholder]=\"displayPlaceholder\" [disabled]=\"isDisabled\" [multiple]=\"isMultiple\"\n disableOptionCentering [panelClass]=\"panelClass\" [formControlName]=\"config.key\"\n (openedChange)=\"onSelectOpenedChange($event, selectRef)\" (selectionChange)=\"onSelectionChange($event, selectRef)\">\n\n <mat-option *ngIf=\"config.searchable\" class=\"ts-select-search\" disabled>\n <input class=\"ts-select-search-input cqa-text-black-100\" type=\"text\" [value]=\"searchTextByKey[config.key] || ''\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\" (input)=\"onSearch(config.key, $any($event.target).value)\"\n placeholder=\"Search...\" />\n </mat-option>\n \n <mat-option [ngClass]=\"{'checkmark': config.optionStyle === 'checkmark','checkbox': config.optionStyle !== 'checkmark','mat-selected': allSelected}\" [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngIf=\"isMultiple && config.showSelectAll\" [value]=\"SELECT_ALL_VALUE\">\n <ng-container *ngIf=\"useCheckboxStyle; else selectAllDefaultTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"allSelected ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"allSelected\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ config.selectAllLabel || 'All' }}</span>\n </span>\n </ng-container>\n <ng-template #selectAllDefaultTpl>\n {{ config.selectAllLabel || 'All' }}\n </ng-template>\n </mat-option>\n\n <mat-option [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngFor=\"let opt of filteredOptions(config)\" [value]=\"opt.id ?? opt.value\">\n <ng-container *ngIf=\"useCheckboxStyle; else defaultOptionTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"isOptionSelected(opt) ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"isOptionSelected(opt)\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ opt.name ?? opt.label ?? opt.value }}</span>\n </span>\n </ng-container>\n <ng-template #defaultOptionTpl>\n {{ opt.name ?? opt.label ?? opt.value }}\n </ng-template>\n </mat-option>\n \n <!-- No results state (only when not loading and no options) -->\n <mat-option disabled *ngIf=\"!(config?.options?.length || 0) && !(config?.isLoading || loadingMore)\">\n No results\n </mat-option>\n <!-- Infinite scroll sentinel (serverSearch or explicit hasMore) -->\n <mat-option disabled class=\"load-more-sentinel\" *ngIf=\"config?.hasMore\">\n <span *ngIf=\"
|
|
2036
|
+
DynamicSelectFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: { form: "form", config: "config" }, outputs: { selectionChange: "selectionChange", selectClick: "selectClick", searchChange: "searchChange", loadMore: "loadMore" }, host: { listeners: { "document:click": "handleDocumentClick($event)" } }, viewQueries: [{ propertyName: "selectRef", first: true, predicate: ["selectRef"], descendants: true }, { propertyName: "hostEl", first: true, predicate: ["host"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\">\n <ng-container [formGroup]=\"form\">\n <label *ngIf=\"config.label\"\n class=\"form-label cqa-text-[#374151] cqa-text-[14px] cqa-font-medium cqa-block cqa-leading-[1.4] cqa-mb-2\">{{\n config.label }}</label>\n <mat-form-field #host class=\"mat-select-custom cqa-w-full\" appearance=\"fill\">\n <mat-select #selectRef=\"matSelect\" [placeholder]=\"displayPlaceholder\" [disabled]=\"isDisabled\" [multiple]=\"isMultiple\"\n disableOptionCentering [panelClass]=\"panelClass\" [formControlName]=\"config.key\"\n (openedChange)=\"onSelectOpenedChange($event, selectRef)\" (selectionChange)=\"onSelectionChange($event, selectRef)\">\n\n <mat-option *ngIf=\"config.searchable\" class=\"ts-select-search\" disabled>\n <input class=\"ts-select-search-input cqa-text-black-100\" type=\"text\" [value]=\"searchTextByKey[config.key] || ''\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\" (input)=\"onSearch(config.key, $any($event.target).value)\"\n placeholder=\"Search...\" />\n </mat-option>\n \n <mat-option [ngClass]=\"{'checkmark': config.optionStyle === 'checkmark','checkbox': config.optionStyle !== 'checkmark','mat-selected': allSelected}\" [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngIf=\"isMultiple && config.showSelectAll\" [value]=\"SELECT_ALL_VALUE\">\n <ng-container *ngIf=\"useCheckboxStyle; else selectAllDefaultTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"allSelected ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"allSelected\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ config.selectAllLabel || 'All' }}</span>\n </span>\n </ng-container>\n <ng-template #selectAllDefaultTpl>\n {{ config.selectAllLabel || 'All' }}\n </ng-template>\n </mat-option>\n\n <mat-option [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngFor=\"let opt of filteredOptions(config)\" [value]=\"opt.id ?? opt.value\">\n <ng-container *ngIf=\"useCheckboxStyle; else defaultOptionTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"isOptionSelected(opt) ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"isOptionSelected(opt)\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ opt.name ?? opt.label ?? opt.value }}</span>\n </span>\n </ng-container>\n <ng-template #defaultOptionTpl>\n {{ opt.name ?? opt.label ?? opt.value }}\n </ng-template>\n </mat-option>\n \n <!-- No results state (only when not loading and no options) -->\n <mat-option disabled *ngIf=\"!(config?.options?.length || 0) && !(config?.isLoading || loadingMore)\">\n No results\n </mat-option>\n <!-- Infinite scroll sentinel (serverSearch or explicit hasMore) -->\n <mat-option disabled class=\"load-more-sentinel\" *ngIf=\"config?.hasMore\">\n <span *ngIf=\"loadingMore\">Loading...</span>\n <span *ngIf=\"!loadingMore\">Scroll to load more\u2026</span>\n </mat-option>\n </mat-select>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Inline spinner shown only when loading more (infinite scroll), never on initial open -->\n <svg *ngIf=\"loadingMore\" width=\"16\" height=\"16\" viewBox=\"0 0 50 50\" aria-label=\"loading\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"25\" cy=\"25\" r=\"20\" stroke=\"#E5E7EB\" stroke-width=\"6\" fill=\"none\"/>\n <path d=\"M45 25a20 20 0 0 0-20-20\" stroke=\"#4F46E5\" stroke-width=\"6\" fill=\"none\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 25 25\" to=\"360 25 25\"\n dur=\"0.8s\" repeatCount=\"indefinite\"/>\n </path>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#0A0A0A\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n </mat-form-field>\n </ng-container>\n</div>", components: [{ type: i3$2.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2012
2037
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DynamicSelectFieldComponent, decorators: [{
|
|
2013
2038
|
type: Component,
|
|
2014
|
-
args: [{ selector: 'cqa-dynamic-select', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-ui-root\">\n <ng-container [formGroup]=\"form\">\n <label *ngIf=\"config.label\"\n class=\"form-label cqa-text-[#374151] cqa-text-[14px] cqa-font-medium cqa-block cqa-leading-[1.4] cqa-mb-2\">{{\n config.label }}</label>\n <mat-form-field #host class=\"mat-select-custom cqa-w-full\" appearance=\"fill\">\n <mat-select #selectRef=\"matSelect\" [placeholder]=\"displayPlaceholder\" [disabled]=\"isDisabled\" [multiple]=\"isMultiple\"\n disableOptionCentering [panelClass]=\"panelClass\" [formControlName]=\"config.key\"\n (openedChange)=\"onSelectOpenedChange($event, selectRef)\" (selectionChange)=\"onSelectionChange($event, selectRef)\">\n\n <mat-option *ngIf=\"config.searchable\" class=\"ts-select-search\" disabled>\n <input class=\"ts-select-search-input cqa-text-black-100\" type=\"text\" [value]=\"searchTextByKey[config.key] || ''\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\" (input)=\"onSearch(config.key, $any($event.target).value)\"\n placeholder=\"Search...\" />\n </mat-option>\n \n <mat-option [ngClass]=\"{'checkmark': config.optionStyle === 'checkmark','checkbox': config.optionStyle !== 'checkmark','mat-selected': allSelected}\" [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngIf=\"isMultiple && config.showSelectAll\" [value]=\"SELECT_ALL_VALUE\">\n <ng-container *ngIf=\"useCheckboxStyle; else selectAllDefaultTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"allSelected ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"allSelected\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ config.selectAllLabel || 'All' }}</span>\n </span>\n </ng-container>\n <ng-template #selectAllDefaultTpl>\n {{ config.selectAllLabel || 'All' }}\n </ng-template>\n </mat-option>\n\n <mat-option [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngFor=\"let opt of filteredOptions(config)\" [value]=\"opt.id ?? opt.value\">\n <ng-container *ngIf=\"useCheckboxStyle; else defaultOptionTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"isOptionSelected(opt) ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"isOptionSelected(opt)\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ opt.name ?? opt.label ?? opt.value }}</span>\n </span>\n </ng-container>\n <ng-template #defaultOptionTpl>\n {{ opt.name ?? opt.label ?? opt.value }}\n </ng-template>\n </mat-option>\n \n <!-- No results state (only when not loading and no options) -->\n <mat-option disabled *ngIf=\"!(config?.options?.length || 0) && !(config?.isLoading || loadingMore)\">\n No results\n </mat-option>\n <!-- Infinite scroll sentinel (serverSearch or explicit hasMore) -->\n <mat-option disabled class=\"load-more-sentinel\" *ngIf=\"config?.hasMore\">\n <span *ngIf=\"
|
|
2039
|
+
args: [{ selector: 'cqa-dynamic-select', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-ui-root\">\n <ng-container [formGroup]=\"form\">\n <label *ngIf=\"config.label\"\n class=\"form-label cqa-text-[#374151] cqa-text-[14px] cqa-font-medium cqa-block cqa-leading-[1.4] cqa-mb-2\">{{\n config.label }}</label>\n <mat-form-field #host class=\"mat-select-custom cqa-w-full\" appearance=\"fill\">\n <mat-select #selectRef=\"matSelect\" [placeholder]=\"displayPlaceholder\" [disabled]=\"isDisabled\" [multiple]=\"isMultiple\"\n disableOptionCentering [panelClass]=\"panelClass\" [formControlName]=\"config.key\"\n (openedChange)=\"onSelectOpenedChange($event, selectRef)\" (selectionChange)=\"onSelectionChange($event, selectRef)\">\n\n <mat-option *ngIf=\"config.searchable\" class=\"ts-select-search\" disabled>\n <input class=\"ts-select-search-input cqa-text-black-100\" type=\"text\" [value]=\"searchTextByKey[config.key] || ''\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\" (input)=\"onSearch(config.key, $any($event.target).value)\"\n placeholder=\"Search...\" />\n </mat-option>\n \n <mat-option [ngClass]=\"{'checkmark': config.optionStyle === 'checkmark','checkbox': config.optionStyle !== 'checkmark','mat-selected': allSelected}\" [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngIf=\"isMultiple && config.showSelectAll\" [value]=\"SELECT_ALL_VALUE\">\n <ng-container *ngIf=\"useCheckboxStyle; else selectAllDefaultTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"allSelected ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"allSelected\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ config.selectAllLabel || 'All' }}</span>\n </span>\n </ng-container>\n <ng-template #selectAllDefaultTpl>\n {{ config.selectAllLabel || 'All' }}\n </ng-template>\n </mat-option>\n\n <mat-option [class]=\"config.optionStyle == 'checkmark' ? 'checkmark' : 'checkbox'\" *ngFor=\"let opt of filteredOptions(config)\" [value]=\"opt.id ?? opt.value\">\n <ng-container *ngIf=\"useCheckboxStyle; else defaultOptionTpl\">\n <span class=\"cqa-flex cqa-items-center\">\n <span class=\"cqa-w-4 cqa-h-4 cqa-flex-shrink-0 cqa-rounded-[4px] cqa-border cqa-border-[#D1D5DB] cqa-mr-2 cqa-flex cqa-items-center cqa-justify-center cqa-border-solid\"\n [ngStyle]=\"isOptionSelected(opt) ? {'background-color':'#4F46E5','border-color':'#4F46E5'} : {}\">\n <svg *ngIf=\"isOptionSelected(opt)\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10 3L4.5 8.5L2 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-min-w-0\">{{ opt.name ?? opt.label ?? opt.value }}</span>\n </span>\n </ng-container>\n <ng-template #defaultOptionTpl>\n {{ opt.name ?? opt.label ?? opt.value }}\n </ng-template>\n </mat-option>\n \n <!-- No results state (only when not loading and no options) -->\n <mat-option disabled *ngIf=\"!(config?.options?.length || 0) && !(config?.isLoading || loadingMore)\">\n No results\n </mat-option>\n <!-- Infinite scroll sentinel (serverSearch or explicit hasMore) -->\n <mat-option disabled class=\"load-more-sentinel\" *ngIf=\"config?.hasMore\">\n <span *ngIf=\"loadingMore\">Loading...</span>\n <span *ngIf=\"!loadingMore\">Scroll to load more\u2026</span>\n </mat-option>\n </mat-select>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Inline spinner shown only when loading more (infinite scroll), never on initial open -->\n <svg *ngIf=\"loadingMore\" width=\"16\" height=\"16\" viewBox=\"0 0 50 50\" aria-label=\"loading\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"25\" cy=\"25\" r=\"20\" stroke=\"#E5E7EB\" stroke-width=\"6\" fill=\"none\"/>\n <path d=\"M45 25a20 20 0 0 0-20-20\" stroke=\"#4F46E5\" stroke-width=\"6\" fill=\"none\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 25 25\" to=\"360 25 25\"\n dur=\"0.8s\" repeatCount=\"indefinite\"/>\n </path>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#0A0A0A\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n </mat-form-field>\n </ng-container>\n</div>", styles: [] }]
|
|
2015
2040
|
}], propDecorators: { form: [{
|
|
2016
2041
|
type: Input
|
|
2017
2042
|
}], config: [{
|