@shival99/z-ui 2.0.49 → 2.0.51

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.
@@ -13,7 +13,7 @@ import { ZPopoverDirective } from '@shival99/z-ui/components/z-popover';
13
13
  import { ZTooltipDirective } from '@shival99/z-ui/components/z-tooltip';
14
14
  import { ZHighlightPipe, ZSafeHtmlPipe } from '@shival99/z-ui/pipes';
15
15
  import { ZTranslateService } from '@shival99/z-ui/services';
16
- import { zRemoveVietnamese, zMergeClasses, zTransform, zUuid, zMergeAsyncOptions, zCreateEvent, Z_ASYNC_OPTIONS_DEFAULT_PAGE_SIZE, zToAsyncOptionsObservable, zResolveAsyncOptionsHasMore } from '@shival99/z-ui/utils';
16
+ import { zRemoveVietnamese, zMergeClasses, zTransform, zUuid, zResolveAsyncSelectedOptions, zMergeAsyncOptions, zCreateEvent, Z_ASYNC_OPTIONS_DEFAULT_PAGE_SIZE, zToAsyncOptionsObservable, zResolveAsyncOptionsHasMore } from '@shival99/z-ui/utils';
17
17
  import { Subject, debounceTime, merge, filter, finalize, isObservable, takeUntil, catchError, of, firstValueFrom } from 'rxjs';
18
18
  import { cva } from 'class-variance-authority';
19
19
 
@@ -43,13 +43,114 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
43
43
  }]
44
44
  }] });
45
45
 
46
+ const Z_SELECT_DEFAULT_CONFIG = {
47
+ minLength: 0,
48
+ debounceTime: 300,
49
+ };
50
+ const TAG_COLORS = [
51
+ {
52
+ bg: 'bg-blue-100 dark:bg-blue-950',
53
+ text: 'text-blue-700 dark:text-blue-300',
54
+ border: 'border-blue-300 dark:border-blue-800',
55
+ },
56
+ {
57
+ bg: 'bg-green-100 dark:bg-green-950',
58
+ text: 'text-green-700 dark:text-green-300',
59
+ border: 'border-green-300 dark:border-green-800',
60
+ },
61
+ {
62
+ bg: 'bg-purple-100 dark:bg-purple-950',
63
+ text: 'text-purple-700 dark:text-purple-300',
64
+ border: 'border-purple-300 dark:border-purple-800',
65
+ },
66
+ {
67
+ bg: 'bg-orange-100 dark:bg-orange-950',
68
+ text: 'text-orange-700 dark:text-orange-300',
69
+ border: 'border-orange-300 dark:border-orange-800',
70
+ },
71
+ {
72
+ bg: 'bg-pink-100 dark:bg-pink-950',
73
+ text: 'text-pink-700 dark:text-pink-300',
74
+ border: 'border-pink-300 dark:border-pink-800',
75
+ },
76
+ {
77
+ bg: 'bg-cyan-100 dark:bg-cyan-950',
78
+ text: 'text-cyan-700 dark:text-cyan-300',
79
+ border: 'border-cyan-300 dark:border-cyan-800',
80
+ },
81
+ {
82
+ bg: 'bg-yellow-100 dark:bg-yellow-950',
83
+ text: 'text-yellow-700 dark:text-yellow-300',
84
+ border: 'border-yellow-300 dark:border-yellow-800',
85
+ },
86
+ {
87
+ bg: 'bg-red-100 dark:bg-red-950',
88
+ text: 'text-red-700 dark:text-red-300',
89
+ border: 'border-red-300 dark:border-red-800',
90
+ },
91
+ {
92
+ bg: 'bg-indigo-100 dark:bg-indigo-950',
93
+ text: 'text-indigo-700 dark:text-indigo-300',
94
+ border: 'border-indigo-300 dark:border-indigo-800',
95
+ },
96
+ {
97
+ bg: 'bg-teal-100 dark:bg-teal-950',
98
+ text: 'text-teal-700 dark:text-teal-300',
99
+ border: 'border-teal-300 dark:border-teal-800',
100
+ },
101
+ ];
102
+
103
+ const colorCache = new Map();
104
+ function getTagColor(value) {
105
+ const key = String(value);
106
+ const cached = colorCache.get(key);
107
+ if (cached) {
108
+ return cached;
109
+ }
110
+ let hash = 0;
111
+ for (let i = 0; i < key.length; i++) {
112
+ hash = (hash << 5) - hash + key.charCodeAt(i);
113
+ hash = hash & hash;
114
+ }
115
+ const index = Math.abs(hash) % TAG_COLORS.length;
116
+ const color = TAG_COLORS[index];
117
+ colorCache.set(key, color);
118
+ return color;
119
+ }
120
+ function filterOptions(options, searchText) {
121
+ const query = searchText.trim();
122
+ if (!query) {
123
+ return options;
124
+ }
125
+ const normalizedQuery = zRemoveVietnamese(query.toLowerCase());
126
+ return options.filter(opt => {
127
+ const normalizedLabel = zRemoveVietnamese(opt.label.toLowerCase());
128
+ return normalizedLabel.includes(normalizedQuery);
129
+ });
130
+ }
131
+ function zGetSelectValueKey(value, key) {
132
+ if (!key) {
133
+ return value;
134
+ }
135
+ if (zIsRecord(value) && key in value) {
136
+ return value[key];
137
+ }
138
+ return value;
139
+ }
140
+ function zIsSelectValueEqual(left, right, key) {
141
+ return zGetSelectValueKey(left, key) === zGetSelectValueKey(right, key);
142
+ }
143
+ function zIsRecord(value) {
144
+ return typeof value === 'object' && value !== null;
145
+ }
146
+
46
147
  class ZIsSelectedPipe {
47
- transform(option, value, isMultipleMode) {
148
+ transform(option, value, isMultipleMode, zKey = '') {
48
149
  if (isMultipleMode) {
49
150
  const current = value ?? [];
50
- return current.includes(option.value);
151
+ return current.some(currentValue => zIsSelectValueEqual(currentValue, option.value, zKey));
51
152
  }
52
- return value === option.value;
153
+ return zIsSelectValueEqual(value, option.value, zKey);
53
154
  }
54
155
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZIsSelectedPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
55
156
  static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.9", ngImport: i0, type: ZIsSelectedPipe, isStandalone: true, name: "zIsSelected" });
@@ -137,92 +238,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
137
238
  }]
138
239
  }] });
139
240
 
140
- const Z_SELECT_DEFAULT_CONFIG = {
141
- minLength: 0,
142
- debounceTime: 300,
143
- };
144
- const TAG_COLORS = [
145
- {
146
- bg: 'bg-blue-100 dark:bg-blue-950',
147
- text: 'text-blue-700 dark:text-blue-300',
148
- border: 'border-blue-300 dark:border-blue-800',
149
- },
150
- {
151
- bg: 'bg-green-100 dark:bg-green-950',
152
- text: 'text-green-700 dark:text-green-300',
153
- border: 'border-green-300 dark:border-green-800',
154
- },
155
- {
156
- bg: 'bg-purple-100 dark:bg-purple-950',
157
- text: 'text-purple-700 dark:text-purple-300',
158
- border: 'border-purple-300 dark:border-purple-800',
159
- },
160
- {
161
- bg: 'bg-orange-100 dark:bg-orange-950',
162
- text: 'text-orange-700 dark:text-orange-300',
163
- border: 'border-orange-300 dark:border-orange-800',
164
- },
165
- {
166
- bg: 'bg-pink-100 dark:bg-pink-950',
167
- text: 'text-pink-700 dark:text-pink-300',
168
- border: 'border-pink-300 dark:border-pink-800',
169
- },
170
- {
171
- bg: 'bg-cyan-100 dark:bg-cyan-950',
172
- text: 'text-cyan-700 dark:text-cyan-300',
173
- border: 'border-cyan-300 dark:border-cyan-800',
174
- },
175
- {
176
- bg: 'bg-yellow-100 dark:bg-yellow-950',
177
- text: 'text-yellow-700 dark:text-yellow-300',
178
- border: 'border-yellow-300 dark:border-yellow-800',
179
- },
180
- {
181
- bg: 'bg-red-100 dark:bg-red-950',
182
- text: 'text-red-700 dark:text-red-300',
183
- border: 'border-red-300 dark:border-red-800',
184
- },
185
- {
186
- bg: 'bg-indigo-100 dark:bg-indigo-950',
187
- text: 'text-indigo-700 dark:text-indigo-300',
188
- border: 'border-indigo-300 dark:border-indigo-800',
189
- },
190
- {
191
- bg: 'bg-teal-100 dark:bg-teal-950',
192
- text: 'text-teal-700 dark:text-teal-300',
193
- border: 'border-teal-300 dark:border-teal-800',
194
- },
195
- ];
196
-
197
- const colorCache = new Map();
198
- function getTagColor(value) {
199
- const key = String(value);
200
- const cached = colorCache.get(key);
201
- if (cached) {
202
- return cached;
203
- }
204
- let hash = 0;
205
- for (let i = 0; i < key.length; i++) {
206
- hash = (hash << 5) - hash + key.charCodeAt(i);
207
- hash = hash & hash;
208
- }
209
- const index = Math.abs(hash) % TAG_COLORS.length;
210
- const color = TAG_COLORS[index];
211
- colorCache.set(key, color);
212
- return color;
213
- }
214
- function filterOptions(options, searchText) {
215
- const query = searchText.trim();
216
- if (!query) {
217
- return options;
218
- }
219
- const normalizedQuery = zRemoveVietnamese(query.toLowerCase());
220
- return options.filter(opt => {
221
- const normalizedLabel = zRemoveVietnamese(opt.label.toLowerCase());
222
- return normalizedLabel.includes(normalizedQuery);
223
- });
224
- }
225
-
226
241
  class ZTagClassesPipe {
227
242
  transform(option, size, isTagsMode) {
228
243
  const baseClasses = zSelectTagVariants({ zSize: size });
@@ -328,6 +343,8 @@ class ZSelectComponent {
328
343
  }, ...(ngDevMode ? [{ debugName: "uiState" }] : []));
329
344
  selectId = zUuid('z-select');
330
345
  dropdownId = `${this.selectId}-dropdown`;
346
+ actualPosition = signal('bottom', ...(ngDevMode ? [{ debugName: "actualPosition" }] : []));
347
+ isPositionTop = computed(() => this.actualPosition().startsWith('top'), ...(ngDevMode ? [{ debugName: "isPositionTop" }] : []));
331
348
  searchText = signal('', ...(ngDevMode ? [{ debugName: "searchText" }] : []));
332
349
  dropdownWidth = signal(0, ...(ngDevMode ? [{ debugName: "dropdownWidth" }] : []));
333
350
  currentValue = this._value.asReadonly();
@@ -337,6 +354,7 @@ class ZSelectComponent {
337
354
  }), ...(ngDevMode ? [{ debugName: "config" }] : []));
338
355
  hasAsyncOptions = computed(() => !!this.config().async?.load, ...(ngDevMode ? [{ debugName: "hasAsyncOptions" }] : []));
339
356
  sourceOptions = computed(() => (this.hasAsyncOptions() ? this._asyncOptions() : this.zOptions()), ...(ngDevMode ? [{ debugName: "sourceOptions" }] : []));
357
+ asyncSelectedOptions = computed(() => zResolveAsyncSelectedOptions(this.config().async), ...(ngDevMode ? [{ debugName: "asyncSelectedOptions" }] : []));
340
358
  isLoading = computed(() => this.zLoading() || this._asyncLoading(), ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
341
359
  isLoadingMore = computed(() => this.zLoadingMore() || this._asyncLoadingMore(), ...(ngDevMode ? [{ debugName: "isLoadingMore" }] : []));
342
360
  canLoadMore = computed(() => this.hasAsyncOptions() ? this._asyncHasMore() : this.zEnableLoadMore(), ...(ngDevMode ? [{ debugName: "canLoadMore" }] : []));
@@ -389,6 +407,17 @@ class ZSelectComponent {
389
407
  label: this._zTranslate.instant(opt.label),
390
408
  }));
391
409
  }, ...(ngDevMode ? [{ debugName: "translatedOptions" }] : []));
410
+ translatedAsyncSelectedOptions = computed(() => {
411
+ this._zTranslate.currentLang();
412
+ const options = this.asyncSelectedOptions();
413
+ if (!this.zTranslateLabels()) {
414
+ return options;
415
+ }
416
+ return options.map(opt => ({
417
+ ...opt,
418
+ label: this._zTranslate.instant(opt.label),
419
+ }));
420
+ }, ...(ngDevMode ? [{ debugName: "translatedAsyncSelectedOptions" }] : []));
392
421
  isMultipleMode = computed(() => {
393
422
  const mode = this.zMode();
394
423
  return mode === 'multiple' || mode === 'tags';
@@ -410,7 +439,7 @@ class ZSelectComponent {
410
439
  }, ...(ngDevMode ? [{ debugName: "effectiveOptionTemplate" }] : []));
411
440
  knownOptions = computed(() => {
412
441
  if (this.zSearchServer() || this.hasAsyncOptions()) {
413
- return this._allKnownOptions();
442
+ return zMergeAsyncOptions(this._allKnownOptions(), this.translatedAsyncSelectedOptions(), this.config().async?.dedupeBy);
414
443
  }
415
444
  return this.translatedOptions();
416
445
  }, ...(ngDevMode ? [{ debugName: "knownOptions" }] : []));
@@ -437,7 +466,7 @@ class ZSelectComponent {
437
466
  return null;
438
467
  }
439
468
  const options = this.knownOptions();
440
- return options.find(opt => opt.value === value) ?? null;
469
+ return this._findOptionByValue(options, value) ?? null;
441
470
  }, ...(ngDevMode ? [{ debugName: "selectedOption" }] : []));
442
471
  selectedOptions = computed(() => {
443
472
  this._zTranslate.currentLang();
@@ -450,9 +479,19 @@ class ZSelectComponent {
450
479
  }
451
480
  const options = this.knownOptions();
452
481
  return value
453
- .map(v => options.find(opt => opt.value === v))
482
+ .map(v => this._findOptionByValue(options, v))
454
483
  .filter((opt) => opt !== undefined);
455
484
  }, ...(ngDevMode ? [{ debugName: "selectedOptions" }] : []));
485
+ selected = computed(() => {
486
+ if (this.isMultipleMode()) {
487
+ return this.selectedOptions();
488
+ }
489
+ const option = this.selectedOption();
490
+ if (!option) {
491
+ return [];
492
+ }
493
+ return [option];
494
+ }, ...(ngDevMode ? [{ debugName: "selected" }] : []));
456
495
  displayedTags = computed(() => {
457
496
  const selected = this.selectedOptions();
458
497
  const max = this.zMaxTagCount();
@@ -483,8 +522,7 @@ class ZSelectComponent {
483
522
  if (!Array.isArray(selectedValues)) {
484
523
  return false;
485
524
  }
486
- const selectedSet = new Set(selectedValues);
487
- return enabledValues.every(value => selectedSet.has(value));
525
+ return enabledValues.every(value => selectedValues.some(selectedValue => this._isValueEqual(selectedValue, value)));
488
526
  }, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
489
527
  filteredOptions = computed(() => {
490
528
  if (this.zSearchServer() || this.hasAsyncOptions()) {
@@ -881,10 +919,14 @@ class ZSelectComponent {
881
919
  triggerEl?.blur();
882
920
  }
883
921
  onPopoverHideEnd() {
922
+ this.actualPosition.set('bottom');
884
923
  if (this.zSearchServer() || this.hasAsyncOptions()) {
885
924
  this.searchText.set('');
886
925
  }
887
926
  }
927
+ onPositionChange(position) {
928
+ this.actualPosition.set(position);
929
+ }
888
930
  onSearchChange(value) {
889
931
  this._searchSubject.next(value);
890
932
  requestAnimationFrame(() => {
@@ -908,13 +950,15 @@ class ZSelectComponent {
908
950
  }
909
951
  if (this.isMultipleMode()) {
910
952
  const current = this._value() ?? [];
911
- const isSelected = current.includes(option.value);
912
- const newValue = isSelected ? current.filter(v => v !== option.value) : [...current, option.value];
953
+ const isSelected = current.some(value => this._isValueEqual(value, option.value));
954
+ const newValue = isSelected
955
+ ? current.filter(value => !this._isValueEqual(value, option.value))
956
+ : [...current, option.value];
913
957
  this._value.set(newValue);
914
958
  this.uiState.update(s => ({ ...s, dirty: true }));
915
959
  this._onChange(newValue);
916
960
  this._triggerAsyncValidation(newValue
917
- .map(v => this.knownOptions().find(o => o.value === v))
961
+ .map(value => this._findOptionByValue(this.knownOptions(), value))
918
962
  .filter((o) => o !== undefined));
919
963
  return;
920
964
  }
@@ -930,7 +974,7 @@ class ZSelectComponent {
930
974
  removeOption(event, option) {
931
975
  event.stopPropagation();
932
976
  const current = this._value() ?? [];
933
- const newValue = current.filter(v => v !== option.value);
977
+ const newValue = current.filter(value => !this._isValueEqual(value, option.value));
934
978
  this._value.set(newValue);
935
979
  this.uiState.update(s => ({ ...s, dirty: true }));
936
980
  this._onChange(newValue);
@@ -972,13 +1016,20 @@ class ZSelectComponent {
972
1016
  }
973
1017
  this.selectAll();
974
1018
  }
975
- trackByValue = (_index, option) => {
1019
+ trackByValue = (_index, option) => this._getOptionKey(option);
1020
+ _findOptionByValue(options, value) {
1021
+ return options.find(option => this._isValueEqual(option.value, value));
1022
+ }
1023
+ _getOptionKey(option) {
976
1024
  const key = this.zKey();
977
1025
  if (key && key in option) {
978
1026
  return option[key];
979
1027
  }
980
- return option.value;
981
- };
1028
+ return zGetSelectValueKey(option.value, key);
1029
+ }
1030
+ _isValueEqual(left, right) {
1031
+ return zIsSelectValueEqual(left, right, this.zKey());
1032
+ }
982
1033
  _emitControl() {
983
1034
  this.zControl.emit({
984
1035
  valid: () => this.valid(),
@@ -991,8 +1042,7 @@ class ZSelectComponent {
991
1042
  isValidating: computed(() => this.uiState().isValidating),
992
1043
  isOpen: computed(() => this.uiState().isOpen),
993
1044
  value: this._value.asReadonly(),
994
- selectedOption: this.selectedOption,
995
- selectedOptions: this.selectedOptions,
1045
+ selected: this.selected,
996
1046
  errorMessage: this.errorMessage,
997
1047
  });
998
1048
  }
@@ -1309,7 +1359,7 @@ class ZSelectComponent {
1309
1359
  useExisting: forwardRef(() => ZSelectComponent),
1310
1360
  multi: true,
1311
1361
  },
1312
- ], queries: [{ propertyName: "customSelectedDirective", first: true, predicate: (ZSelectSelectedDirective), descendants: true, isSignal: true }, { propertyName: "customOptionDirective", first: true, predicate: (ZSelectOptionDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "searchInputRef", first: true, predicate: ["dropdownSearchInput"], descendants: true, isSignal: true }, { propertyName: "dropdownTpl", first: true, predicate: ["dropdownTpl"], descendants: true, isSignal: true }, { propertyName: "optionsContainerRef", first: true, predicate: ["optionsContainer"], descendants: true, isSignal: true }, { propertyName: "virtualScrollRef", first: true, predicate: ["virtualScrollElement"], descendants: true, isSignal: true }, { propertyName: "loadMoreSentinelRef", first: true, predicate: ["loadMoreSentinel"], descendants: true, isSignal: true }], exportAs: ["zSelect"], ngImport: i0, template: "<div class=\"z-select-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"selectId\" 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 class=\"relative\">\n <div\n #triggerEl\n [id]=\"selectId\"\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"6\"\n [zDisabled]=\"isInteractionDisabled()\"\n [zScrollClose]=\"zScrollClose()\"\n zPopoverWidth=\"trigger\"\n zTrigger=\"click\"\n [zPosition]=\"zPosition()\"\n zClass=\"border-0 shadow-none p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n class=\"z-select-trigger cursor-pointer\"\n [class]=\"selectClasses()\"\n [class.z-select-open]=\"uiState().isOpen\"\n (mousedown)=\"onTriggerMousedown()\"\n (keydown)=\"onTriggerKeydown($event)\"\n tabindex=\"0\"\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() || 'lucideChevronDown'\" zSize=\"18\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <div\n class=\"z-select-tags-wrapper flex min-w-0 flex-1 items-center gap-1\"\n [class.flex-wrap]=\"zWrap()\"\n [class.overflow-hidden]=\"!zWrap()\">\n @if (isMultipleMode()) {\n @if (selectedOptions().length === 0) {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n } @else {\n @for (opt of displayedTags(); track opt.value) {\n <span\n #tagEl\n [class]=\"opt | zTagClasses: zSize() : isTagsMode()\"\n class=\"z-select-tag\"\n [class.min-w-0]=\"!zWrap()\"\n [class.shrink]=\"!zWrap()\">\n @if (effectiveSelectedTemplate()) {\n <ng-container *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: opt }\" />\n } @else {\n <span\n class=\"truncate\"\n [class.max-w-25]=\"zWrap()\"\n z-tooltip\n [zContent]=\"opt.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"6\"\n [zTriggerElement]=\"tagEl\">\n {{ opt.label }}\n </span>\n }\n @if (zAllowClear() && !isDisabled()) {\n <button\n type=\"button\"\n class=\"-mr-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-sm transition-colors hover:bg-black/10\"\n (click)=\"removeOption($event, opt)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"10\" />\n </button>\n }\n </span>\n }\n @if (remainingCount() > 0) {\n <span\n class=\"z-select-remaining text-muted-foreground bg-muted rounded-sm px-1.5 py-0.5 text-xs font-medium\">\n +{{ remainingCount() }}\n </span>\n }\n }\n } @else {\n @if (selectedOption()) {\n @if (effectiveSelectedTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: selectedOption() }\" />\n } @else {\n <span\n class=\"truncate\"\n z-tooltip\n [zContent]=\"selectedOption()!.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"10\">\n {{ selectedOption()!.label }}\n </span>\n }\n } @else {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n }\n }\n </div>\n\n @if (isLoading() || isLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n @if (!isLoading() && zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 items-center justify-center transition-colors\"\n (click)=\"clearAll($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n\n @if (uiState().isValidating) {\n <z-icon zType=\"lucideLoader2\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n <z-icon\n zType=\"lucideChevronDown\"\n zSize=\"18\"\n class=\"text-muted-foreground shrink-0 transition-transform duration-200\"\n [class.rotate-180]=\"uiState().isOpen\" />\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 pt-2 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n </div>\n\n <ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-select-dropdown bg-popover border-border rounded-sm border shadow-[var(--z-popover-shadow)]\"\n [style.width.px]=\"dropdownWidth()\"\n [style.min-width.px]=\"dropdownWidth()\">\n @if (zShowSearch()) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"18\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #dropdownSearchInput\n type=\"text\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full min-w-0 overflow-hidden bg-transparent py-3 text-sm text-ellipsis whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n [placeholder]=\"effectivePlaceholderSearch()\"\n [ngModel]=\"searchText()\"\n (ngModelChange)=\"onSearchChange($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n </div>\n }\n\n @if (isLoading()) {\n <div class=\"flex items-center justify-center\" [style.height.px]=\"optionsMaxHeight()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length > 0) {\n @if (shouldUseVirtualScroll()) {\n <div\n #virtualScrollElement\n class=\"z-select-options z-select-virtual-scroll overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"optionsMaxHeight()\">\n <div class=\"z-select-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n <div\n #optionEl\n class=\"z-select-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"opt | zIsSelected: currentValue() : isMultipleMode() | zOptionClasses: opt.disabled\"\n [style.height.px]=\"zOptionHeight()\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: { $implicit: opt, selected: opt | zIsSelected: currentValue() : isMultipleMode() }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode()) {\n <z-icon zType=\"lucideCheck\" zSize=\"16\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n </div>\n @if (isLoadingMore()) {\n <div\n class=\"bg-popover/80 absolute right-0 bottom-0 left-0 flex items-center justify-center py-2\"\n [style.transform]=\"'translateY(' + virtualizer.getTotalSize() + 'px)'\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n </div>\n } @else {\n <div\n #optionsContainer\n class=\"z-select-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.maxHeight.px]=\"optionsMaxHeight()\">\n @for (opt of filteredOptions(); track opt.value) {\n <div\n #optionEl2\n class=\"z-select-option relative min-w-0\"\n [ngClass]=\"opt | zIsSelected: currentValue() : isMultipleMode() | zOptionClasses: opt.disabled\"\n [style.minHeight.px]=\"zOptionHeight()\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: { $implicit: opt, selected: opt | zIsSelected: currentValue() : isMultipleMode() }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zArrow]=\"false\"\n [zOffset]=\"5\"\n [zHideDelay]=\"0\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode()) {\n <z-icon zType=\"lucideCheck\" zSize=\"18\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n @if (canLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center p-1\" [style.height.px]=\"optionsMaxHeight()\">\n @if (isEmptyData()) {\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"effectiveNotFoundText()\" />\n }\n </div>\n }\n\n @if (isLoadingMore()) {\n <div class=\"z-select-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\n @if (zShowAction() && (zActionTemplate() || isMultipleMode())) {\n <div class=\"border-border flex items-center gap-2 border-t px-2 py-1.5\">\n @if (zActionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zActionTemplate()!\" />\n } @else {\n <z-button\n zSize=\"xs\"\n [zType]=\"isAllSelected() ? 'ghost-error' : 'ghost-info'\"\n class=\"min-w-0 flex-1\"\n (click)=\"toggleSelectAllAction()\"\n [zWave]=\"false\">\n <z-icon [zType]=\"isAllSelected() ? 'lucideX' : 'lucideCheckCheck'\" zSize=\"18\" class=\"shrink-0\" />\n <span class=\"truncate\">{{ isAllSelected() ? effectiveClearAllText() : effectiveSelectAllText() }}</span>\n </z-button>\n }\n </div>\n }\n </div>\n </ng-template>\n</div>\n", styles: [".z-select-trigger{-webkit-user-select:none;user-select:none}.z-select-trigger:focus{outline:none}.z-select-trigger *{cursor:inherit}.z-select-tag{-webkit-user-select:none;user-select:none;animation:z-select-tag-enter .2s cubic-bezier(.4,0,.2,1)}@keyframes z-select-tag-enter{0%{opacity:0;transform:scale(.8) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-select-remaining{animation:z-select-remaining-enter .25s cubic-bezier(.4,0,.2,1)}@keyframes z-select-remaining-enter{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.z-select-dropdown input{text-overflow:ellipsis;overflow:hidden}.z-select-options{overflow-x:hidden!important}.z-select-virtual-scroll .z-select-virtual-inner{width:100%}.z-select-loading-more{animation:z-select-loading-enter .2s ease-out}@keyframes z-select-loading-enter{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "pipe", type: ZIsSelectedPipe, name: "zIsSelected" }, { kind: "pipe", type: ZOptionClassesPipe, name: "zOptionClasses" }, { kind: "pipe", type: ZTagClassesPipe, name: "zTagClasses" }, { kind: "pipe", type: ZHighlightPipe, name: "zHighlight" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1362
+ ], queries: [{ propertyName: "customSelectedDirective", first: true, predicate: (ZSelectSelectedDirective), descendants: true, isSignal: true }, { propertyName: "customOptionDirective", first: true, predicate: (ZSelectOptionDirective), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "searchInputRef", first: true, predicate: ["dropdownSearchInput"], descendants: true, isSignal: true }, { propertyName: "dropdownTpl", first: true, predicate: ["dropdownTpl"], descendants: true, isSignal: true }, { propertyName: "optionsContainerRef", first: true, predicate: ["optionsContainer"], descendants: true, isSignal: true }, { propertyName: "virtualScrollRef", first: true, predicate: ["virtualScrollElement"], descendants: true, isSignal: true }, { propertyName: "loadMoreSentinelRef", first: true, predicate: ["loadMoreSentinel"], descendants: true, isSignal: true }], exportAs: ["zSelect"], ngImport: i0, template: "<div class=\"z-select-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"selectId\" 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 class=\"relative\">\n <div\n #triggerEl\n [id]=\"selectId\"\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"6\"\n [zDisabled]=\"isInteractionDisabled()\"\n [zScrollClose]=\"zScrollClose()\"\n zPopoverWidth=\"trigger\"\n zTrigger=\"click\"\n [zPosition]=\"zPosition()\"\n zClass=\"border-0 shadow-none p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n (zPositionChange)=\"onPositionChange($event)\"\n class=\"z-select-trigger cursor-pointer\"\n [class]=\"selectClasses()\"\n [class.z-select-open]=\"uiState().isOpen\"\n [class.z-select-open-top]=\"uiState().isOpen && isPositionTop()\"\n [class.z-select-open-bottom]=\"uiState().isOpen && !isPositionTop()\"\n (mousedown)=\"onTriggerMousedown()\"\n (keydown)=\"onTriggerKeydown($event)\"\n tabindex=\"0\"\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() || 'lucideChevronDown'\" zSize=\"18\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <div\n class=\"z-select-tags-wrapper flex min-w-0 flex-1 items-center gap-1\"\n [class.flex-wrap]=\"zWrap()\"\n [class.overflow-hidden]=\"!zWrap()\">\n @if (isMultipleMode()) {\n @if (selectedOptions().length === 0) {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n } @else {\n @for (opt of displayedTags(); track opt.value) {\n <span\n #tagEl\n [class]=\"opt | zTagClasses: zSize() : isTagsMode()\"\n class=\"z-select-tag\"\n [class.min-w-0]=\"!zWrap()\"\n [class.shrink]=\"!zWrap()\">\n @if (effectiveSelectedTemplate()) {\n <ng-container *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: opt }\" />\n } @else {\n <span\n class=\"truncate\"\n [class.max-w-25]=\"zWrap()\"\n z-tooltip\n [zContent]=\"opt.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"6\"\n [zTriggerElement]=\"tagEl\">\n {{ opt.label }}\n </span>\n }\n @if (zAllowClear() && !isDisabled()) {\n <button\n type=\"button\"\n class=\"-mr-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-sm transition-colors hover:bg-black/10\"\n (click)=\"removeOption($event, opt)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"10\" />\n </button>\n }\n </span>\n }\n @if (remainingCount() > 0) {\n <span\n class=\"z-select-remaining text-muted-foreground bg-muted rounded-sm px-1.5 py-0.5 text-xs font-medium\">\n +{{ remainingCount() }}\n </span>\n }\n }\n } @else {\n @if (selectedOption()) {\n @if (effectiveSelectedTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: selectedOption() }\" />\n } @else {\n <span\n class=\"truncate\"\n z-tooltip\n [zContent]=\"selectedOption()!.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"10\">\n {{ selectedOption()!.label }}\n </span>\n }\n } @else {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n }\n }\n </div>\n\n @if (isLoading() || isLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n @if (!isLoading() && zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 items-center justify-center transition-colors\"\n (click)=\"clearAll($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n\n @if (uiState().isValidating) {\n <z-icon zType=\"lucideLoader2\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n <z-icon\n zType=\"lucideChevronDown\"\n zSize=\"18\"\n class=\"text-muted-foreground shrink-0 transition-transform duration-200\"\n [class.rotate-180]=\"uiState().isOpen\" />\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 pt-2 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n </div>\n\n <ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-select-dropdown bg-popover border-border border shadow-[var(--z-popover-shadow)]\"\n [class.z-select-dropdown-bottom]=\"!isPositionTop()\"\n [class.z-select-dropdown-top]=\"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 [style.min-width.px]=\"dropdownWidth()\">\n @if (zShowSearch()) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"18\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #dropdownSearchInput\n type=\"text\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full min-w-0 overflow-hidden bg-transparent py-3 text-sm text-ellipsis whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n [placeholder]=\"effectivePlaceholderSearch()\"\n [ngModel]=\"searchText()\"\n (ngModelChange)=\"onSearchChange($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n </div>\n }\n\n @if (isLoading()) {\n <div class=\"flex items-center justify-center\" [style.height.px]=\"optionsMaxHeight()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length > 0) {\n @if (shouldUseVirtualScroll()) {\n <div\n #virtualScrollElement\n class=\"z-select-options z-select-virtual-scroll overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"optionsMaxHeight()\">\n <div class=\"z-select-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n <div\n #optionEl\n class=\"z-select-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"\n opt | zIsSelected: currentValue() : isMultipleMode() : zKey() | zOptionClasses: opt.disabled\n \"\n [style.height.px]=\"zOptionHeight()\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: {\n $implicit: opt,\n selected: opt | zIsSelected: currentValue() : isMultipleMode() : zKey(),\n }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode() : zKey()) {\n <z-icon zType=\"lucideCheck\" zSize=\"16\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n </div>\n @if (isLoadingMore()) {\n <div\n class=\"bg-popover/80 absolute right-0 bottom-0 left-0 flex items-center justify-center py-2\"\n [style.transform]=\"'translateY(' + virtualizer.getTotalSize() + 'px)'\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n </div>\n } @else {\n <div\n #optionsContainer\n class=\"z-select-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.maxHeight.px]=\"optionsMaxHeight()\">\n @for (opt of filteredOptions(); track opt.value) {\n <div\n #optionEl2\n class=\"z-select-option relative min-w-0\"\n [ngClass]=\"\n opt | zIsSelected: currentValue() : isMultipleMode() : zKey() | zOptionClasses: opt.disabled\n \"\n [style.minHeight.px]=\"zOptionHeight()\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: {\n $implicit: opt,\n selected: opt | zIsSelected: currentValue() : isMultipleMode() : zKey(),\n }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zArrow]=\"false\"\n [zOffset]=\"5\"\n [zHideDelay]=\"0\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode() : zKey()) {\n <z-icon zType=\"lucideCheck\" zSize=\"18\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n @if (canLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center p-1\" [style.height.px]=\"optionsMaxHeight()\">\n @if (isEmptyData()) {\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"effectiveNotFoundText()\" />\n }\n </div>\n }\n\n @if (isLoadingMore()) {\n <div class=\"z-select-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\n @if (zShowAction() && (zActionTemplate() || isMultipleMode())) {\n <div class=\"border-border flex items-center gap-2 border-t px-2 py-1.5\">\n @if (zActionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zActionTemplate()!\" />\n } @else {\n <z-button\n zSize=\"xs\"\n [zType]=\"isAllSelected() ? 'ghost-error' : 'ghost-info'\"\n class=\"min-w-0 flex-1\"\n (click)=\"toggleSelectAllAction()\"\n [zWave]=\"false\">\n <z-icon [zType]=\"isAllSelected() ? 'lucideX' : 'lucideCheckCheck'\" zSize=\"18\" class=\"shrink-0\" />\n <span class=\"truncate\">{{ isAllSelected() ? effectiveClearAllText() : effectiveSelectAllText() }}</span>\n </z-button>\n }\n </div>\n }\n </div>\n </ng-template>\n</div>\n", styles: [".z-select-trigger{-webkit-user-select:none;user-select:none}.z-select-trigger:focus{outline:none}.z-select-trigger *{cursor:inherit}.z-select-tag{-webkit-user-select:none;user-select:none;animation:z-select-tag-enter .2s cubic-bezier(.4,0,.2,1)}@keyframes z-select-tag-enter{0%{opacity:0;transform:scale(.8) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-select-remaining{animation:z-select-remaining-enter .25s cubic-bezier(.4,0,.2,1)}@keyframes z-select-remaining-enter{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.z-select-open-bottom{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.z-select-open-top{border-top-left-radius:0!important;border-top-right-radius:0!important}.z-select-dropdown{animation:z-select-dropdown-from-top .15s ease-out}.z-select-dropdown input{text-overflow:ellipsis;overflow:hidden}.z-select-dropdown-bottom{animation:z-select-dropdown-from-bottom .15s ease-out}@keyframes z-select-dropdown-from-top{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-select-dropdown-from-bottom{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}.z-select-options{overflow-x:hidden!important}.z-select-virtual-scroll .z-select-virtual-inner{width:100%}.z-select-loading-more{animation:z-select-loading-enter .2s ease-out}@keyframes z-select-loading-enter{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "pipe", type: ZIsSelectedPipe, name: "zIsSelected" }, { kind: "pipe", type: ZOptionClassesPipe, name: "zOptionClasses" }, { kind: "pipe", type: ZTagClassesPipe, name: "zTagClasses" }, { kind: "pipe", type: ZHighlightPipe, name: "zHighlight" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1313
1363
  }
1314
1364
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZSelectComponent, decorators: [{
1315
1365
  type: Component,
@@ -1334,7 +1384,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
1334
1384
  useExisting: forwardRef(() => ZSelectComponent),
1335
1385
  multi: true,
1336
1386
  },
1337
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, exportAs: 'zSelect', template: "<div class=\"z-select-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"selectId\" 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 class=\"relative\">\n <div\n #triggerEl\n [id]=\"selectId\"\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"6\"\n [zDisabled]=\"isInteractionDisabled()\"\n [zScrollClose]=\"zScrollClose()\"\n zPopoverWidth=\"trigger\"\n zTrigger=\"click\"\n [zPosition]=\"zPosition()\"\n zClass=\"border-0 shadow-none p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n class=\"z-select-trigger cursor-pointer\"\n [class]=\"selectClasses()\"\n [class.z-select-open]=\"uiState().isOpen\"\n (mousedown)=\"onTriggerMousedown()\"\n (keydown)=\"onTriggerKeydown($event)\"\n tabindex=\"0\"\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() || 'lucideChevronDown'\" zSize=\"18\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <div\n class=\"z-select-tags-wrapper flex min-w-0 flex-1 items-center gap-1\"\n [class.flex-wrap]=\"zWrap()\"\n [class.overflow-hidden]=\"!zWrap()\">\n @if (isMultipleMode()) {\n @if (selectedOptions().length === 0) {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n } @else {\n @for (opt of displayedTags(); track opt.value) {\n <span\n #tagEl\n [class]=\"opt | zTagClasses: zSize() : isTagsMode()\"\n class=\"z-select-tag\"\n [class.min-w-0]=\"!zWrap()\"\n [class.shrink]=\"!zWrap()\">\n @if (effectiveSelectedTemplate()) {\n <ng-container *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: opt }\" />\n } @else {\n <span\n class=\"truncate\"\n [class.max-w-25]=\"zWrap()\"\n z-tooltip\n [zContent]=\"opt.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"6\"\n [zTriggerElement]=\"tagEl\">\n {{ opt.label }}\n </span>\n }\n @if (zAllowClear() && !isDisabled()) {\n <button\n type=\"button\"\n class=\"-mr-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-sm transition-colors hover:bg-black/10\"\n (click)=\"removeOption($event, opt)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"10\" />\n </button>\n }\n </span>\n }\n @if (remainingCount() > 0) {\n <span\n class=\"z-select-remaining text-muted-foreground bg-muted rounded-sm px-1.5 py-0.5 text-xs font-medium\">\n +{{ remainingCount() }}\n </span>\n }\n }\n } @else {\n @if (selectedOption()) {\n @if (effectiveSelectedTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: selectedOption() }\" />\n } @else {\n <span\n class=\"truncate\"\n z-tooltip\n [zContent]=\"selectedOption()!.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"10\">\n {{ selectedOption()!.label }}\n </span>\n }\n } @else {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n }\n }\n </div>\n\n @if (isLoading() || isLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n @if (!isLoading() && zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 items-center justify-center transition-colors\"\n (click)=\"clearAll($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n\n @if (uiState().isValidating) {\n <z-icon zType=\"lucideLoader2\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n <z-icon\n zType=\"lucideChevronDown\"\n zSize=\"18\"\n class=\"text-muted-foreground shrink-0 transition-transform duration-200\"\n [class.rotate-180]=\"uiState().isOpen\" />\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 pt-2 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n </div>\n\n <ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-select-dropdown bg-popover border-border rounded-sm border shadow-[var(--z-popover-shadow)]\"\n [style.width.px]=\"dropdownWidth()\"\n [style.min-width.px]=\"dropdownWidth()\">\n @if (zShowSearch()) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"18\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #dropdownSearchInput\n type=\"text\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full min-w-0 overflow-hidden bg-transparent py-3 text-sm text-ellipsis whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n [placeholder]=\"effectivePlaceholderSearch()\"\n [ngModel]=\"searchText()\"\n (ngModelChange)=\"onSearchChange($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n </div>\n }\n\n @if (isLoading()) {\n <div class=\"flex items-center justify-center\" [style.height.px]=\"optionsMaxHeight()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length > 0) {\n @if (shouldUseVirtualScroll()) {\n <div\n #virtualScrollElement\n class=\"z-select-options z-select-virtual-scroll overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"optionsMaxHeight()\">\n <div class=\"z-select-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n <div\n #optionEl\n class=\"z-select-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"opt | zIsSelected: currentValue() : isMultipleMode() | zOptionClasses: opt.disabled\"\n [style.height.px]=\"zOptionHeight()\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: { $implicit: opt, selected: opt | zIsSelected: currentValue() : isMultipleMode() }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode()) {\n <z-icon zType=\"lucideCheck\" zSize=\"16\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n </div>\n @if (isLoadingMore()) {\n <div\n class=\"bg-popover/80 absolute right-0 bottom-0 left-0 flex items-center justify-center py-2\"\n [style.transform]=\"'translateY(' + virtualizer.getTotalSize() + 'px)'\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n </div>\n } @else {\n <div\n #optionsContainer\n class=\"z-select-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.maxHeight.px]=\"optionsMaxHeight()\">\n @for (opt of filteredOptions(); track opt.value) {\n <div\n #optionEl2\n class=\"z-select-option relative min-w-0\"\n [ngClass]=\"opt | zIsSelected: currentValue() : isMultipleMode() | zOptionClasses: opt.disabled\"\n [style.minHeight.px]=\"zOptionHeight()\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: { $implicit: opt, selected: opt | zIsSelected: currentValue() : isMultipleMode() }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zArrow]=\"false\"\n [zOffset]=\"5\"\n [zHideDelay]=\"0\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode()) {\n <z-icon zType=\"lucideCheck\" zSize=\"18\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n @if (canLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center p-1\" [style.height.px]=\"optionsMaxHeight()\">\n @if (isEmptyData()) {\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"effectiveNotFoundText()\" />\n }\n </div>\n }\n\n @if (isLoadingMore()) {\n <div class=\"z-select-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\n @if (zShowAction() && (zActionTemplate() || isMultipleMode())) {\n <div class=\"border-border flex items-center gap-2 border-t px-2 py-1.5\">\n @if (zActionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zActionTemplate()!\" />\n } @else {\n <z-button\n zSize=\"xs\"\n [zType]=\"isAllSelected() ? 'ghost-error' : 'ghost-info'\"\n class=\"min-w-0 flex-1\"\n (click)=\"toggleSelectAllAction()\"\n [zWave]=\"false\">\n <z-icon [zType]=\"isAllSelected() ? 'lucideX' : 'lucideCheckCheck'\" zSize=\"18\" class=\"shrink-0\" />\n <span class=\"truncate\">{{ isAllSelected() ? effectiveClearAllText() : effectiveSelectAllText() }}</span>\n </z-button>\n }\n </div>\n }\n </div>\n </ng-template>\n</div>\n", styles: [".z-select-trigger{-webkit-user-select:none;user-select:none}.z-select-trigger:focus{outline:none}.z-select-trigger *{cursor:inherit}.z-select-tag{-webkit-user-select:none;user-select:none;animation:z-select-tag-enter .2s cubic-bezier(.4,0,.2,1)}@keyframes z-select-tag-enter{0%{opacity:0;transform:scale(.8) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-select-remaining{animation:z-select-remaining-enter .25s cubic-bezier(.4,0,.2,1)}@keyframes z-select-remaining-enter{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.z-select-dropdown input{text-overflow:ellipsis;overflow:hidden}.z-select-options{overflow-x:hidden!important}.z-select-virtual-scroll .z-select-virtual-inner{width:100%}.z-select-loading-more{animation:z-select-loading-enter .2s ease-out}@keyframes z-select-loading-enter{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
1387
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, exportAs: 'zSelect', template: "<div class=\"z-select-wrapper relative flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"selectId\" 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 class=\"relative\">\n <div\n #triggerEl\n [id]=\"selectId\"\n z-popover\n [zPopoverContent]=\"dropdownTpl\"\n [zOffset]=\"6\"\n [zDisabled]=\"isInteractionDisabled()\"\n [zScrollClose]=\"zScrollClose()\"\n zPopoverWidth=\"trigger\"\n zTrigger=\"click\"\n [zPosition]=\"zPosition()\"\n zClass=\"border-0 shadow-none p-0\"\n (zControl)=\"onPopoverControl($event)\"\n (zShow)=\"onPopoverShow()\"\n (zHideStart)=\"onPopoverHideStart()\"\n (zHide)=\"onPopoverHideEnd()\"\n (zPositionChange)=\"onPositionChange($event)\"\n class=\"z-select-trigger cursor-pointer\"\n [class]=\"selectClasses()\"\n [class.z-select-open]=\"uiState().isOpen\"\n [class.z-select-open-top]=\"uiState().isOpen && isPositionTop()\"\n [class.z-select-open-bottom]=\"uiState().isOpen && !isPositionTop()\"\n (mousedown)=\"onTriggerMousedown()\"\n (keydown)=\"onTriggerKeydown($event)\"\n tabindex=\"0\"\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() || 'lucideChevronDown'\" zSize=\"18\" class=\"text-muted-foreground shrink-0\" />\n }\n\n <div\n class=\"z-select-tags-wrapper flex min-w-0 flex-1 items-center gap-1\"\n [class.flex-wrap]=\"zWrap()\"\n [class.overflow-hidden]=\"!zWrap()\">\n @if (isMultipleMode()) {\n @if (selectedOptions().length === 0) {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n } @else {\n @for (opt of displayedTags(); track opt.value) {\n <span\n #tagEl\n [class]=\"opt | zTagClasses: zSize() : isTagsMode()\"\n class=\"z-select-tag\"\n [class.min-w-0]=\"!zWrap()\"\n [class.shrink]=\"!zWrap()\">\n @if (effectiveSelectedTemplate()) {\n <ng-container *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: opt }\" />\n } @else {\n <span\n class=\"truncate\"\n [class.max-w-25]=\"zWrap()\"\n z-tooltip\n [zContent]=\"opt.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"6\"\n [zTriggerElement]=\"tagEl\">\n {{ opt.label }}\n </span>\n }\n @if (zAllowClear() && !isDisabled()) {\n <button\n type=\"button\"\n class=\"-mr-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-sm transition-colors hover:bg-black/10\"\n (click)=\"removeOption($event, opt)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"10\" />\n </button>\n }\n </span>\n }\n @if (remainingCount() > 0) {\n <span\n class=\"z-select-remaining text-muted-foreground bg-muted rounded-sm px-1.5 py-0.5 text-xs font-medium\">\n +{{ remainingCount() }}\n </span>\n }\n }\n } @else {\n @if (selectedOption()) {\n @if (effectiveSelectedTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"effectiveSelectedTemplate()!; context: { $implicit: selectedOption() }\" />\n } @else {\n <span\n class=\"truncate\"\n z-tooltip\n [zContent]=\"selectedOption()!.label\"\n [zTooltipDisabled]=\"uiState().isOpen\"\n zTooltipPosition=\"top\"\n [zTooltipHideDelay]=\"0\"\n [zTooltipOffset]=\"10\">\n {{ selectedOption()!.label }}\n </span>\n }\n } @else {\n <span class=\"text-muted-foreground min-w-0 flex-1 truncate whitespace-nowrap\">\n {{ effectivePlaceholder() }}\n </span>\n }\n }\n </div>\n\n @if (isLoading() || isLoadingMore()) {\n <z-icon zType=\"lucideLoaderCircle\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n @if (!isLoading() && zAllowClear() && hasValue() && !isDisabled() && !isReadonly()) {\n <button\n type=\"button\"\n class=\"text-muted-foreground hover:text-foreground flex shrink-0 items-center justify-center transition-colors\"\n (click)=\"clearAll($event)\"\n tabindex=\"-1\">\n <z-icon zType=\"lucideX\" zSize=\"18\" />\n </button>\n }\n\n @if (uiState().isValidating) {\n <z-icon zType=\"lucideLoader2\" zSize=\"18\" class=\"text-muted-foreground shrink-0 animate-spin\" />\n }\n\n <z-icon\n zType=\"lucideChevronDown\"\n zSize=\"18\"\n class=\"text-muted-foreground shrink-0 transition-transform duration-200\"\n [class.rotate-180]=\"uiState().isOpen\" />\n </div>\n\n @if (hasError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 pt-2 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n </div>\n\n <ng-template #dropdownTpl let-close=\"close\">\n <div\n [id]=\"dropdownId\"\n class=\"z-select-dropdown bg-popover border-border border shadow-[var(--z-popover-shadow)]\"\n [class.z-select-dropdown-bottom]=\"!isPositionTop()\"\n [class.z-select-dropdown-top]=\"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 [style.min-width.px]=\"dropdownWidth()\">\n @if (zShowSearch()) {\n <div class=\"border-border flex items-center border-b px-3\">\n <z-icon zType=\"lucideSearch\" zSize=\"18\" class=\"text-muted-foreground/50 mr-2 shrink-0\" />\n <input\n #dropdownSearchInput\n type=\"text\"\n class=\"placeholder:text-muted-foreground text-foreground flex h-10 w-full min-w-0 overflow-hidden bg-transparent py-3 text-sm text-ellipsis whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n [placeholder]=\"effectivePlaceholderSearch()\"\n [ngModel]=\"searchText()\"\n (ngModelChange)=\"onSearchChange($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n </div>\n }\n\n @if (isLoading()) {\n <div class=\"flex items-center justify-center\" [style.height.px]=\"optionsMaxHeight()\">\n <z-loading [zLoading]=\"true\" zSize=\"default\" />\n </div>\n } @else {\n @if (filteredOptions().length > 0) {\n @if (shouldUseVirtualScroll()) {\n <div\n #virtualScrollElement\n class=\"z-select-options z-select-virtual-scroll overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.height.px]=\"optionsMaxHeight()\">\n <div class=\"z-select-virtual-inner relative\" [style.height.px]=\"virtualizer.getTotalSize()\">\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let opt = filteredOptions()[virtualItem.index];\n <div\n #optionEl\n class=\"z-select-option absolute right-0 left-0 min-w-0\"\n [ngClass]=\"\n opt | zIsSelected: currentValue() : isMultipleMode() : zKey() | zOptionClasses: opt.disabled\n \"\n [style.height.px]=\"zOptionHeight()\"\n [style.transform]=\"'translateY(' + virtualItem.start + 'px)'\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: {\n $implicit: opt,\n selected: opt | zIsSelected: currentValue() : isMultipleMode() : zKey(),\n }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zHideDelay]=\"0\"\n [zOffset]=\"5\"\n [zArrow]=\"false\"\n [zTriggerElement]=\"optionEl\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode() : zKey()) {\n <z-icon zType=\"lucideCheck\" zSize=\"16\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n </div>\n @if (isLoadingMore()) {\n <div\n class=\"bg-popover/80 absolute right-0 bottom-0 left-0 flex items-center justify-center py-2\"\n [style.transform]=\"'translateY(' + virtualizer.getTotalSize() + 'px)'\">\n <z-loading zSize=\"xs\" [zLoading]=\"true\" />\n </div>\n }\n </div>\n } @else {\n <div\n #optionsContainer\n class=\"z-select-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.maxHeight.px]=\"optionsMaxHeight()\">\n @for (opt of filteredOptions(); track opt.value) {\n <div\n #optionEl2\n class=\"z-select-option relative min-w-0\"\n [ngClass]=\"\n opt | zIsSelected: currentValue() : isMultipleMode() : zKey() | zOptionClasses: opt.disabled\n \"\n [style.minHeight.px]=\"zOptionHeight()\"\n (click)=\"selectOption(opt, close)\">\n @if (effectiveOptionTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n effectiveOptionTemplate()!;\n context: {\n $implicit: opt,\n selected: opt | zIsSelected: currentValue() : isMultipleMode() : zKey(),\n }\n \" />\n } @else {\n <span\n class=\"min-w-0 flex-1 truncate\"\n z-tooltip\n [zContent]=\"opt.label\"\n zPosition=\"top\"\n [zArrow]=\"false\"\n [zOffset]=\"5\"\n [zHideDelay]=\"0\"\n [zTriggerElement]=\"optionEl2\"\n [innerHTML]=\"opt.label | zHighlight: searchText() | zSafeHtml\"></span>\n }\n @if (opt | zIsSelected: currentValue() : isMultipleMode() : zKey()) {\n <z-icon zType=\"lucideCheck\" zSize=\"18\" [zStrokeWidth]=\"4\" class=\"text-primary ml-auto shrink-0\" />\n }\n </div>\n }\n @if (canLoadMore()) {\n <div #loadMoreSentinel class=\"h-px w-full shrink-0\"></div>\n }\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center p-1\" [style.height.px]=\"optionsMaxHeight()\">\n @if (isEmptyData()) {\n <z-empty [zIcon]=\"zEmptyIcon()\" zSize=\"sm\" [zMessage]=\"effectiveEmptyText()\" />\n } @else {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"effectiveNotFoundText()\" />\n }\n </div>\n }\n\n @if (isLoadingMore()) {\n <div class=\"z-select-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\n @if (zShowAction() && (zActionTemplate() || isMultipleMode())) {\n <div class=\"border-border flex items-center gap-2 border-t px-2 py-1.5\">\n @if (zActionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zActionTemplate()!\" />\n } @else {\n <z-button\n zSize=\"xs\"\n [zType]=\"isAllSelected() ? 'ghost-error' : 'ghost-info'\"\n class=\"min-w-0 flex-1\"\n (click)=\"toggleSelectAllAction()\"\n [zWave]=\"false\">\n <z-icon [zType]=\"isAllSelected() ? 'lucideX' : 'lucideCheckCheck'\" zSize=\"18\" class=\"shrink-0\" />\n <span class=\"truncate\">{{ isAllSelected() ? effectiveClearAllText() : effectiveSelectAllText() }}</span>\n </z-button>\n }\n </div>\n }\n </div>\n </ng-template>\n</div>\n", styles: [".z-select-trigger{-webkit-user-select:none;user-select:none}.z-select-trigger:focus{outline:none}.z-select-trigger *{cursor:inherit}.z-select-tag{-webkit-user-select:none;user-select:none;animation:z-select-tag-enter .2s cubic-bezier(.4,0,.2,1)}@keyframes z-select-tag-enter{0%{opacity:0;transform:scale(.8) translateY(.25rem)}to{opacity:1;transform:scale(1) translateY(0)}}.z-select-remaining{animation:z-select-remaining-enter .25s cubic-bezier(.4,0,.2,1)}@keyframes z-select-remaining-enter{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.z-select-open-bottom{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.z-select-open-top{border-top-left-radius:0!important;border-top-right-radius:0!important}.z-select-dropdown{animation:z-select-dropdown-from-top .15s ease-out}.z-select-dropdown input{text-overflow:ellipsis;overflow:hidden}.z-select-dropdown-bottom{animation:z-select-dropdown-from-bottom .15s ease-out}@keyframes z-select-dropdown-from-top{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-select-dropdown-from-bottom{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}.z-select-options{overflow-x:hidden!important}.z-select-virtual-scroll .z-select-virtual-inner{width:100%}.z-select-loading-more{animation:z-select-loading-enter .2s ease-out}@keyframes z-select-loading-enter{0%{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
1338
1388
  }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], searchInputRef: [{ type: i0.ViewChild, args: ['dropdownSearchInput', { isSignal: true }] }], dropdownTpl: [{ type: i0.ViewChild, args: ['dropdownTpl', { isSignal: true }] }], optionsContainerRef: [{ type: i0.ViewChild, args: ['optionsContainer', { isSignal: true }] }], virtualScrollRef: [{ type: i0.ViewChild, args: ['virtualScrollElement', { isSignal: true }] }], loadMoreSentinelRef: [{ type: i0.ViewChild, args: ['loadMoreSentinel', { isSignal: true }] }], customSelectedDirective: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ZSelectSelectedDirective), { isSignal: true }] }], customOptionDirective: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ZSelectOptionDirective), { isSignal: true }] }], zOnSearch: [{ type: i0.Output, args: ["zOnSearch"] }], zOnLoadMore: [{ type: i0.Output, args: ["zOnLoadMore"] }], zOnBlur: [{ type: i0.Output, args: ["zOnBlur"] }], zOnFocus: [{ type: i0.Output, args: ["zOnFocus"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zEvent: [{ type: i0.Output, args: ["zEvent"] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMode", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", 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 }] }], zRequired: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRequired", 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 }] }], zPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPrefix", required: false }] }], zAllowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowClear", required: false }] }], zWrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "zWrap", required: false }] }], zShowSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowSearch", required: false }] }], zPlaceholderSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPlaceholderSearch", required: false }] }], zDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDebounce", required: false }] }], zNotFoundText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zNotFoundText", required: false }] }], zEmptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEmptyText", required: false }] }], zEmptyIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "zEmptyIcon", required: false }] }], zMaxTagCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMaxTagCount", required: false }] }], zDropdownMaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDropdownMaxHeight", required: false }] }], zOptionHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptionHeight", required: false }] }], zVirtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "zVirtualScroll", required: false }] }], zShowAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowAction", required: false }] }], zOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptions", required: false }] }], zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: false }] }], zTranslateLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTranslateLabels", required: false }] }], zKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "zKey", required: false }] }], zSearchServer: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSearchServer", 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 }] }], zMaxVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMaxVisible", required: false }] }], zScrollClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "zScrollClose", required: false }] }], zPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPosition", required: false }] }], zSelectedTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSelectedTemplate", required: false }] }], zOptionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptionTemplate", required: false }] }], zActionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zActionTemplate", required: false }] }], zAsyncValidators: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAsyncValidators", required: false }] }], zAsyncDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAsyncDebounce", required: false }] }], zAsyncValidateOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAsyncValidateOn", required: false }] }], zValidators: [{ type: i0.Input, args: [{ isSignal: true, alias: "zValidators", required: false }] }] } });
1339
1389
 
1340
1390
  /**