nexheal-lib 0.0.51 → 0.0.52

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.
@@ -2802,7 +2802,15 @@ class PaginatedAutocompleteControl {
2802
2802
  _displayedOptions = [];
2803
2803
  set options(value) {
2804
2804
  const incoming = value || [];
2805
- if (this._pendingPage <= 1) {
2805
+ if (this.paginationType === 'arrow') {
2806
+ // Arrow mode: discrete pages — each load REPLACES the view and is cached
2807
+ this._displayedOptions = [...incoming];
2808
+ this.pageCache.set(this._pendingPage, [...incoming]);
2809
+ this.currentPage = this._pendingPage;
2810
+ this.highlightedIndex = incoming.length > 0 ? 0 : null;
2811
+ this.resetListScroll();
2812
+ }
2813
+ else if (this._pendingPage <= 1) {
2806
2814
  this._displayedOptions = [...incoming];
2807
2815
  }
2808
2816
  else {
@@ -2812,22 +2820,13 @@ class PaginatedAutocompleteControl {
2812
2820
  ...this._displayedOptions,
2813
2821
  ...incoming.filter((o) => !existingIds.has(o.id)),
2814
2822
  ];
2815
- // Keyboard-triggered page load: move the highlight into the new items
2816
- if (this.pendingHighlightIndex !== null) {
2817
- const idx = Math.min(this.pendingHighlightIndex, this._displayedOptions.length - 1);
2818
- this.pendingHighlightIndex = null;
2819
- if (idx >= 0) {
2820
- this.highlightedIndex = idx;
2821
- setTimeout(() => this.scrollHighlightedItemIntoView(), 0);
2822
- }
2823
- }
2824
2823
  }
2825
2824
  this.isPageLoading = false;
2826
2825
  this.loadErrorMessage = null;
2827
2826
  this.failedPage = null;
2828
2827
  this.processValueBuffer();
2829
2828
  if (this.isDropdownOpen) {
2830
- if (this._pendingPage <= 1) {
2829
+ if (this._pendingPage <= 1 && this.paginationType !== 'arrow') {
2831
2830
  this.highlightedIndex = this._displayedOptions.length > 0 ? 0 : null;
2832
2831
  }
2833
2832
  setTimeout(() => {
@@ -2863,8 +2862,8 @@ class PaginatedAutocompleteControl {
2863
2862
  preventClearOnBlur = false;
2864
2863
  searchInput$ = new Subject();
2865
2864
  cancelPendingSearch = false;
2866
- /** When set, the highlight jumps to this index after the next page appends */
2867
- pendingHighlightIndex = null;
2865
+ /** Arrow mode: cache of visited pages for the current search */
2866
+ pageCache = new Map();
2868
2867
  onChange = () => { };
2869
2868
  onTouched = () => { };
2870
2869
  inputElement;
@@ -2881,6 +2880,11 @@ class PaginatedAutocompleteControl {
2881
2880
  get hasMore() {
2882
2881
  return this._displayedOptions.length < this.totalCount;
2883
2882
  }
2883
+ get totalPages() {
2884
+ return this.pageSize > 0
2885
+ ? Math.max(1, Math.ceil(this.totalCount / this.pageSize))
2886
+ : 1;
2887
+ }
2884
2888
  constructor() { }
2885
2889
  ngOnInit() {
2886
2890
  this.inputControl.markAsPristine();
@@ -2952,6 +2956,10 @@ class PaginatedAutocompleteControl {
2952
2956
  loadPage(page, search) {
2953
2957
  this.currentPage = page;
2954
2958
  this._pendingPage = page;
2959
+ if (page === 1) {
2960
+ // Fresh page-1 load = new search context; visited pages are stale
2961
+ this.pageCache.clear();
2962
+ }
2955
2963
  this.lastLoadedSearch = search;
2956
2964
  this.loadErrorMessage = null;
2957
2965
  this.failedPage = null;
@@ -2972,6 +2980,41 @@ class PaginatedAutocompleteControl {
2972
2980
  // which after a selection holds the display name, not the search term.
2973
2981
  this.loadPage(this.currentPage + 1, this.lastLoadedSearch ?? (this.inputControl.value || ""));
2974
2982
  }
2983
+ /** Arrow mode: show an already-visited page instantly, no API call */
2984
+ showCachedPage(page) {
2985
+ const cached = this.pageCache.get(page);
2986
+ if (!cached)
2987
+ return false;
2988
+ this.currentPage = page;
2989
+ this._pendingPage = page;
2990
+ this._displayedOptions = [...cached];
2991
+ this.highlightedIndex = cached.length > 0 ? 0 : null;
2992
+ this.resetListScroll();
2993
+ return true;
2994
+ }
2995
+ nextArrowPage() {
2996
+ if (this.isPageLoading || this.currentPage >= this.totalPages)
2997
+ return;
2998
+ const next = this.currentPage + 1;
2999
+ if (!this.showCachedPage(next)) {
3000
+ this.loadPage(next, this.lastLoadedSearch || "");
3001
+ }
3002
+ }
3003
+ prevArrowPage() {
3004
+ if (this.isPageLoading || this.currentPage <= 1)
3005
+ return;
3006
+ const prev = this.currentPage - 1;
3007
+ if (!this.showCachedPage(prev)) {
3008
+ this.loadPage(prev, this.lastLoadedSearch || "");
3009
+ }
3010
+ }
3011
+ resetListScroll() {
3012
+ setTimeout(() => {
3013
+ if (this.dropdownElement) {
3014
+ this.dropdownElement.nativeElement.scrollTop = 0;
3015
+ }
3016
+ }, 0);
3017
+ }
2975
3018
  onListScroll(event) {
2976
3019
  if (this.paginationType !== 'scroll')
2977
3020
  return;
@@ -3062,6 +3105,9 @@ class PaginatedAutocompleteControl {
3062
3105
  this.lastLoadedSearch === term &&
3063
3106
  this._displayedOptions.length > 0) {
3064
3107
  this.openDropdown();
3108
+ if (this.paginationType === 'arrow') {
3109
+ this.showCachedPage(1);
3110
+ }
3065
3111
  const idx = this.selectedItems
3066
3112
  ? this._displayedOptions.findIndex((o) => o.id === this.selectedItems.id)
3067
3113
  : -1;
@@ -3140,28 +3186,14 @@ class PaginatedAutocompleteControl {
3140
3186
  case "ArrowRight": {
3141
3187
  if (this.paginationType !== 'arrow')
3142
3188
  break; // caret moves normally
3143
- // Jump forward a full page; fetch the next page if we're at the end
3144
- const target = (this.highlightedIndex ?? -1) + this.pageSize;
3145
- if (target > this._displayedOptions.length - 1 && this.hasMore) {
3146
- if (!this.isPageLoading) {
3147
- this.pendingHighlightIndex = this._displayedOptions.length;
3148
- this.loadNextPage();
3149
- }
3150
- }
3151
- else {
3152
- this.highlightedIndex = Math.min(target, this._displayedOptions.length - 1);
3153
- this.scrollHighlightedItemIntoView();
3154
- }
3189
+ this.nextArrowPage();
3155
3190
  event.preventDefault();
3156
3191
  break;
3157
3192
  }
3158
3193
  case "ArrowLeft": {
3159
3194
  if (this.paginationType !== 'arrow')
3160
3195
  break; // caret moves normally
3161
- // Jump back a full page
3162
- const target = (this.highlightedIndex ?? 0) - this.pageSize;
3163
- this.highlightedIndex = Math.max(target, 0);
3164
- this.scrollHighlightedItemIntoView();
3196
+ this.prevArrowPage();
3165
3197
  event.preventDefault();
3166
3198
  break;
3167
3199
  }
@@ -3253,7 +3285,7 @@ class PaginatedAutocompleteControl {
3253
3285
  useExisting: PaginatedAutocompleteControl,
3254
3286
  multi: true,
3255
3287
  },
3256
- ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }, { propertyName: "dropdownElement", first: true, predicate: ["dropdownElement"], descendants: true }], ngImport: i0, template: "<div class=\"form-group auto-complete paginated-autocomplete\" [ngClass]=\"customClass\" [class.readonly]=\"readonly\">\n @if (title) {\n <label class=\"inp-label\" [ngClass]=\"{ 'required': required }\">{{ title }}</label>\n }\n\n <input #inputElement type=\"text\" class=\"form-control\" [placeholder]=\"placeholder\" [formControl]=\"inputControl\"\n (input)=\"onUserType($event)\" (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" (focus)=\"onFocus()\" (click)=\"onInputClick()\"\n [ngClass]=\"{'is-invalid': error}\" [attr.autocomplete]=\"autocomplete || null\" [readonly]=\"readonly\" />\n\n <span class=\"focus-border\"></span>\n\n @if (!inputLoader && inputControl.value && clearVal && hasFocus) {\n <label class=\"clear\" (mousedown)=\"onOptionMouseDown()\" (click)=\"resetInput()\">\n <i class=\"he he-close\"></i>\n </label>\n }\n\n @if (isDropdownOpen) {\n <div #dropdownElement class=\"option-list\" (mousedown)=\"onOptionMouseDown()\" (scroll)=\"onListScroll($event)\">\n @if (options.length === 0 && !isPageLoading && !loadErrorMessage) {\n <div class=\"no-results\">\n <div>No results found</div>\n </div>\n } @else {\n @for (suggestion of options; track suggestion.id; let i = $index) {\n <div class=\"list-item\" [ngClass]=\"{\n 'active': suggestion === selectedItems,\n 'highlighted': highlightedIndex === i\n }\" (click)=\"selectSuggestion(suggestion)\" (mouseover)=\"onMouseOver(i)\">\n {{ suggestion[optionDisplayProperty] }}\n </div>\n }\n\n @if (isPageLoading) {\n <div class=\"list-loading\">Loading...</div>\n }\n\n @if (loadErrorMessage) {\n <div class=\"load-error\" (click)=\"retryLoad($event)\">\n {{ loadErrorMessage }} \u00B7 <span class=\"retry\">Retry</span>\n </div>\n }\n\n @if (paginationType === 'click' && hasMore && !isPageLoading && !loadErrorMessage) {\n <div class=\"load-more\" (click)=\"onLoadMoreClick($event)\">\n Load more ({{ options.length }} of {{ totalCount }})\n </div>\n }\n\n @if (totalCount > 0 && options.length > 0 && !loadErrorMessage && !(paginationType === 'click' && hasMore)) {\n <div class=\"list-footer\">\n {{ options.length }} of {{ totalCount }}\n @if (hasMore && paginationType === 'scroll') {\n <span> \u00B7 scroll for more</span>\n }\n @if (hasMore && paginationType === 'arrow') {\n <span> \u00B7 \u2190 \u2192 to page</span>\n }\n </div>\n }\n }\n </div>\n }\n\n @if (inputLoader) {\n <label class=\"loader input-loader\"></label>\n }\n\n @if (error) {\n <div class=\"val-msg\">{{ errorMessage }}</div>\n }\n</div>\n", styles: [".form-group.paginated-autocomplete .form-control{padding-right:unset}.form-group.paginated-autocomplete .clear{right:7px}.form-group.paginated-autocomplete .option-list{max-height:220px;overflow-y:auto}.form-group.paginated-autocomplete .option-list .no-results{padding:10px;color:#9b9b9b;text-align:center}.form-group.paginated-autocomplete .option-list .list-loading{padding:8px 10px;color:#9b9b9b;text-align:center;font-size:12px}.form-group.paginated-autocomplete .option-list .load-more{padding:8px 10px;text-align:center;cursor:pointer;color:#0d6efd;font-size:13px;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-more:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .load-error{padding:8px 10px;text-align:center;font-size:12px;color:#dc3545;cursor:pointer;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-error .retry{color:#0d6efd;text-decoration:underline}.form-group.paginated-autocomplete .option-list .load-error:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .list-footer{position:sticky;bottom:0;padding:4px 10px;text-align:center;font-size:11px;color:#9b9b9b;background-color:#fff;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
3288
+ ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }, { propertyName: "dropdownElement", first: true, predicate: ["dropdownElement"], descendants: true }], ngImport: i0, template: "<div class=\"form-group auto-complete paginated-autocomplete\" [ngClass]=\"customClass\" [class.readonly]=\"readonly\">\n @if (title) {\n <label class=\"inp-label\" [ngClass]=\"{ 'required': required }\">{{ title }}</label>\n }\n\n <input #inputElement type=\"text\" class=\"form-control\" [placeholder]=\"placeholder\" [formControl]=\"inputControl\"\n (input)=\"onUserType($event)\" (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" (focus)=\"onFocus()\" (click)=\"onInputClick()\"\n [ngClass]=\"{'is-invalid': error}\" [attr.autocomplete]=\"autocomplete || null\" [readonly]=\"readonly\" />\n\n <span class=\"focus-border\"></span>\n\n @if (!inputLoader && inputControl.value && clearVal && hasFocus) {\n <label class=\"clear\" (mousedown)=\"onOptionMouseDown()\" (click)=\"resetInput()\">\n <i class=\"he he-close\"></i>\n </label>\n }\n\n @if (isDropdownOpen) {\n <div #dropdownElement class=\"option-list\" (mousedown)=\"onOptionMouseDown()\" (scroll)=\"onListScroll($event)\">\n @if (options.length === 0 && !isPageLoading && !loadErrorMessage) {\n <div class=\"no-results\">\n <div>No results found</div>\n </div>\n } @else {\n @for (suggestion of options; track suggestion.id; let i = $index) {\n <div class=\"list-item\" [ngClass]=\"{\n 'active': suggestion === selectedItems,\n 'highlighted': highlightedIndex === i\n }\" (click)=\"selectSuggestion(suggestion)\" (mouseover)=\"onMouseOver(i)\">\n {{ suggestion[optionDisplayProperty] }}\n </div>\n }\n\n @if (isPageLoading) {\n <div class=\"list-loading\">Loading...</div>\n }\n\n @if (loadErrorMessage) {\n <div class=\"load-error\" (click)=\"retryLoad($event)\">\n {{ loadErrorMessage }} \u00B7 <span class=\"retry\">Retry</span>\n </div>\n }\n\n @if (paginationType === 'click' && hasMore && !isPageLoading && !loadErrorMessage) {\n <div class=\"load-more\" (click)=\"onLoadMoreClick($event)\">\n Load more ({{ options.length }} of {{ totalCount }})\n </div>\n }\n\n @if (totalCount > 0 && options.length > 0 && !loadErrorMessage && !(paginationType === 'click' && hasMore)) {\n <div class=\"list-footer\">\n @if (paginationType === 'arrow') {\n <span class=\"pager\">\n <span class=\"pager-btn\" [class.disabled]=\"currentPage <= 1\" (click)=\"prevArrowPage()\">\u2190</span>\n Page {{ currentPage }} of {{ totalPages }}\n <span class=\"pager-btn\" [class.disabled]=\"currentPage >= totalPages\" (click)=\"nextArrowPage()\">\u2192</span>\n </span>\n } @else {\n {{ options.length }} of {{ totalCount }}\n @if (hasMore && paginationType === 'scroll') {\n <span> \u00B7 scroll for more</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (inputLoader) {\n <label class=\"loader input-loader\"></label>\n }\n\n @if (error) {\n <div class=\"val-msg\">{{ errorMessage }}</div>\n }\n</div>\n", styles: [".form-group.paginated-autocomplete .form-control{padding-right:unset}.form-group.paginated-autocomplete .clear{right:7px}.form-group.paginated-autocomplete .option-list{max-height:220px;overflow-y:auto}.form-group.paginated-autocomplete .option-list .no-results{padding:10px;color:#9b9b9b;text-align:center}.form-group.paginated-autocomplete .option-list .list-loading{padding:8px 10px;color:#9b9b9b;text-align:center;font-size:12px}.form-group.paginated-autocomplete .option-list .load-more{padding:8px 10px;text-align:center;cursor:pointer;color:#0d6efd;font-size:13px;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-more:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .load-error{padding:8px 10px;text-align:center;font-size:12px;color:#dc3545;cursor:pointer;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-error .retry{color:#0d6efd;text-decoration:underline}.form-group.paginated-autocomplete .option-list .load-error:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .list-footer{position:sticky;bottom:0;padding:4px 10px;text-align:center;font-size:11px;color:#9b9b9b;background-color:#fff;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
3257
3289
  }
3258
3290
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PaginatedAutocompleteControl, decorators: [{
3259
3291
  type: Component,
@@ -3263,7 +3295,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
3263
3295
  useExisting: PaginatedAutocompleteControl,
3264
3296
  multi: true,
3265
3297
  },
3266
- ], template: "<div class=\"form-group auto-complete paginated-autocomplete\" [ngClass]=\"customClass\" [class.readonly]=\"readonly\">\n @if (title) {\n <label class=\"inp-label\" [ngClass]=\"{ 'required': required }\">{{ title }}</label>\n }\n\n <input #inputElement type=\"text\" class=\"form-control\" [placeholder]=\"placeholder\" [formControl]=\"inputControl\"\n (input)=\"onUserType($event)\" (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" (focus)=\"onFocus()\" (click)=\"onInputClick()\"\n [ngClass]=\"{'is-invalid': error}\" [attr.autocomplete]=\"autocomplete || null\" [readonly]=\"readonly\" />\n\n <span class=\"focus-border\"></span>\n\n @if (!inputLoader && inputControl.value && clearVal && hasFocus) {\n <label class=\"clear\" (mousedown)=\"onOptionMouseDown()\" (click)=\"resetInput()\">\n <i class=\"he he-close\"></i>\n </label>\n }\n\n @if (isDropdownOpen) {\n <div #dropdownElement class=\"option-list\" (mousedown)=\"onOptionMouseDown()\" (scroll)=\"onListScroll($event)\">\n @if (options.length === 0 && !isPageLoading && !loadErrorMessage) {\n <div class=\"no-results\">\n <div>No results found</div>\n </div>\n } @else {\n @for (suggestion of options; track suggestion.id; let i = $index) {\n <div class=\"list-item\" [ngClass]=\"{\n 'active': suggestion === selectedItems,\n 'highlighted': highlightedIndex === i\n }\" (click)=\"selectSuggestion(suggestion)\" (mouseover)=\"onMouseOver(i)\">\n {{ suggestion[optionDisplayProperty] }}\n </div>\n }\n\n @if (isPageLoading) {\n <div class=\"list-loading\">Loading...</div>\n }\n\n @if (loadErrorMessage) {\n <div class=\"load-error\" (click)=\"retryLoad($event)\">\n {{ loadErrorMessage }} \u00B7 <span class=\"retry\">Retry</span>\n </div>\n }\n\n @if (paginationType === 'click' && hasMore && !isPageLoading && !loadErrorMessage) {\n <div class=\"load-more\" (click)=\"onLoadMoreClick($event)\">\n Load more ({{ options.length }} of {{ totalCount }})\n </div>\n }\n\n @if (totalCount > 0 && options.length > 0 && !loadErrorMessage && !(paginationType === 'click' && hasMore)) {\n <div class=\"list-footer\">\n {{ options.length }} of {{ totalCount }}\n @if (hasMore && paginationType === 'scroll') {\n <span> \u00B7 scroll for more</span>\n }\n @if (hasMore && paginationType === 'arrow') {\n <span> \u00B7 \u2190 \u2192 to page</span>\n }\n </div>\n }\n }\n </div>\n }\n\n @if (inputLoader) {\n <label class=\"loader input-loader\"></label>\n }\n\n @if (error) {\n <div class=\"val-msg\">{{ errorMessage }}</div>\n }\n</div>\n", styles: [".form-group.paginated-autocomplete .form-control{padding-right:unset}.form-group.paginated-autocomplete .clear{right:7px}.form-group.paginated-autocomplete .option-list{max-height:220px;overflow-y:auto}.form-group.paginated-autocomplete .option-list .no-results{padding:10px;color:#9b9b9b;text-align:center}.form-group.paginated-autocomplete .option-list .list-loading{padding:8px 10px;color:#9b9b9b;text-align:center;font-size:12px}.form-group.paginated-autocomplete .option-list .load-more{padding:8px 10px;text-align:center;cursor:pointer;color:#0d6efd;font-size:13px;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-more:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .load-error{padding:8px 10px;text-align:center;font-size:12px;color:#dc3545;cursor:pointer;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-error .retry{color:#0d6efd;text-decoration:underline}.form-group.paginated-autocomplete .option-list .load-error:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .list-footer{position:sticky;bottom:0;padding:4px 10px;text-align:center;font-size:11px;color:#9b9b9b;background-color:#fff;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}\n"] }]
3298
+ ], template: "<div class=\"form-group auto-complete paginated-autocomplete\" [ngClass]=\"customClass\" [class.readonly]=\"readonly\">\n @if (title) {\n <label class=\"inp-label\" [ngClass]=\"{ 'required': required }\">{{ title }}</label>\n }\n\n <input #inputElement type=\"text\" class=\"form-control\" [placeholder]=\"placeholder\" [formControl]=\"inputControl\"\n (input)=\"onUserType($event)\" (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" (focus)=\"onFocus()\" (click)=\"onInputClick()\"\n [ngClass]=\"{'is-invalid': error}\" [attr.autocomplete]=\"autocomplete || null\" [readonly]=\"readonly\" />\n\n <span class=\"focus-border\"></span>\n\n @if (!inputLoader && inputControl.value && clearVal && hasFocus) {\n <label class=\"clear\" (mousedown)=\"onOptionMouseDown()\" (click)=\"resetInput()\">\n <i class=\"he he-close\"></i>\n </label>\n }\n\n @if (isDropdownOpen) {\n <div #dropdownElement class=\"option-list\" (mousedown)=\"onOptionMouseDown()\" (scroll)=\"onListScroll($event)\">\n @if (options.length === 0 && !isPageLoading && !loadErrorMessage) {\n <div class=\"no-results\">\n <div>No results found</div>\n </div>\n } @else {\n @for (suggestion of options; track suggestion.id; let i = $index) {\n <div class=\"list-item\" [ngClass]=\"{\n 'active': suggestion === selectedItems,\n 'highlighted': highlightedIndex === i\n }\" (click)=\"selectSuggestion(suggestion)\" (mouseover)=\"onMouseOver(i)\">\n {{ suggestion[optionDisplayProperty] }}\n </div>\n }\n\n @if (isPageLoading) {\n <div class=\"list-loading\">Loading...</div>\n }\n\n @if (loadErrorMessage) {\n <div class=\"load-error\" (click)=\"retryLoad($event)\">\n {{ loadErrorMessage }} \u00B7 <span class=\"retry\">Retry</span>\n </div>\n }\n\n @if (paginationType === 'click' && hasMore && !isPageLoading && !loadErrorMessage) {\n <div class=\"load-more\" (click)=\"onLoadMoreClick($event)\">\n Load more ({{ options.length }} of {{ totalCount }})\n </div>\n }\n\n @if (totalCount > 0 && options.length > 0 && !loadErrorMessage && !(paginationType === 'click' && hasMore)) {\n <div class=\"list-footer\">\n @if (paginationType === 'arrow') {\n <span class=\"pager\">\n <span class=\"pager-btn\" [class.disabled]=\"currentPage <= 1\" (click)=\"prevArrowPage()\">\u2190</span>\n Page {{ currentPage }} of {{ totalPages }}\n <span class=\"pager-btn\" [class.disabled]=\"currentPage >= totalPages\" (click)=\"nextArrowPage()\">\u2192</span>\n </span>\n } @else {\n {{ options.length }} of {{ totalCount }}\n @if (hasMore && paginationType === 'scroll') {\n <span> \u00B7 scroll for more</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (inputLoader) {\n <label class=\"loader input-loader\"></label>\n }\n\n @if (error) {\n <div class=\"val-msg\">{{ errorMessage }}</div>\n }\n</div>\n", styles: [".form-group.paginated-autocomplete .form-control{padding-right:unset}.form-group.paginated-autocomplete .clear{right:7px}.form-group.paginated-autocomplete .option-list{max-height:220px;overflow-y:auto}.form-group.paginated-autocomplete .option-list .no-results{padding:10px;color:#9b9b9b;text-align:center}.form-group.paginated-autocomplete .option-list .list-loading{padding:8px 10px;color:#9b9b9b;text-align:center;font-size:12px}.form-group.paginated-autocomplete .option-list .load-more{padding:8px 10px;text-align:center;cursor:pointer;color:#0d6efd;font-size:13px;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-more:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .load-error{padding:8px 10px;text-align:center;font-size:12px;color:#dc3545;cursor:pointer;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}.form-group.paginated-autocomplete .option-list .load-error .retry{color:#0d6efd;text-decoration:underline}.form-group.paginated-autocomplete .option-list .load-error:hover{background-color:#f5f5f5}.form-group.paginated-autocomplete .option-list .list-footer{position:sticky;bottom:0;padding:4px 10px;text-align:center;font-size:11px;color:#9b9b9b;background-color:#fff;border-top:1px solid #eee;-webkit-user-select:none;user-select:none}\n"] }]
3267
3299
  }], ctorParameters: () => [], propDecorators: { title: [{
3268
3300
  type: Input
3269
3301
  }], required: [{