@shival99/z-ui 1.9.23 → 1.9.24
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/fesm2022/shival99-z-ui-components-z-autocomplete.mjs +186 -26
- package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-checkbox.mjs +4 -4
- package/fesm2022/shival99-z-ui-components-z-checkbox.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-kanban.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-kanban.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-pagination.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-pagination.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-radio.mjs +5 -5
- package/fesm2022/shival99-z-ui-components-z-radio.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-select.mjs +205 -40
- package/fesm2022/shival99-z-ui-components-z-select.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-table.mjs +2 -2
- package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-utils.mjs +69 -2
- package/fesm2022/shival99-z-ui-utils.mjs.map +1 -1
- package/package.json +1 -1
- package/types/shival99-z-ui-components-z-autocomplete.d.ts +37 -6
- package/types/shival99-z-ui-components-z-modal.d.ts +1 -1
- package/types/shival99-z-ui-components-z-select.d.ts +37 -4
- package/types/shival99-z-ui-utils.d.ts +47 -2
|
@@ -10,8 +10,8 @@ import { ZLoadingComponent } from '@shival99/z-ui/components/z-loading';
|
|
|
10
10
|
import { ZPopoverDirective } from '@shival99/z-ui/components/z-popover';
|
|
11
11
|
import { ZTooltipDirective } from '@shival99/z-ui/components/z-tooltip';
|
|
12
12
|
import { ZHighlightPipe, ZSafeHtmlPipe } from '@shival99/z-ui/pipes';
|
|
13
|
-
import { zTransform, zUuid, zRemoveVietnamese, zMergeClasses, zCreateEvent } from '@shival99/z-ui/utils';
|
|
14
|
-
import { Subject, debounceTime, distinctUntilChanged } from 'rxjs';
|
|
13
|
+
import { zTransform, zUuid, zRemoveVietnamese, zMergeClasses, zCreateEvent, Z_ASYNC_OPTIONS_DEFAULT_PAGE_SIZE, zToAsyncOptionsObservable, zMergeAsyncOptions, zResolveAsyncOptionsHasMore } from '@shival99/z-ui/utils';
|
|
14
|
+
import { Subject, debounceTime, distinctUntilChanged, finalize } from 'rxjs';
|
|
15
15
|
import { cva } from 'class-variance-authority';
|
|
16
16
|
|
|
17
17
|
class ZAutocompleteOptionDirective {
|
|
@@ -142,6 +142,12 @@ class ZAutocompleteComponent {
|
|
|
142
142
|
_formControl = signal(null, ...(ngDevMode ? [{ debugName: "_formControl" }] : []));
|
|
143
143
|
_popoverControl = signal(null, ...(ngDevMode ? [{ debugName: "_popoverControl" }] : []));
|
|
144
144
|
_selectedOption = signal(null, ...(ngDevMode ? [{ debugName: "_selectedOption" }] : []));
|
|
145
|
+
_asyncOptions = signal([], ...(ngDevMode ? [{ debugName: "_asyncOptions" }] : []));
|
|
146
|
+
_asyncKeyword = signal('', ...(ngDevMode ? [{ debugName: "_asyncKeyword" }] : []));
|
|
147
|
+
_asyncPage = signal(1, ...(ngDevMode ? [{ debugName: "_asyncPage" }] : []));
|
|
148
|
+
_asyncHasMore = signal(false, ...(ngDevMode ? [{ debugName: "_asyncHasMore" }] : []));
|
|
149
|
+
_asyncLoading = signal(false, ...(ngDevMode ? [{ debugName: "_asyncLoading" }] : []));
|
|
150
|
+
_asyncLoadingMore = signal(false, ...(ngDevMode ? [{ debugName: "_asyncLoadingMore" }] : []));
|
|
145
151
|
uiState = signal({
|
|
146
152
|
isOpen: false,
|
|
147
153
|
isFocused: false,
|
|
@@ -160,6 +166,8 @@ class ZAutocompleteComponent {
|
|
|
160
166
|
_localLoadingTimeout = null;
|
|
161
167
|
_loadMoreObserver = null;
|
|
162
168
|
_virtualScrollListener = null;
|
|
169
|
+
_asyncLoadSubscription = null;
|
|
170
|
+
_asyncRequestId = 0;
|
|
163
171
|
_lastFilteredOptionsLength = 0;
|
|
164
172
|
_shouldScrollActiveOption = false;
|
|
165
173
|
/** Stores input value before keyboard navigation for ESC revert */
|
|
@@ -184,6 +192,11 @@ class ZAutocompleteComponent {
|
|
|
184
192
|
...Z_AUTOCOMPLETE_DEFAULT_CONFIG,
|
|
185
193
|
...this.zConfig(),
|
|
186
194
|
}), ...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
195
|
+
hasAsyncOptions = computed(() => !!this.config().async?.load, ...(ngDevMode ? [{ debugName: "hasAsyncOptions" }] : []));
|
|
196
|
+
sourceOptions = computed(() => (this.hasAsyncOptions() ? this._asyncOptions() : this.zOptions()), ...(ngDevMode ? [{ debugName: "sourceOptions" }] : []));
|
|
197
|
+
isLoading = computed(() => this.zLoading() || this._asyncLoading(), ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
198
|
+
isLoadingMore = computed(() => this.zLoadingMore() || this._asyncLoadingMore(), ...(ngDevMode ? [{ debugName: "isLoadingMore" }] : []));
|
|
199
|
+
canLoadMore = computed(() => this.hasAsyncOptions() ? this._asyncHasMore() : this.zEnableLoadMore(), ...(ngDevMode ? [{ debugName: "canLoadMore" }] : []));
|
|
187
200
|
isDisabled = computed(() => this._disabled() || this.zDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
188
201
|
isReadonly = computed(() => this.zReadonly(), ...(ngDevMode ? [{ debugName: "isReadonly" }] : []));
|
|
189
202
|
isInteractionDisabled = computed(() => this.isDisabled() || this.isReadonly() || this.zLoading(), ...(ngDevMode ? [{ debugName: "isInteractionDisabled" }] : []));
|
|
@@ -191,7 +204,7 @@ class ZAutocompleteComponent {
|
|
|
191
204
|
effectiveHeightExpand = computed(() => this.zHeightExpand() || this.config().dropdownMaxHeight, ...(ngDevMode ? [{ debugName: "effectiveHeightExpand" }] : []));
|
|
192
205
|
effectiveEmptyText = computed(() => this.zEmptyText() || this.config().emptyMessage, ...(ngDevMode ? [{ debugName: "effectiveEmptyText" }] : []));
|
|
193
206
|
effectiveNoDataText = computed(() => this.zNoDataText() || this.config().noDataMessage, ...(ngDevMode ? [{ debugName: "effectiveNoDataText" }] : []));
|
|
194
|
-
effectiveDebounceTime = computed(() => this.zDebounceTime(), ...(ngDevMode ? [{ debugName: "effectiveDebounceTime" }] : []));
|
|
207
|
+
effectiveDebounceTime = computed(() => this.zConfig().debounceTime ?? this.zDebounceTime(), ...(ngDevMode ? [{ debugName: "effectiveDebounceTime" }] : []));
|
|
195
208
|
effectiveOptionTemplate = computed(() => {
|
|
196
209
|
const directive = this.customOptionDirective();
|
|
197
210
|
if (directive) {
|
|
@@ -206,7 +219,7 @@ class ZAutocompleteComponent {
|
|
|
206
219
|
* Server mode relies only on zLoading from parent.
|
|
207
220
|
*/
|
|
208
221
|
isLoadingState = computed(() => {
|
|
209
|
-
if (this.config().serverSearch) {
|
|
222
|
+
if (this.config().serverSearch || this.hasAsyncOptions()) {
|
|
210
223
|
return false;
|
|
211
224
|
}
|
|
212
225
|
const hasInput = this.inputValue().trim() !== '';
|
|
@@ -223,22 +236,22 @@ class ZAutocompleteComponent {
|
|
|
223
236
|
if (this.hasCustomOptionTemplate()) {
|
|
224
237
|
return false;
|
|
225
238
|
}
|
|
226
|
-
if (this.
|
|
239
|
+
if (this.canLoadMore()) {
|
|
227
240
|
return false;
|
|
228
241
|
}
|
|
229
242
|
const maxVisible = this.zMaxVisible();
|
|
230
|
-
if (maxVisible !== null && this.
|
|
243
|
+
if (maxVisible !== null && this.sourceOptions().length > maxVisible) {
|
|
231
244
|
return true;
|
|
232
245
|
}
|
|
233
|
-
return this.
|
|
246
|
+
return this.sourceOptions().length > 50;
|
|
234
247
|
}, ...(ngDevMode ? [{ debugName: "shouldUseVirtualScroll" }] : []));
|
|
235
248
|
filteredOptions = computed(() => {
|
|
236
|
-
const options = this.
|
|
249
|
+
const options = this.sourceOptions();
|
|
237
250
|
const cfg = this.config();
|
|
238
251
|
const allowCustom = this.zAllowCustomValue();
|
|
239
252
|
const query = this.zType() === 'address_bar' ? this.searchQuery() : this.debouncedQuery();
|
|
240
253
|
// If server search is enabled, skip local filtering - just apply maxDisplayed limit
|
|
241
|
-
if (cfg.serverSearch) {
|
|
254
|
+
if (cfg.serverSearch || this.hasAsyncOptions()) {
|
|
242
255
|
let result = options;
|
|
243
256
|
if (cfg.maxDisplayed && options.length > cfg.maxDisplayed) {
|
|
244
257
|
result = options.slice(0, cfg.maxDisplayed);
|
|
@@ -340,7 +353,7 @@ class ZAutocompleteComponent {
|
|
|
340
353
|
if (!isOpen || idx < 0) {
|
|
341
354
|
return;
|
|
342
355
|
}
|
|
343
|
-
if (!this._shouldScrollActiveOption || this.shouldUseVirtualScroll() || this.
|
|
356
|
+
if (!this._shouldScrollActiveOption || this.shouldUseVirtualScroll() || this.canLoadMore()) {
|
|
344
357
|
return;
|
|
345
358
|
}
|
|
346
359
|
this._shouldScrollActiveOption = false;
|
|
@@ -358,7 +371,7 @@ class ZAutocompleteComponent {
|
|
|
358
371
|
const sentinel = this.loadMoreSentinelRef();
|
|
359
372
|
const { isOpen } = this.uiState();
|
|
360
373
|
const optionsCount = this.filteredOptions().length;
|
|
361
|
-
if (!sentinel || !isOpen || optionsCount === 0) {
|
|
374
|
+
if (!sentinel || !isOpen || optionsCount === 0 || !this.canLoadMore()) {
|
|
362
375
|
this._cleanupLoadMoreObserver();
|
|
363
376
|
return;
|
|
364
377
|
}
|
|
@@ -589,7 +602,9 @@ class ZAutocompleteComponent {
|
|
|
589
602
|
this._value.set('');
|
|
590
603
|
this._onChange('');
|
|
591
604
|
this.zValueChange.emit('');
|
|
592
|
-
this.
|
|
605
|
+
if (!this.hasAsyncOptions()) {
|
|
606
|
+
this._query$.next('');
|
|
607
|
+
}
|
|
593
608
|
this._closePanel();
|
|
594
609
|
this.activeIndex.set(-1);
|
|
595
610
|
}
|
|
@@ -598,6 +613,7 @@ class ZAutocompleteComponent {
|
|
|
598
613
|
}
|
|
599
614
|
onPopoverShow() {
|
|
600
615
|
this.uiState.update(s => ({ ...s, isOpen: true }));
|
|
616
|
+
this._loadAsyncOptionsOnFocus();
|
|
601
617
|
setTimeout(() => {
|
|
602
618
|
this.inputRef()?.nativeElement.focus();
|
|
603
619
|
}, 50);
|
|
@@ -608,7 +624,9 @@ class ZAutocompleteComponent {
|
|
|
608
624
|
this._clearLocalLoadingTimer();
|
|
609
625
|
this._pendingSearch.set(false);
|
|
610
626
|
this.debouncedQuery.set('');
|
|
611
|
-
this.
|
|
627
|
+
if (!this.hasAsyncOptions()) {
|
|
628
|
+
this._query$.next('');
|
|
629
|
+
}
|
|
612
630
|
}
|
|
613
631
|
onPopoverHideEnd() {
|
|
614
632
|
this.actualPosition.set('bottom');
|
|
@@ -651,8 +669,11 @@ class ZAutocompleteComponent {
|
|
|
651
669
|
if (this.zType() === 'address_bar') {
|
|
652
670
|
this.searchQuery.set('');
|
|
653
671
|
}
|
|
654
|
-
this.
|
|
672
|
+
if (!this.hasAsyncOptions()) {
|
|
673
|
+
this._query$.next('');
|
|
674
|
+
}
|
|
655
675
|
this.zOnCommit.emit({ value: '', source: 'blur' });
|
|
676
|
+
this._resetAsyncOptions();
|
|
656
677
|
setTimeout(() => {
|
|
657
678
|
this.inputRef()?.nativeElement.focus();
|
|
658
679
|
});
|
|
@@ -683,6 +704,7 @@ class ZAutocompleteComponent {
|
|
|
683
704
|
this._closePanel();
|
|
684
705
|
this._clearLocalLoadingTimer();
|
|
685
706
|
this._pendingSearch.set(false);
|
|
707
|
+
this._resetAsyncOptions();
|
|
686
708
|
if (this.zType() === 'address_bar') {
|
|
687
709
|
this.searchQuery.set('');
|
|
688
710
|
}
|
|
@@ -725,6 +747,10 @@ class ZAutocompleteComponent {
|
|
|
725
747
|
}
|
|
726
748
|
this.debouncedQuery.set(query);
|
|
727
749
|
this.zOnSearch.emit(query);
|
|
750
|
+
if (this.hasAsyncOptions()) {
|
|
751
|
+
this._loadAsyncOptions(query, false);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
728
754
|
if (this.config().serverSearch) {
|
|
729
755
|
return;
|
|
730
756
|
}
|
|
@@ -736,6 +762,133 @@ class ZAutocompleteComponent {
|
|
|
736
762
|
}, 100);
|
|
737
763
|
});
|
|
738
764
|
}
|
|
765
|
+
_loadAsyncOptionsOnFocus() {
|
|
766
|
+
const asyncConfig = this.config().async;
|
|
767
|
+
if (!asyncConfig?.loadOnFocus) {
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
const keyword = this.inputValue().trim();
|
|
771
|
+
if (this._asyncKeyword() === keyword && this._asyncOptions().length > 0) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
this._loadAsyncOptions(keyword, false);
|
|
775
|
+
}
|
|
776
|
+
_loadAsyncOptions(keyword, append) {
|
|
777
|
+
const asyncConfig = this.config().async;
|
|
778
|
+
if (!asyncConfig) {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const normalizedKeyword = keyword.trim();
|
|
782
|
+
const pageSize = asyncConfig.pageSize ?? Z_ASYNC_OPTIONS_DEFAULT_PAGE_SIZE;
|
|
783
|
+
const { minLength } = this.config();
|
|
784
|
+
const canLoadEmptyOnFocus = asyncConfig.loadOnFocus && normalizedKeyword.length === 0;
|
|
785
|
+
if (!append && normalizedKeyword.length < minLength && !canLoadEmptyOnFocus) {
|
|
786
|
+
this._resetAsyncOptions();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (append && (!this._asyncHasMore() || this._asyncLoading() || this._asyncLoadingMore())) {
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const page = append ? this._asyncPage() + 1 : 1;
|
|
793
|
+
const requestId = ++this._asyncRequestId;
|
|
794
|
+
const scrollTopBeforeAppend = append ? this._getAsyncOptionsScrollTop() : null;
|
|
795
|
+
if (!append) {
|
|
796
|
+
this._asyncLoadSubscription?.unsubscribe();
|
|
797
|
+
this._asyncKeyword.set(normalizedKeyword);
|
|
798
|
+
this._asyncLoading.set(true);
|
|
799
|
+
this._asyncHasMore.set(false);
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
this._asyncLoadingMore.set(true);
|
|
803
|
+
}
|
|
804
|
+
let result;
|
|
805
|
+
try {
|
|
806
|
+
result = asyncConfig.load({
|
|
807
|
+
keyword: normalizedKeyword,
|
|
808
|
+
page,
|
|
809
|
+
pageSize,
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
this._handleAsyncOptionsError(error, append);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
this._asyncLoadSubscription = zToAsyncOptionsObservable(result)
|
|
817
|
+
.pipe(finalize(() => {
|
|
818
|
+
if (requestId !== this._asyncRequestId) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
this._asyncLoading.set(false);
|
|
822
|
+
this._asyncLoadingMore.set(false);
|
|
823
|
+
}), takeUntilDestroyed(this._destroyRef))
|
|
824
|
+
.subscribe({
|
|
825
|
+
next: response => {
|
|
826
|
+
if (requestId !== this._asyncRequestId) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const nextItems = response.items ?? [];
|
|
830
|
+
const previousCount = this._asyncOptions().length;
|
|
831
|
+
const mergedOptions = append
|
|
832
|
+
? zMergeAsyncOptions(this._asyncOptions(), nextItems, asyncConfig.dedupeBy)
|
|
833
|
+
: zMergeAsyncOptions([], nextItems, asyncConfig.dedupeBy);
|
|
834
|
+
const hasNewItems = mergedOptions.length > previousCount;
|
|
835
|
+
if (append && !hasNewItems) {
|
|
836
|
+
this._asyncHasMore.set(false);
|
|
837
|
+
this._restoreAsyncOptionsScrollTop(scrollTopBeforeAppend);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
this._asyncOptions.set(mergedOptions);
|
|
841
|
+
this._asyncPage.set(page);
|
|
842
|
+
this._asyncHasMore.set(append && !hasNewItems ? false : zResolveAsyncOptionsHasMore(response, pageSize, mergedOptions.length));
|
|
843
|
+
this._restoreAsyncOptionsScrollTop(scrollTopBeforeAppend);
|
|
844
|
+
},
|
|
845
|
+
error: error => {
|
|
846
|
+
if (requestId !== this._asyncRequestId) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
this._handleAsyncOptionsError(error, append);
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
_handleAsyncOptionsError(error, append) {
|
|
854
|
+
console.error('ZAutocomplete async options load failed:', error);
|
|
855
|
+
if (!append) {
|
|
856
|
+
this._asyncOptions.set([]);
|
|
857
|
+
this._asyncPage.set(1);
|
|
858
|
+
}
|
|
859
|
+
this._asyncHasMore.set(false);
|
|
860
|
+
this._asyncLoading.set(false);
|
|
861
|
+
this._asyncLoadingMore.set(false);
|
|
862
|
+
}
|
|
863
|
+
_getAsyncOptionsScrollTop() {
|
|
864
|
+
const scrollElement = this.shouldUseVirtualScroll()
|
|
865
|
+
? this.virtualScrollRef()?.nativeElement
|
|
866
|
+
: this.optionsContainerRef()?.nativeElement;
|
|
867
|
+
return scrollElement?.scrollTop ?? null;
|
|
868
|
+
}
|
|
869
|
+
_restoreAsyncOptionsScrollTop(scrollTop) {
|
|
870
|
+
if (scrollTop === null) {
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
requestAnimationFrame(() => {
|
|
874
|
+
const scrollElement = this.shouldUseVirtualScroll()
|
|
875
|
+
? this.virtualScrollRef()?.nativeElement
|
|
876
|
+
: this.optionsContainerRef()?.nativeElement;
|
|
877
|
+
if (scrollElement) {
|
|
878
|
+
scrollElement.scrollTop = scrollTop;
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
_resetAsyncOptions() {
|
|
883
|
+
this._asyncLoadSubscription?.unsubscribe();
|
|
884
|
+
this._asyncRequestId++;
|
|
885
|
+
this._asyncOptions.set([]);
|
|
886
|
+
this._asyncKeyword.set('');
|
|
887
|
+
this._asyncPage.set(1);
|
|
888
|
+
this._asyncHasMore.set(false);
|
|
889
|
+
this._asyncLoading.set(false);
|
|
890
|
+
this._asyncLoadingMore.set(false);
|
|
891
|
+
}
|
|
739
892
|
_clearLocalLoadingTimer() {
|
|
740
893
|
if (!this._localLoadingTimeout) {
|
|
741
894
|
return;
|
|
@@ -752,11 +905,8 @@ class ZAutocompleteComponent {
|
|
|
752
905
|
}
|
|
753
906
|
this._loadMoreObserver = new IntersectionObserver(entries => {
|
|
754
907
|
const entry = entries[0];
|
|
755
|
-
if (entry?.isIntersecting && !this.
|
|
756
|
-
this.
|
|
757
|
-
currentCount: this.filteredOptions().length,
|
|
758
|
-
scrollTop: container.scrollTop,
|
|
759
|
-
});
|
|
908
|
+
if (entry?.isIntersecting && !this.isLoadingMore()) {
|
|
909
|
+
this._handleLoadMore(container.scrollTop);
|
|
760
910
|
}
|
|
761
911
|
}, {
|
|
762
912
|
root: container,
|
|
@@ -779,17 +929,14 @@ class ZAutocompleteComponent {
|
|
|
779
929
|
return;
|
|
780
930
|
}
|
|
781
931
|
const handleScroll = () => {
|
|
782
|
-
if (this.
|
|
932
|
+
if (this.isLoadingMore()) {
|
|
783
933
|
return;
|
|
784
934
|
}
|
|
785
935
|
const { scrollTop, scrollHeight, clientHeight } = scrollElement;
|
|
786
936
|
const threshold = clientHeight * this.zScrollDistance();
|
|
787
937
|
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
|
788
938
|
if (distanceFromBottom <= threshold) {
|
|
789
|
-
this.
|
|
790
|
-
currentCount: this.filteredOptions().length,
|
|
791
|
-
scrollTop,
|
|
792
|
-
});
|
|
939
|
+
this._handleLoadMore(scrollTop);
|
|
793
940
|
}
|
|
794
941
|
};
|
|
795
942
|
scrollElement.addEventListener('scroll', handleScroll);
|
|
@@ -804,6 +951,19 @@ class ZAutocompleteComponent {
|
|
|
804
951
|
this._virtualScrollListener();
|
|
805
952
|
this._virtualScrollListener = null;
|
|
806
953
|
}
|
|
954
|
+
_handleLoadMore(scrollTop) {
|
|
955
|
+
if (this.hasAsyncOptions()) {
|
|
956
|
+
if (!this.canLoadMore()) {
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
this._loadAsyncOptions(this._asyncKeyword(), true);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
this.zOnLoadMore.emit({
|
|
963
|
+
currentCount: this.filteredOptions().length,
|
|
964
|
+
scrollTop,
|
|
965
|
+
});
|
|
966
|
+
}
|
|
807
967
|
_emitControl() {
|
|
808
968
|
this.zControl.emit({
|
|
809
969
|
focus: () => this.focus(),
|
|
@@ -835,7 +995,7 @@ class ZAutocompleteComponent {
|
|
|
835
995
|
useExisting: forwardRef(() => ZAutocompleteComponent),
|
|
836
996
|
multi: true,
|
|
837
997
|
},
|
|
838
|
-
], queries: [{ propertyName: "customOptionDirective", first: true, predicate: (ZAutocompleteOptionDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "dropdownTpl", first: true, predicate: ["dropdownTpl"], descendants: true, isSignal: true }, { propertyName: "virtualScrollRef", first: true, predicate: ["virtualScrollElement"], descendants: true, isSignal: true }, { propertyName: "optionsContainerRef", first: true, predicate: ["optionsContainer"], descendants: true, isSignal: true }, { propertyName: "loadMoreSentinelRef", first: true, predicate: ["loadMoreSentinel"], descendants: true, isSignal: true }, { propertyName: "virtualOptionElements", predicate: ["virtualOptionEl"], descendants: true, isSignal: true }], exportAs: ["zAutocomplete"], ngImport: i0, template: "<div class=\"z-autocomplete-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"autocompleteId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"0\"\n [zDisabled]=\"isInteractionDisabled()\"\n zTrigger=\"manual\"\n zPosition=\"bottom\"\n zClass=\"border-0 shadow-none bg-transparent p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n (zPositionChange)=\"onPositionChange($event)\"\n class=\"z-autocomplete-trigger\"\n [class]=\"inputClasses()\"\n [class.z-autocomplete-open]=\"uiState().isOpen\"\n [class.z-autocomplete-open-top]=\"uiState().isOpen && isPositionTop()\"\n [class.z-autocomplete-open-bottom]=\"uiState().isOpen && !isPositionTop()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"uiState().isOpen\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"dropdownId\">\n @if (zPrefix()) {\n <z-icon [zType]=\"zPrefix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <input\n #inputEl\n [id]=\"autocompleteId\"\n type=\"text\"\n class=\"z-autocomplete-input min-w-0 flex-1 bg-transparent outline-none\"\n [class.text-sm]=\"zSize() === 'sm' || zSize() === 'default'\"\n [placeholder]=\"zPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"isReadonly()\"\n [value]=\"inputValue()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur($event)\"\n (click)=\"onInputClick()\"\n (keydown)=\"onKeydown($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n\n @if (zLoading() || isLoadingState() || zLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"16\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n } @else {\n @if (zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 cursor-pointer items-center justify-center transition-colors\"\n (mousedown)=\"clearInput($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" class=\"cursor-pointer!\" />\n </button>\n }\n\n @if (zSuffix()) {\n <z-icon [zType]=\"zSuffix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n }\n </div>\n</div>\n\n<ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-autocomplete-dropdown bg-popover border-ring overflow-hidden border shadow-lg\"\n [class.z-autocomplete-dropdown-bottom]=\"!isPositionTop()\"\n [class.rounded-b-sm]=\"!isPositionTop()\"\n [class.rounded-t-sm]=\"isPositionTop()\"\n [class.border-t-0]=\"!isPositionTop()\"\n [class.border-b-0]=\"isPositionTop()\"\n [style.width.px]=\"dropdownWidth()\"\n role=\"listbox\"\n (mousedown)=\"$event.preventDefault()\">\n @if (zLoading() || isLoadingState()) {\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length === 0) {\n <!-- Empty State -->\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n @if (inputValue().trim() !== '') {\n <!-- Searched but no results -->\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <!-- No data initially -->\n <z-empty [zIcon]=\"zNoDataIcon()\" zSize=\"sm\" [zMessage]=\"effectiveNoDataText()\" />\n }\n </div>\n } @else if (shouldUseVirtualScroll()) {\n <!-- Virtual Scroll Mode -->\n <div\n #virtualScrollElement\n class=\"z-autocomplete-content-state z-autocomplete-options z-autocomplete-virtual-scroll relative overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"effectiveHeightExpand()\">\n <div class=\"z-autocomplete-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n @let isActive = activeIndex() === virtualItem.index;\n <div\n #virtualOptionEl\n class=\"z-autocomplete-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"getOptionClasses(opt, virtualItem.index)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"zDynamicSize() ? null : effectiveOptionHeight()\"\n [style.minHeight.px]=\"zDynamicSize() ? effectiveOptionHeight() : null\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(virtualItem.index)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"virtualOptionEl\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Normal Scroll Mode -->\n <div\n #optionsContainer\n class=\"z-autocomplete-content-state z-autocomplete-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\"\n [style.maxHeight.px]=\"effectiveHeightExpand()\">\n @for (item of optionViews(); track item.trackKey) {\n @let opt = item.option;\n @let i = item.index;\n @let isActive = activeIndex() === i;\n <div\n #optionEl2\n class=\"z-autocomplete-option relative min-w-0\"\n [ngClass]=\"getOptionClasses(opt, i)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [style.minHeight.px]=\"effectiveOptionHeight()\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(i)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n @if (zEnableLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n\n @if (zLoadingMore()) {\n <div class=\"z-autocomplete-loading-more border-border/50 flex items-center justify-center border-t py-1.5\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [".z-autocomplete-wrapper{width:100%}.z-autocomplete-trigger{-webkit-user-select:none;user-select:none}.z-autocomplete-trigger:focus-within{outline:none}.z-autocomplete-trigger *{cursor:inherit}.z-autocomplete-input{text-overflow:ellipsis;overflow:hidden}.z-autocomplete-input::placeholder{color:hsl(var(--muted-foreground))}.z-autocomplete-input:disabled{cursor:not-allowed}.z-autocomplete-open-bottom{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.z-autocomplete-open-top{border-top-left-radius:0!important;border-top-right-radius:0!important}.z-autocomplete-dropdown{animation:z-autocomplete-dropdown-from-top .15s ease-out}.z-autocomplete-dropdown-bottom{animation:z-autocomplete-dropdown-from-bottom .15s ease-out}@keyframes z-autocomplete-dropdown-from-top{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-autocomplete-dropdown-from-bottom{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}.z-autocomplete-separator{display:none}.z-autocomplete-options{overflow-x:hidden!important}.z-autocomplete-scrollbar{--scrollbar-padding: 0;--scrollbar-track-color: transparent;--scrollbar-thumb-color: hsl(var(--muted-foreground) / .3);--scrollbar-thumb-hover-color: hsl(var(--muted-foreground) / .5);--scrollbar-size: 6px}.z-autocomplete-virtual-scroll .z-autocomplete-virtual-inner{width:100%}.z-autocomplete-content-state{animation:z-autocomplete-content-fade-in .15s ease-out}@keyframes z-autocomplete-content-fade-in{0%{opacity:0}to{opacity:1}}.z-autocomplete-option mark{background:transparent;color:hsl(var(--primary));font-weight:600}.z-autocomplete-option{transition:background-color .1s ease,color .1s ease}.z-autocomplete-options:not(.z-autocomplete-virtual-scroll) .z-autocomplete-option{animation:z-autocomplete-option-enter .12s ease-out;animation-fill-mode:both}@keyframes z-autocomplete-option-enter{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zManualClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange"], exportAs: ["zPopover"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTrigger", "zTooltipType", "zTooltipSize", "zClass", "zShowDelay", "zHideDelay", "zArrow", "zDisabled", "zOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "pipe", type: ZHighlightPipe, name: "zHighlight" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
998
|
+
], queries: [{ propertyName: "customOptionDirective", first: true, predicate: (ZAutocompleteOptionDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "dropdownTpl", first: true, predicate: ["dropdownTpl"], descendants: true, isSignal: true }, { propertyName: "virtualScrollRef", first: true, predicate: ["virtualScrollElement"], descendants: true, isSignal: true }, { propertyName: "optionsContainerRef", first: true, predicate: ["optionsContainer"], descendants: true, isSignal: true }, { propertyName: "loadMoreSentinelRef", first: true, predicate: ["loadMoreSentinel"], descendants: true, isSignal: true }, { propertyName: "virtualOptionElements", predicate: ["virtualOptionEl"], descendants: true, isSignal: true }], exportAs: ["zAutocomplete"], ngImport: i0, template: "<div class=\"z-autocomplete-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"autocompleteId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"0\"\n [zDisabled]=\"isInteractionDisabled()\"\n zTrigger=\"manual\"\n zPosition=\"bottom\"\n zClass=\"border-0 shadow-none bg-transparent p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n (zPositionChange)=\"onPositionChange($event)\"\n class=\"z-autocomplete-trigger\"\n [class]=\"inputClasses()\"\n [class.z-autocomplete-open]=\"uiState().isOpen\"\n [class.z-autocomplete-open-top]=\"uiState().isOpen && isPositionTop()\"\n [class.z-autocomplete-open-bottom]=\"uiState().isOpen && !isPositionTop()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"uiState().isOpen\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"dropdownId\">\n @if (zPrefix()) {\n <z-icon [zType]=\"zPrefix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <input\n #inputEl\n [id]=\"autocompleteId\"\n type=\"text\"\n class=\"z-autocomplete-input min-w-0 flex-1 bg-transparent outline-none\"\n [class.text-sm]=\"zSize() === 'sm' || zSize() === 'default'\"\n [placeholder]=\"zPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"isReadonly()\"\n [value]=\"inputValue()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur($event)\"\n (click)=\"onInputClick()\"\n (keydown)=\"onKeydown($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n\n @if (isLoading() || isLoadingState() || isLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"16\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n } @else {\n @if (zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 cursor-pointer items-center justify-center transition-colors\"\n (mousedown)=\"clearInput($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" class=\"cursor-pointer!\" />\n </button>\n }\n\n @if (zSuffix()) {\n <z-icon [zType]=\"zSuffix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n }\n </div>\n</div>\n\n<ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-autocomplete-dropdown bg-popover border-ring overflow-hidden border shadow-lg\"\n [class.z-autocomplete-dropdown-bottom]=\"!isPositionTop()\"\n [class.rounded-b-sm]=\"!isPositionTop()\"\n [class.rounded-t-sm]=\"isPositionTop()\"\n [class.border-t-0]=\"!isPositionTop()\"\n [class.border-b-0]=\"isPositionTop()\"\n [style.width.px]=\"dropdownWidth()\"\n role=\"listbox\"\n (mousedown)=\"$event.preventDefault()\">\n @if (isLoading() || isLoadingState()) {\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length === 0) {\n <!-- Empty State -->\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n @if (inputValue().trim() !== '') {\n <!-- Searched but no results -->\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <!-- No data initially -->\n <z-empty [zIcon]=\"zNoDataIcon()\" zSize=\"sm\" [zMessage]=\"effectiveNoDataText()\" />\n }\n </div>\n } @else if (shouldUseVirtualScroll()) {\n <!-- Virtual Scroll Mode -->\n <div\n #virtualScrollElement\n class=\"z-autocomplete-content-state z-autocomplete-options z-autocomplete-virtual-scroll relative overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"effectiveHeightExpand()\">\n <div class=\"z-autocomplete-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n @let isActive = activeIndex() === virtualItem.index;\n <div\n #virtualOptionEl\n class=\"z-autocomplete-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"getOptionClasses(opt, virtualItem.index)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"zDynamicSize() ? null : effectiveOptionHeight()\"\n [style.minHeight.px]=\"zDynamicSize() ? effectiveOptionHeight() : null\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(virtualItem.index)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"virtualOptionEl\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Normal Scroll Mode -->\n <div\n #optionsContainer\n class=\"z-autocomplete-content-state z-autocomplete-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\"\n [style.maxHeight.px]=\"effectiveHeightExpand()\">\n @for (item of optionViews(); track item.trackKey) {\n @let opt = item.option;\n @let i = item.index;\n @let isActive = activeIndex() === i;\n <div\n #optionEl2\n class=\"z-autocomplete-option relative min-w-0\"\n [ngClass]=\"getOptionClasses(opt, i)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [style.minHeight.px]=\"effectiveOptionHeight()\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(i)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n @if (canLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n\n @if (isLoadingMore()) {\n <div class=\"z-autocomplete-loading-more border-border/50 flex items-center justify-center border-t py-1.5\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [".z-autocomplete-wrapper{width:100%}.z-autocomplete-trigger{-webkit-user-select:none;user-select:none}.z-autocomplete-trigger:focus-within{outline:none}.z-autocomplete-trigger *{cursor:inherit}.z-autocomplete-input{text-overflow:ellipsis;overflow:hidden}.z-autocomplete-input::placeholder{color:hsl(var(--muted-foreground))}.z-autocomplete-input:disabled{cursor:not-allowed}.z-autocomplete-open-bottom{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.z-autocomplete-open-top{border-top-left-radius:0!important;border-top-right-radius:0!important}.z-autocomplete-dropdown{animation:z-autocomplete-dropdown-from-top .15s ease-out}.z-autocomplete-dropdown-bottom{animation:z-autocomplete-dropdown-from-bottom .15s ease-out}@keyframes z-autocomplete-dropdown-from-top{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-autocomplete-dropdown-from-bottom{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}.z-autocomplete-separator{display:none}.z-autocomplete-options{overflow-x:hidden!important}.z-autocomplete-scrollbar{--scrollbar-padding: 0;--scrollbar-track-color: transparent;--scrollbar-thumb-color: hsl(var(--muted-foreground) / .3);--scrollbar-thumb-hover-color: hsl(var(--muted-foreground) / .5);--scrollbar-size: 6px}.z-autocomplete-virtual-scroll .z-autocomplete-virtual-inner{width:100%}.z-autocomplete-content-state{animation:z-autocomplete-content-fade-in .15s ease-out}@keyframes z-autocomplete-content-fade-in{0%{opacity:0}to{opacity:1}}.z-autocomplete-option mark{background:transparent;color:hsl(var(--primary));font-weight:600}.z-autocomplete-option{transition:background-color .1s ease,color .1s ease}.z-autocomplete-options:not(.z-autocomplete-virtual-scroll) .z-autocomplete-option{animation:z-autocomplete-option-enter .12s ease-out;animation-fill-mode:both}@keyframes z-autocomplete-option-enter{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zManualClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange"], exportAs: ["zPopover"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTrigger", "zTooltipType", "zTooltipSize", "zClass", "zShowDelay", "zHideDelay", "zArrow", "zDisabled", "zOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "pipe", type: ZHighlightPipe, name: "zHighlight" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
839
999
|
}
|
|
840
1000
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZAutocompleteComponent, decorators: [{
|
|
841
1001
|
type: Component,
|
|
@@ -856,7 +1016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
|
|
|
856
1016
|
useExisting: forwardRef(() => ZAutocompleteComponent),
|
|
857
1017
|
multi: true,
|
|
858
1018
|
},
|
|
859
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, exportAs: 'zAutocomplete', template: "<div class=\"z-autocomplete-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"autocompleteId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"0\"\n [zDisabled]=\"isInteractionDisabled()\"\n zTrigger=\"manual\"\n zPosition=\"bottom\"\n zClass=\"border-0 shadow-none bg-transparent p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n (zPositionChange)=\"onPositionChange($event)\"\n class=\"z-autocomplete-trigger\"\n [class]=\"inputClasses()\"\n [class.z-autocomplete-open]=\"uiState().isOpen\"\n [class.z-autocomplete-open-top]=\"uiState().isOpen && isPositionTop()\"\n [class.z-autocomplete-open-bottom]=\"uiState().isOpen && !isPositionTop()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"uiState().isOpen\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"dropdownId\">\n @if (zPrefix()) {\n <z-icon [zType]=\"zPrefix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <input\n #inputEl\n [id]=\"autocompleteId\"\n type=\"text\"\n class=\"z-autocomplete-input min-w-0 flex-1 bg-transparent outline-none\"\n [class.text-sm]=\"zSize() === 'sm' || zSize() === 'default'\"\n [placeholder]=\"zPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"isReadonly()\"\n [value]=\"inputValue()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur($event)\"\n (click)=\"onInputClick()\"\n (keydown)=\"onKeydown($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n\n @if (zLoading() || isLoadingState() || zLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"16\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n } @else {\n @if (zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 cursor-pointer items-center justify-center transition-colors\"\n (mousedown)=\"clearInput($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" class=\"cursor-pointer!\" />\n </button>\n }\n\n @if (zSuffix()) {\n <z-icon [zType]=\"zSuffix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n }\n </div>\n</div>\n\n<ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-autocomplete-dropdown bg-popover border-ring overflow-hidden border shadow-lg\"\n [class.z-autocomplete-dropdown-bottom]=\"!isPositionTop()\"\n [class.rounded-b-sm]=\"!isPositionTop()\"\n [class.rounded-t-sm]=\"isPositionTop()\"\n [class.border-t-0]=\"!isPositionTop()\"\n [class.border-b-0]=\"isPositionTop()\"\n [style.width.px]=\"dropdownWidth()\"\n role=\"listbox\"\n (mousedown)=\"$event.preventDefault()\">\n @if (zLoading() || isLoadingState()) {\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length === 0) {\n <!-- Empty State -->\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n @if (inputValue().trim() !== '') {\n <!-- Searched but no results -->\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <!-- No data initially -->\n <z-empty [zIcon]=\"zNoDataIcon()\" zSize=\"sm\" [zMessage]=\"effectiveNoDataText()\" />\n }\n </div>\n } @else if (shouldUseVirtualScroll()) {\n <!-- Virtual Scroll Mode -->\n <div\n #virtualScrollElement\n class=\"z-autocomplete-content-state z-autocomplete-options z-autocomplete-virtual-scroll relative overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"effectiveHeightExpand()\">\n <div class=\"z-autocomplete-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n @let isActive = activeIndex() === virtualItem.index;\n <div\n #virtualOptionEl\n class=\"z-autocomplete-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"getOptionClasses(opt, virtualItem.index)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"zDynamicSize() ? null : effectiveOptionHeight()\"\n [style.minHeight.px]=\"zDynamicSize() ? effectiveOptionHeight() : null\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(virtualItem.index)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"virtualOptionEl\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Normal Scroll Mode -->\n <div\n #optionsContainer\n class=\"z-autocomplete-content-state z-autocomplete-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\"\n [style.maxHeight.px]=\"effectiveHeightExpand()\">\n @for (item of optionViews(); track item.trackKey) {\n @let opt = item.option;\n @let i = item.index;\n @let isActive = activeIndex() === i;\n <div\n #optionEl2\n class=\"z-autocomplete-option relative min-w-0\"\n [ngClass]=\"getOptionClasses(opt, i)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [style.minHeight.px]=\"effectiveOptionHeight()\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(i)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n @if (zEnableLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n\n @if (zLoadingMore()) {\n <div class=\"z-autocomplete-loading-more border-border/50 flex items-center justify-center border-t py-1.5\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [".z-autocomplete-wrapper{width:100%}.z-autocomplete-trigger{-webkit-user-select:none;user-select:none}.z-autocomplete-trigger:focus-within{outline:none}.z-autocomplete-trigger *{cursor:inherit}.z-autocomplete-input{text-overflow:ellipsis;overflow:hidden}.z-autocomplete-input::placeholder{color:hsl(var(--muted-foreground))}.z-autocomplete-input:disabled{cursor:not-allowed}.z-autocomplete-open-bottom{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.z-autocomplete-open-top{border-top-left-radius:0!important;border-top-right-radius:0!important}.z-autocomplete-dropdown{animation:z-autocomplete-dropdown-from-top .15s ease-out}.z-autocomplete-dropdown-bottom{animation:z-autocomplete-dropdown-from-bottom .15s ease-out}@keyframes z-autocomplete-dropdown-from-top{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-autocomplete-dropdown-from-bottom{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}.z-autocomplete-separator{display:none}.z-autocomplete-options{overflow-x:hidden!important}.z-autocomplete-scrollbar{--scrollbar-padding: 0;--scrollbar-track-color: transparent;--scrollbar-thumb-color: hsl(var(--muted-foreground) / .3);--scrollbar-thumb-hover-color: hsl(var(--muted-foreground) / .5);--scrollbar-size: 6px}.z-autocomplete-virtual-scroll .z-autocomplete-virtual-inner{width:100%}.z-autocomplete-content-state{animation:z-autocomplete-content-fade-in .15s ease-out}@keyframes z-autocomplete-content-fade-in{0%{opacity:0}to{opacity:1}}.z-autocomplete-option mark{background:transparent;color:hsl(var(--primary));font-weight:600}.z-autocomplete-option{transition:background-color .1s ease,color .1s ease}.z-autocomplete-options:not(.z-autocomplete-virtual-scroll) .z-autocomplete-option{animation:z-autocomplete-option-enter .12s ease-out;animation-fill-mode:both}@keyframes z-autocomplete-option-enter{0%{opacity:0}to{opacity:1}}\n"] }]
|
|
1019
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, exportAs: 'zAutocomplete', template: "<div class=\"z-autocomplete-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"autocompleteId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n <div\n #triggerEl\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"0\"\n [zDisabled]=\"isInteractionDisabled()\"\n zTrigger=\"manual\"\n zPosition=\"bottom\"\n zClass=\"border-0 shadow-none bg-transparent p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n (zPositionChange)=\"onPositionChange($event)\"\n class=\"z-autocomplete-trigger\"\n [class]=\"inputClasses()\"\n [class.z-autocomplete-open]=\"uiState().isOpen\"\n [class.z-autocomplete-open-top]=\"uiState().isOpen && isPositionTop()\"\n [class.z-autocomplete-open-bottom]=\"uiState().isOpen && !isPositionTop()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"uiState().isOpen\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"dropdownId\">\n @if (zPrefix()) {\n <z-icon [zType]=\"zPrefix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <input\n #inputEl\n [id]=\"autocompleteId\"\n type=\"text\"\n class=\"z-autocomplete-input min-w-0 flex-1 bg-transparent outline-none\"\n [class.text-sm]=\"zSize() === 'sm' || zSize() === 'default'\"\n [placeholder]=\"zPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"isReadonly()\"\n [value]=\"inputValue()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur($event)\"\n (click)=\"onInputClick()\"\n (keydown)=\"onKeydown($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n\n @if (isLoading() || isLoadingState() || isLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"16\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n } @else {\n @if (zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 cursor-pointer items-center justify-center transition-colors\"\n (mousedown)=\"clearInput($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" class=\"cursor-pointer!\" />\n </button>\n }\n\n @if (zSuffix()) {\n <z-icon [zType]=\"zSuffix() || 'lucideSearch'\" zSize=\"16\" class=\"text-muted-foreground shrink-0\" />\n }\n }\n </div>\n</div>\n\n<ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-autocomplete-dropdown bg-popover border-ring overflow-hidden border shadow-lg\"\n [class.z-autocomplete-dropdown-bottom]=\"!isPositionTop()\"\n [class.rounded-b-sm]=\"!isPositionTop()\"\n [class.rounded-t-sm]=\"isPositionTop()\"\n [class.border-t-0]=\"!isPositionTop()\"\n [class.border-b-0]=\"isPositionTop()\"\n [style.width.px]=\"dropdownWidth()\"\n role=\"listbox\"\n (mousedown)=\"$event.preventDefault()\">\n @if (isLoading() || isLoadingState()) {\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length === 0) {\n <!-- Empty State -->\n <div\n class=\"z-autocomplete-content-state flex flex-col items-center justify-center p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\">\n @if (inputValue().trim() !== '') {\n <!-- Searched but no results -->\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <!-- No data initially -->\n <z-empty [zIcon]=\"zNoDataIcon()\" zSize=\"sm\" [zMessage]=\"effectiveNoDataText()\" />\n }\n </div>\n } @else if (shouldUseVirtualScroll()) {\n <!-- Virtual Scroll Mode -->\n <div\n #virtualScrollElement\n class=\"z-autocomplete-content-state z-autocomplete-options z-autocomplete-virtual-scroll relative overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"effectiveHeightExpand()\">\n <div class=\"z-autocomplete-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n @let isActive = activeIndex() === virtualItem.index;\n <div\n #virtualOptionEl\n class=\"z-autocomplete-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"getOptionClasses(opt, virtualItem.index)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"zDynamicSize() ? null : effectiveOptionHeight()\"\n [style.minHeight.px]=\"zDynamicSize() ? effectiveOptionHeight() : null\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(virtualItem.index)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"virtualOptionEl\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Normal Scroll Mode -->\n <div\n #optionsContainer\n class=\"z-autocomplete-content-state z-autocomplete-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.minHeight.px]=\"effectiveHeightExpand()\"\n [style.maxHeight.px]=\"effectiveHeightExpand()\">\n @for (item of optionViews(); track item.trackKey) {\n @let opt = item.option;\n @let i = item.index;\n @let isActive = activeIndex() === i;\n <div\n #optionEl2\n class=\"z-autocomplete-option relative min-w-0\"\n [ngClass]=\"getOptionClasses(opt, i)\"\n [class.items-start]=\"hasCustomOptionTemplate()\"\n [style.minHeight.px]=\"effectiveOptionHeight()\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(i)\"\n (click)=\"selectOption(opt)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveOptionTemplate()!; context: { $implicit: opt, active: isActive }\" />\n } @else {\n @if (opt.icon) {\n <z-icon [zType]=\"opt.icon\" zSize=\"16\" class=\"shrink-0\" />\n }\n <div class=\"min-w-0 flex-1\">\n <span\n class=\"block min-w-0 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"\n config().highlightMatch ? (opt.label | zHighlight: highlightQuery() | zSafeHtml) : opt.label\n \"></span>\n @if (opt.description) {\n <span class=\"text-muted-foreground block min-w-0 truncate text-xs\">{{ opt.description }}</span>\n }\n </div>\n }\n </div>\n }\n @if (canLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n\n @if (isLoadingMore()) {\n <div class=\"z-autocomplete-loading-more border-border/50 flex items-center justify-center border-t py-1.5\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [".z-autocomplete-wrapper{width:100%}.z-autocomplete-trigger{-webkit-user-select:none;user-select:none}.z-autocomplete-trigger:focus-within{outline:none}.z-autocomplete-trigger *{cursor:inherit}.z-autocomplete-input{text-overflow:ellipsis;overflow:hidden}.z-autocomplete-input::placeholder{color:hsl(var(--muted-foreground))}.z-autocomplete-input:disabled{cursor:not-allowed}.z-autocomplete-open-bottom{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.z-autocomplete-open-top{border-top-left-radius:0!important;border-top-right-radius:0!important}.z-autocomplete-dropdown{animation:z-autocomplete-dropdown-from-top .15s ease-out}.z-autocomplete-dropdown-bottom{animation:z-autocomplete-dropdown-from-bottom .15s ease-out}@keyframes z-autocomplete-dropdown-from-top{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-autocomplete-dropdown-from-bottom{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}.z-autocomplete-separator{display:none}.z-autocomplete-options{overflow-x:hidden!important}.z-autocomplete-scrollbar{--scrollbar-padding: 0;--scrollbar-track-color: transparent;--scrollbar-thumb-color: hsl(var(--muted-foreground) / .3);--scrollbar-thumb-hover-color: hsl(var(--muted-foreground) / .5);--scrollbar-size: 6px}.z-autocomplete-virtual-scroll .z-autocomplete-virtual-inner{width:100%}.z-autocomplete-content-state{animation:z-autocomplete-content-fade-in .15s ease-out}@keyframes z-autocomplete-content-fade-in{0%{opacity:0}to{opacity:1}}.z-autocomplete-option mark{background:transparent;color:hsl(var(--primary));font-weight:600}.z-autocomplete-option{transition:background-color .1s ease,color .1s ease}.z-autocomplete-options:not(.z-autocomplete-virtual-scroll) .z-autocomplete-option{animation:z-autocomplete-option-enter .12s ease-out;animation-fill-mode:both}@keyframes z-autocomplete-option-enter{0%{opacity:0}to{opacity:1}}\n"] }]
|
|
860
1020
|
}], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }], dropdownTpl: [{ type: i0.ViewChild, args: ['dropdownTpl', { isSignal: true }] }], virtualScrollRef: [{ type: i0.ViewChild, args: ['virtualScrollElement', { isSignal: true }] }], optionsContainerRef: [{ type: i0.ViewChild, args: ['optionsContainer', { isSignal: true }] }], loadMoreSentinelRef: [{ type: i0.ViewChild, args: ['loadMoreSentinel', { isSignal: true }] }], virtualOptionElements: [{ type: i0.ViewChildren, args: ['virtualOptionEl', { isSignal: true }] }], customOptionDirective: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ZAutocompleteOptionDirective), { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptions", required: false }] }], zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zType", required: false }] }], zLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLabel", required: false }] }], zLabelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLabelClass", required: false }] }], zPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPlaceholder", required: false }] }], zDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDisabled", required: false }] }], zReadonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "zReadonly", required: false }] }], zLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLoading", required: false }] }], zRequired: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRequired", required: false }] }], zPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPrefix", required: false }] }], zSuffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSuffix", required: false }] }], zAllowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowClear", required: false }] }], zVirtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "zVirtualScroll", required: false }] }], zDynamicSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDynamicSize", required: false }] }], zOptionHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptionHeight", required: false }] }], zHeightExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "zHeightExpand", required: false }] }], zMaxVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMaxVisible", required: false }] }], zResetOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "zResetOnSelect", required: false }] }], zEmptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEmptyText", required: false }] }], zEmptyIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEmptyIcon", required: false }] }], zNoDataText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zNoDataText", required: false }] }], zNoDataIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "zNoDataIcon", required: false }] }], zAllowCustomValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowCustomValue", required: false }] }], zDebounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDebounceTime", required: false }] }], zLoadingMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLoadingMore", required: false }] }], zEnableLoadMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEnableLoadMore", required: false }] }], zScrollDistance: [{ type: i0.Input, args: [{ isSignal: true, alias: "zScrollDistance", required: false }] }], zKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "zKey", required: false }] }], zOptionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptionTemplate", required: false }] }], zOnSearch: [{ type: i0.Output, args: ["zOnSearch"] }], zOnLoadMore: [{ type: i0.Output, args: ["zOnLoadMore"] }], zOnSelect: [{ type: i0.Output, args: ["zOnSelect"] }], zOnEnter: [{ type: i0.Output, args: ["zOnEnter"] }], zOnCommit: [{ type: i0.Output, args: ["zOnCommit"] }], zValueChange: [{ type: i0.Output, args: ["zValueChange"] }], zOnBlur: [{ type: i0.Output, args: ["zOnBlur"] }], zOnFocus: [{ type: i0.Output, args: ["zOnFocus"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zEvent: [{ type: i0.Output, args: ["zEvent"] }] } });
|
|
861
1021
|
|
|
862
1022
|
/**
|