@shival99/z-ui 1.5.0 → 1.6.0

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.
Files changed (26) hide show
  1. package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs +533 -0
  2. package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs.map +1 -0
  3. package/fesm2022/shival99-z-ui-components-z-calendar.mjs +1 -1
  4. package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -1
  5. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs +1 -1
  6. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs.map +1 -1
  7. package/fesm2022/shival99-z-ui-components-z-filter.mjs +1 -1
  8. package/fesm2022/shival99-z-ui-components-z-filter.mjs.map +1 -1
  9. package/fesm2022/shival99-z-ui-components-z-menu.mjs +1 -1
  10. package/fesm2022/shival99-z-ui-components-z-menu.mjs.map +1 -1
  11. package/fesm2022/shival99-z-ui-components-z-popover.mjs +21 -3
  12. package/fesm2022/shival99-z-ui-components-z-popover.mjs.map +1 -1
  13. package/fesm2022/shival99-z-ui-components-z-select.mjs +1 -1
  14. package/fesm2022/shival99-z-ui-components-z-select.mjs.map +1 -1
  15. package/fesm2022/shival99-z-ui-components-z-table.mjs +32 -11
  16. package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
  17. package/fesm2022/shival99-z-ui-components-z-tabs.mjs +1 -1
  18. package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -1
  19. package/fesm2022/shival99-z-ui-i18n.mjs +6 -0
  20. package/fesm2022/shival99-z-ui-i18n.mjs.map +1 -1
  21. package/package.json +5 -1
  22. package/types/shival99-z-ui-components-z-autocomplete.d.ts +183 -0
  23. package/types/shival99-z-ui-components-z-calendar.d.ts +4 -4
  24. package/types/shival99-z-ui-components-z-popover.d.ts +4 -3
  25. package/types/shival99-z-ui-components-z-select.d.ts +1 -1
  26. package/types/shival99-z-ui-components-z-table.d.ts +9 -2
@@ -0,0 +1,533 @@
1
+ import { cva } from 'class-variance-authority';
2
+ import { NgClass, NgTemplateOutlet } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, Injector, DestroyRef, viewChild, viewChildren, input, output, signal, effect, computed, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
5
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { NgControl, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
7
+ import { injectVirtualizer } from '@shival99/angular-virtual';
8
+ import { ZEmptyComponent } from '@shival99/z-ui/components/z-empty';
9
+ import { ZIconComponent } from '@shival99/z-ui/components/z-icon';
10
+ import { ZLoadingComponent } from '@shival99/z-ui/components/z-loading';
11
+ import { ZPopoverDirective } from '@shival99/z-ui/components/z-popover';
12
+ import { ZTooltipDirective } from '@shival99/z-ui/components/z-tooltip';
13
+ import { ZHighlightPipe, ZSafeHtmlPipe } from '@shival99/z-ui/pipes';
14
+ import { zTransform, zUuid, zRemoveVietnamese, zMergeClasses } from '@shival99/z-ui/utils';
15
+ import { Subject, debounceTime, distinctUntilChanged } from 'rxjs';
16
+
17
+ const Z_AUTOCOMPLETE_DEFAULT_CONFIG = {
18
+ minLength: 1,
19
+ debounceTime: 0,
20
+ maxDisplayed: 50,
21
+ highlightMatch: true,
22
+ emptyMessage: 'Không tìm thấy kết quả',
23
+ noDataMessage: 'Chưa có dữ liệu',
24
+ closeOnSelect: true,
25
+ optionHeight: 36,
26
+ dropdownMaxHeight: 280,
27
+ };
28
+
29
+ const zAutocompleteInputVariants = cva([
30
+ 'flex w-full items-center rounded-[6px] border border-input bg-white shadow-xs',
31
+ 'transition-[border-color,box-shadow,background-color,color,opacity,border-radius] duration-200',
32
+ 'dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
33
+ 'outline-none',
34
+ 'text-sm',
35
+ ], {
36
+ variants: {
37
+ zSize: {
38
+ sm: 'h-8 px-2 gap-2 text-sm',
39
+ default: 'h-9 px-2.5 gap-2 text-sm',
40
+ lg: 'h-10 px-3 gap-2.5 text-sm',
41
+ },
42
+ zStatus: {
43
+ default: 'focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]',
44
+ open: 'border-ring',
45
+ error: 'border-destructive! ring-destructive/20 ring-[3px] focus-within:border-destructive! focus-within:ring-destructive/30',
46
+ disabled: 'opacity-50 cursor-not-allowed bg-muted! text-muted-foreground',
47
+ readonly: 'cursor-default bg-muted/50 text-muted-foreground',
48
+ },
49
+ },
50
+ defaultVariants: {
51
+ zSize: 'default',
52
+ zStatus: 'default',
53
+ },
54
+ });
55
+ const zAutocompleteOptionVariants = cva('flex items-center gap-2 px-2 py-1.5 cursor-pointer transition-colors text-sm rounded-[4px] outline-none', {
56
+ variants: {
57
+ active: {
58
+ true: 'bg-primary/15 text-primary',
59
+ false: 'hover:bg-primary/10 hover:text-foreground',
60
+ },
61
+ disabled: {
62
+ true: 'opacity-50 cursor-not-allowed pointer-events-none',
63
+ false: '',
64
+ },
65
+ },
66
+ defaultVariants: {
67
+ active: false,
68
+ disabled: false,
69
+ },
70
+ });
71
+
72
+ class ZAutocompleteComponent {
73
+ _injector = inject(Injector);
74
+ _destroyRef = inject(DestroyRef);
75
+ _query$ = new Subject();
76
+ triggerRef = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerRef" }] : []));
77
+ inputRef = viewChild('inputEl', ...(ngDevMode ? [{ debugName: "inputRef" }] : []));
78
+ dropdownTpl = viewChild('dropdownTpl', ...(ngDevMode ? [{ debugName: "dropdownTpl" }] : []));
79
+ virtualScrollRef = viewChild('virtualScrollElement', ...(ngDevMode ? [{ debugName: "virtualScrollRef" }] : []));
80
+ optionsContainerRef = viewChild('optionsContainer', ...(ngDevMode ? [{ debugName: "optionsContainerRef" }] : []));
81
+ virtualOptionElements = viewChildren('virtualOptionEl', ...(ngDevMode ? [{ debugName: "virtualOptionElements" }] : []));
82
+ class = input('', ...(ngDevMode ? [{ debugName: "class" }] : []));
83
+ zOptions = input([], ...(ngDevMode ? [{ debugName: "zOptions" }] : []));
84
+ zConfig = input({}, ...(ngDevMode ? [{ debugName: "zConfig" }] : []));
85
+ zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
86
+ zLabel = input('', ...(ngDevMode ? [{ debugName: "zLabel" }] : []));
87
+ zLabelClass = input('', ...(ngDevMode ? [{ debugName: "zLabelClass" }] : []));
88
+ zPlaceholder = input('', ...(ngDevMode ? [{ debugName: "zPlaceholder" }] : []));
89
+ zDisabled = input(false, { ...(ngDevMode ? { debugName: "zDisabled" } : {}), transform: zTransform });
90
+ zReadonly = input(false, { ...(ngDevMode ? { debugName: "zReadonly" } : {}), transform: zTransform });
91
+ zLoading = input(false, { ...(ngDevMode ? { debugName: "zLoading" } : {}), transform: zTransform });
92
+ zRequired = input(false, { ...(ngDevMode ? { debugName: "zRequired" } : {}), transform: zTransform });
93
+ zPrefix = input('', ...(ngDevMode ? [{ debugName: "zPrefix" }] : []));
94
+ zSuffix = input('', ...(ngDevMode ? [{ debugName: "zSuffix" }] : []));
95
+ zAllowClear = input(true, { ...(ngDevMode ? { debugName: "zAllowClear" } : {}), transform: zTransform });
96
+ zVirtualScroll = input(false, { ...(ngDevMode ? { debugName: "zVirtualScroll" } : {}), transform: zTransform });
97
+ zDynamicSize = input(true, { ...(ngDevMode ? { debugName: "zDynamicSize" } : {}), transform: zTransform });
98
+ zOptionHeight = input(36, ...(ngDevMode ? [{ debugName: "zOptionHeight" }] : []));
99
+ zHeightExpand = input(280, ...(ngDevMode ? [{ debugName: "zHeightExpand" }] : []));
100
+ zMaxVisible = input(null, ...(ngDevMode ? [{ debugName: "zMaxVisible" }] : []));
101
+ zResetOnSelect = input(true, { ...(ngDevMode ? { debugName: "zResetOnSelect" } : {}), transform: zTransform });
102
+ zEmptyText = input('', ...(ngDevMode ? [{ debugName: "zEmptyText" }] : []));
103
+ zEmptyIcon = input('lucideSearchX', ...(ngDevMode ? [{ debugName: "zEmptyIcon" }] : []));
104
+ zNoDataText = input('', ...(ngDevMode ? [{ debugName: "zNoDataText" }] : []));
105
+ zNoDataIcon = input('lucidePackageOpen', ...(ngDevMode ? [{ debugName: "zNoDataIcon" }] : []));
106
+ zAllowCustomValue = input(false, { ...(ngDevMode ? { debugName: "zAllowCustomValue" } : {}), transform: zTransform });
107
+ zDebounceTime = input(null, ...(ngDevMode ? [{ debugName: "zDebounceTime" }] : []));
108
+ zOptionTemplate = input(null, ...(ngDevMode ? [{ debugName: "zOptionTemplate" }] : []));
109
+ zOnSearch = output();
110
+ zOnSelect = output();
111
+ zOnEnter = output();
112
+ zValueChange = output();
113
+ zControl = output();
114
+ _value = signal('', ...(ngDevMode ? [{ debugName: "_value" }] : []));
115
+ _disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
116
+ _touched = signal(false, ...(ngDevMode ? [{ debugName: "_touched" }] : []));
117
+ _dirty = signal(false, ...(ngDevMode ? [{ debugName: "_dirty" }] : []));
118
+ _formControl = signal(null, ...(ngDevMode ? [{ debugName: "_formControl" }] : []));
119
+ _popoverControl = signal(null, ...(ngDevMode ? [{ debugName: "_popoverControl" }] : []));
120
+ _selectedOption = signal(null, ...(ngDevMode ? [{ debugName: "_selectedOption" }] : []));
121
+ uiState = signal({
122
+ isOpen: false,
123
+ isFocused: false,
124
+ }, ...(ngDevMode ? [{ debugName: "uiState" }] : []));
125
+ actualPosition = signal('bottom', ...(ngDevMode ? [{ debugName: "actualPosition" }] : []));
126
+ autocompleteId = zUuid('z-autocomplete');
127
+ dropdownId = `${this.autocompleteId}-dropdown`;
128
+ inputValue = signal('', ...(ngDevMode ? [{ debugName: "inputValue" }] : []));
129
+ activeIndex = signal(-1, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
130
+ dropdownWidth = signal(0, ...(ngDevMode ? [{ debugName: "dropdownWidth" }] : []));
131
+ virtualizer = injectVirtualizer(() => ({
132
+ scrollElement: this.virtualScrollRef(),
133
+ count: this.filteredOptions().length,
134
+ estimateSize: () => this.effectiveOptionHeight(),
135
+ measureElement: (element) => element.getBoundingClientRect().height,
136
+ overscan: 5,
137
+ }));
138
+ _measureVirtualItems = effect(() => {
139
+ if (!this.zDynamicSize()) {
140
+ return;
141
+ }
142
+ const elements = this.virtualOptionElements();
143
+ for (const el of elements) {
144
+ this.virtualizer.measureElement(el.nativeElement);
145
+ }
146
+ }, ...(ngDevMode ? [{ debugName: "_measureVirtualItems" }] : []));
147
+ config = computed(() => ({
148
+ ...Z_AUTOCOMPLETE_DEFAULT_CONFIG,
149
+ ...this.zConfig(),
150
+ }), ...(ngDevMode ? [{ debugName: "config" }] : []));
151
+ isDisabled = computed(() => this._disabled() || this.zDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
152
+ isReadonly = computed(() => this.zReadonly(), ...(ngDevMode ? [{ debugName: "isReadonly" }] : []));
153
+ isInteractionDisabled = computed(() => this.isDisabled() || this.isReadonly() || this.zLoading(), ...(ngDevMode ? [{ debugName: "isInteractionDisabled" }] : []));
154
+ effectiveOptionHeight = computed(() => this.zOptionHeight() || this.config().optionHeight, ...(ngDevMode ? [{ debugName: "effectiveOptionHeight" }] : []));
155
+ effectiveHeightExpand = computed(() => this.zHeightExpand() || this.config().dropdownMaxHeight, ...(ngDevMode ? [{ debugName: "effectiveHeightExpand" }] : []));
156
+ effectiveEmptyText = computed(() => this.zEmptyText() || this.config().emptyMessage, ...(ngDevMode ? [{ debugName: "effectiveEmptyText" }] : []));
157
+ effectiveNoDataText = computed(() => this.zNoDataText() || this.config().noDataMessage, ...(ngDevMode ? [{ debugName: "effectiveNoDataText" }] : []));
158
+ effectiveDebounceTime = computed(() => {
159
+ const inputValue = this.zDebounceTime();
160
+ return inputValue !== null ? inputValue : this.config().debounceTime;
161
+ }, ...(ngDevMode ? [{ debugName: "effectiveDebounceTime" }] : []));
162
+ isPositionTop = computed(() => {
163
+ const pos = this.actualPosition();
164
+ return pos.startsWith('top');
165
+ }, ...(ngDevMode ? [{ debugName: "isPositionTop" }] : []));
166
+ shouldUseVirtualScroll = computed(() => {
167
+ if (this.zVirtualScroll()) {
168
+ return true;
169
+ }
170
+ const maxVisible = this.zMaxVisible();
171
+ if (maxVisible !== null && this.zOptions().length > maxVisible) {
172
+ return true;
173
+ }
174
+ return this.zOptions().length > 50;
175
+ }, ...(ngDevMode ? [{ debugName: "shouldUseVirtualScroll" }] : []));
176
+ filteredOptions = computed(() => {
177
+ const options = this.zOptions();
178
+ const query = this.inputValue();
179
+ const cfg = this.config();
180
+ if (!query || query.trim() === '') {
181
+ if (cfg.maxDisplayed && options.length > cfg.maxDisplayed) {
182
+ return options.slice(0, cfg.maxDisplayed);
183
+ }
184
+ return options;
185
+ }
186
+ const normalizedQuery = zRemoveVietnamese(query.toLowerCase());
187
+ let filtered = options.filter(opt => {
188
+ const normalizedLabel = zRemoveVietnamese(opt.label.toLowerCase());
189
+ return normalizedLabel.includes(normalizedQuery);
190
+ });
191
+ if (cfg.maxDisplayed && filtered.length > cfg.maxDisplayed) {
192
+ filtered = filtered.slice(0, cfg.maxDisplayed);
193
+ }
194
+ return filtered;
195
+ }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
196
+ hasValue = computed(() => {
197
+ const value = this.inputValue();
198
+ return value !== null && value !== undefined && value.trim() !== '';
199
+ }, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
200
+ currentStatus = computed(() => {
201
+ if (this.isDisabled()) {
202
+ return 'disabled';
203
+ }
204
+ if (this.isReadonly()) {
205
+ return 'readonly';
206
+ }
207
+ if (this.uiState().isOpen) {
208
+ return 'open';
209
+ }
210
+ return 'default';
211
+ }, ...(ngDevMode ? [{ debugName: "currentStatus" }] : []));
212
+ inputClasses = computed(() => zMergeClasses(zAutocompleteInputVariants({
213
+ zSize: this.zSize(),
214
+ zStatus: this.currentStatus(),
215
+ }), this.class()), ...(ngDevMode ? [{ debugName: "inputClasses" }] : []));
216
+ state = computed(() => ({
217
+ focused: this.uiState().isFocused,
218
+ touched: this._touched(),
219
+ dirty: this._dirty(),
220
+ disabled: this.isDisabled(),
221
+ readonly: this.isReadonly(),
222
+ open: this.uiState().isOpen,
223
+ }), ...(ngDevMode ? [{ debugName: "state" }] : []));
224
+ _onChange = () => void 0;
225
+ _onTouched = () => void 0;
226
+ _ngControl = null;
227
+ constructor() {
228
+ effect(onCleanup => {
229
+ const triggerEl = this.triggerRef()?.nativeElement;
230
+ if (!triggerEl) {
231
+ return;
232
+ }
233
+ const observer = new ResizeObserver(() => {
234
+ this.dropdownWidth.set(triggerEl.getBoundingClientRect().width);
235
+ });
236
+ observer.observe(triggerEl);
237
+ this.dropdownWidth.set(triggerEl.getBoundingClientRect().width);
238
+ onCleanup(() => {
239
+ observer.disconnect();
240
+ });
241
+ });
242
+ effect(() => {
243
+ const options = this.filteredOptions();
244
+ const { isOpen } = this.uiState();
245
+ if (isOpen && options.length > 0) {
246
+ this.activeIndex.set(0);
247
+ }
248
+ });
249
+ effect(() => {
250
+ const idx = this.activeIndex();
251
+ const { isOpen } = this.uiState();
252
+ if (!isOpen || idx < 0) {
253
+ return;
254
+ }
255
+ if (!this.shouldUseVirtualScroll()) {
256
+ const container = this.optionsContainerRef()?.nativeElement;
257
+ if (!container) {
258
+ return;
259
+ }
260
+ const options = container.querySelectorAll('.z-autocomplete-option');
261
+ const activeOption = options[idx];
262
+ if (activeOption) {
263
+ activeOption.scrollIntoView({ block: 'nearest' });
264
+ }
265
+ }
266
+ });
267
+ }
268
+ ngOnInit() {
269
+ this._setupDebounce();
270
+ queueMicrotask(() => {
271
+ try {
272
+ this._ngControl = this._injector.get(NgControl, null);
273
+ if (this._ngControl?.control) {
274
+ this._formControl.set(this._ngControl.control);
275
+ }
276
+ }
277
+ catch {
278
+ this._ngControl = null;
279
+ }
280
+ });
281
+ setTimeout(() => this._emitControl());
282
+ }
283
+ writeValue(value) {
284
+ this._value.set(value ?? '');
285
+ this.inputValue.set(value ?? '');
286
+ }
287
+ registerOnChange(fn) {
288
+ this._onChange = fn;
289
+ }
290
+ registerOnTouched(fn) {
291
+ this._onTouched = fn;
292
+ }
293
+ setDisabledState(isDisabled) {
294
+ this._disabled.set(isDisabled);
295
+ }
296
+ onInput(event) {
297
+ const { value } = event.target;
298
+ this.inputValue.set(value);
299
+ this._value.set(value);
300
+ this._dirty.set(true);
301
+ this._onChange(value);
302
+ this._query$.next(value);
303
+ this.zValueChange.emit(value);
304
+ if (!this.uiState().isOpen) {
305
+ this._openPanel();
306
+ }
307
+ this._selectedOption.set(null);
308
+ }
309
+ onFocus() {
310
+ this.uiState.update(s => ({ ...s, isFocused: true }));
311
+ this._openPanel();
312
+ }
313
+ onInputClick() {
314
+ if (!this.uiState().isOpen) {
315
+ this._openPanel();
316
+ }
317
+ }
318
+ onBlur() {
319
+ this.uiState.update(s => ({ ...s, isFocused: false }));
320
+ this._touched.set(true);
321
+ this._onTouched();
322
+ }
323
+ onKeydown(event) {
324
+ if (this.isInteractionDisabled()) {
325
+ return;
326
+ }
327
+ const { isOpen } = this.uiState();
328
+ const options = this.filteredOptions();
329
+ const currentValue = this.inputValue();
330
+ if (event.key === 'Enter') {
331
+ event.preventDefault();
332
+ if (!isOpen) {
333
+ this._openPanel();
334
+ return;
335
+ }
336
+ this._handleEnterKey(options, currentValue);
337
+ return;
338
+ }
339
+ if (!isOpen) {
340
+ if (event.key === 'ArrowDown') {
341
+ event.preventDefault();
342
+ this._openPanel();
343
+ }
344
+ return;
345
+ }
346
+ switch (event.key) {
347
+ case 'ArrowDown':
348
+ event.preventDefault();
349
+ this.activeIndex.update(i => (i < options.length - 1 ? i + 1 : 0));
350
+ break;
351
+ case 'ArrowUp':
352
+ event.preventDefault();
353
+ this.activeIndex.update(i => (i > 0 ? i - 1 : options.length - 1));
354
+ break;
355
+ case 'Escape':
356
+ event.preventDefault();
357
+ this._closePanel();
358
+ break;
359
+ case 'Tab':
360
+ this._closePanel();
361
+ break;
362
+ }
363
+ }
364
+ _handleEnterKey(options, currentValue) {
365
+ const idx = this.activeIndex();
366
+ if (options.length > 0) {
367
+ const selectedIdx = idx >= 0 && idx < options.length ? idx : 0;
368
+ this.selectOption(options[selectedIdx]);
369
+ return;
370
+ }
371
+ if (this.zAllowCustomValue() && currentValue.trim()) {
372
+ this.zOnEnter.emit(currentValue.trim());
373
+ this._resetInput();
374
+ }
375
+ }
376
+ _resetInput() {
377
+ if (this.zResetOnSelect()) {
378
+ this.inputValue.set('');
379
+ this._value.set('');
380
+ this._onChange('');
381
+ this.zValueChange.emit('');
382
+ }
383
+ this._closePanel();
384
+ this.activeIndex.set(-1);
385
+ }
386
+ onPopoverControl(control) {
387
+ this._popoverControl.set(control);
388
+ }
389
+ onPopoverShow() {
390
+ this.uiState.update(s => ({ ...s, isOpen: true }));
391
+ setTimeout(() => {
392
+ this.inputRef()?.nativeElement.focus();
393
+ }, 50);
394
+ }
395
+ onPopoverHideStart() {
396
+ this.uiState.update(s => ({ ...s, isOpen: false }));
397
+ this.activeIndex.set(-1);
398
+ }
399
+ onPopoverHideEnd() {
400
+ this.actualPosition.set('bottom');
401
+ }
402
+ onPositionChange(position) {
403
+ this.actualPosition.set(position);
404
+ }
405
+ selectOption(option) {
406
+ if (option.disabled) {
407
+ return;
408
+ }
409
+ this._dirty.set(true);
410
+ this.zOnSelect.emit(option);
411
+ this._selectedOption.set(option);
412
+ const newValue = this.zResetOnSelect() ? '' : option.label;
413
+ this.inputValue.set(newValue);
414
+ this._value.set(newValue);
415
+ this._onChange(newValue);
416
+ this.zValueChange.emit(newValue);
417
+ if (this.config().closeOnSelect) {
418
+ this._closePanel();
419
+ }
420
+ this.activeIndex.set(-1);
421
+ }
422
+ clearInput(event) {
423
+ event.stopPropagation();
424
+ event.preventDefault();
425
+ this.inputValue.set('');
426
+ this._value.set('');
427
+ this._dirty.set(true);
428
+ this._onChange('');
429
+ this.zValueChange.emit('');
430
+ this._selectedOption.set(null);
431
+ this._closePanel();
432
+ setTimeout(() => {
433
+ this.inputRef()?.nativeElement.focus();
434
+ });
435
+ }
436
+ getOptionClasses(option, index) {
437
+ return zAutocompleteOptionVariants({
438
+ active: this.activeIndex() === index,
439
+ disabled: option.disabled ?? false,
440
+ });
441
+ }
442
+ trackByValue = (_index, option) => option.value;
443
+ focus() {
444
+ this.inputRef()?.nativeElement.focus();
445
+ }
446
+ blur() {
447
+ this.inputRef()?.nativeElement.blur();
448
+ }
449
+ clear() {
450
+ this.inputValue.set('');
451
+ this._value.set('');
452
+ this._onChange('');
453
+ this.zValueChange.emit('');
454
+ this._selectedOption.set(null);
455
+ this._closePanel();
456
+ }
457
+ reset() {
458
+ this.clear();
459
+ this._touched.set(false);
460
+ this._dirty.set(false);
461
+ }
462
+ open() {
463
+ this._openPanel();
464
+ }
465
+ close() {
466
+ this._closePanel();
467
+ }
468
+ _openPanel() {
469
+ if (this.isInteractionDisabled()) {
470
+ return;
471
+ }
472
+ this._popoverControl()?.show();
473
+ }
474
+ _closePanel() {
475
+ this._popoverControl()?.close();
476
+ }
477
+ _setupDebounce() {
478
+ this._query$
479
+ .pipe(debounceTime(this.effectiveDebounceTime()), distinctUntilChanged(), takeUntilDestroyed(this._destroyRef))
480
+ .subscribe(query => {
481
+ this.zOnSearch.emit(query);
482
+ });
483
+ }
484
+ _emitControl() {
485
+ this.zControl.emit({
486
+ focus: () => this.focus(),
487
+ blur: () => this.blur(),
488
+ clear: () => this.clear(),
489
+ reset: () => this.reset(),
490
+ open: () => this.open(),
491
+ close: () => this.close(),
492
+ value: this._value.asReadonly(),
493
+ selectedOption: this._selectedOption.asReadonly(),
494
+ state: this.state,
495
+ });
496
+ }
497
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZAutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
498
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ZAutocompleteComponent, isStandalone: true, selector: "z-autocomplete", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zOptions: { classPropertyName: "zOptions", publicName: "zOptions", isSignal: true, isRequired: false, transformFunction: null }, zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zLabel: { classPropertyName: "zLabel", publicName: "zLabel", isSignal: true, isRequired: false, transformFunction: null }, zLabelClass: { classPropertyName: "zLabelClass", publicName: "zLabelClass", isSignal: true, isRequired: false, transformFunction: null }, zPlaceholder: { classPropertyName: "zPlaceholder", publicName: "zPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, zDisabled: { classPropertyName: "zDisabled", publicName: "zDisabled", isSignal: true, isRequired: false, transformFunction: null }, zReadonly: { classPropertyName: "zReadonly", publicName: "zReadonly", isSignal: true, isRequired: false, transformFunction: null }, zLoading: { classPropertyName: "zLoading", publicName: "zLoading", isSignal: true, isRequired: false, transformFunction: null }, zRequired: { classPropertyName: "zRequired", publicName: "zRequired", isSignal: true, isRequired: false, transformFunction: null }, zPrefix: { classPropertyName: "zPrefix", publicName: "zPrefix", isSignal: true, isRequired: false, transformFunction: null }, zSuffix: { classPropertyName: "zSuffix", publicName: "zSuffix", isSignal: true, isRequired: false, transformFunction: null }, zAllowClear: { classPropertyName: "zAllowClear", publicName: "zAllowClear", isSignal: true, isRequired: false, transformFunction: null }, zVirtualScroll: { classPropertyName: "zVirtualScroll", publicName: "zVirtualScroll", isSignal: true, isRequired: false, transformFunction: null }, zDynamicSize: { classPropertyName: "zDynamicSize", publicName: "zDynamicSize", isSignal: true, isRequired: false, transformFunction: null }, zOptionHeight: { classPropertyName: "zOptionHeight", publicName: "zOptionHeight", isSignal: true, isRequired: false, transformFunction: null }, zHeightExpand: { classPropertyName: "zHeightExpand", publicName: "zHeightExpand", isSignal: true, isRequired: false, transformFunction: null }, zMaxVisible: { classPropertyName: "zMaxVisible", publicName: "zMaxVisible", isSignal: true, isRequired: false, transformFunction: null }, zResetOnSelect: { classPropertyName: "zResetOnSelect", publicName: "zResetOnSelect", isSignal: true, isRequired: false, transformFunction: null }, zEmptyText: { classPropertyName: "zEmptyText", publicName: "zEmptyText", isSignal: true, isRequired: false, transformFunction: null }, zEmptyIcon: { classPropertyName: "zEmptyIcon", publicName: "zEmptyIcon", isSignal: true, isRequired: false, transformFunction: null }, zNoDataText: { classPropertyName: "zNoDataText", publicName: "zNoDataText", isSignal: true, isRequired: false, transformFunction: null }, zNoDataIcon: { classPropertyName: "zNoDataIcon", publicName: "zNoDataIcon", isSignal: true, isRequired: false, transformFunction: null }, zAllowCustomValue: { classPropertyName: "zAllowCustomValue", publicName: "zAllowCustomValue", isSignal: true, isRequired: false, transformFunction: null }, zDebounceTime: { classPropertyName: "zDebounceTime", publicName: "zDebounceTime", isSignal: true, isRequired: false, transformFunction: null }, zOptionTemplate: { classPropertyName: "zOptionTemplate", publicName: "zOptionTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zOnSearch: "zOnSearch", zOnSelect: "zOnSelect", zOnEnter: "zOnEnter", zValueChange: "zValueChange", zControl: "zControl" }, providers: [
499
+ {
500
+ provide: NG_VALUE_ACCESSOR,
501
+ useExisting: forwardRef(() => ZAutocompleteComponent),
502
+ multi: true,
503
+ },
504
+ ], 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: "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()\"\n (blur)=\"onBlur()\"\n (click)=\"onInputClick()\"\n (keydown)=\"onKeydown($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n\n @if (zLoading()) {\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=\"14\" 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.rounded-b-[6px]]=\"!isPositionTop()\"\n [class.rounded-t-[6px]]=\"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()) {\n <div class=\"flex flex-col items-center justify-center\" [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 class=\"flex flex-col items-center justify-center p-1\" [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-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 [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 (zOptionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zOptionTemplate()!; 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: inputValue() | 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-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.maxHeight.px]=\"effectiveHeightExpand()\">\n @for (opt of filteredOptions(); track opt.value; let i = $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 [style.minHeight.px]=\"effectiveOptionHeight()\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(i)\"\n (click)=\"selectOption(opt)\">\n @if (zOptionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zOptionTemplate()!; 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: inputValue() | 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 }\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-enter .15s ease-out;contain:layout style;will-change:transform,opacity}@keyframes z-autocomplete-dropdown-enter{0%{opacity:0;transform:translateY(-4px)}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-option mark{background:transparent;color:hsl(var(--primary));font-weight:600}.z-autocomplete-option{transition:background-color .1s ease,color .1s ease}\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 });
505
+ }
506
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZAutocompleteComponent, decorators: [{
507
+ type: Component,
508
+ args: [{ selector: 'z-autocomplete', imports: [
509
+ FormsModule,
510
+ NgClass,
511
+ NgTemplateOutlet,
512
+ ZIconComponent,
513
+ ZLoadingComponent,
514
+ ZPopoverDirective,
515
+ ZTooltipDirective,
516
+ ZEmptyComponent,
517
+ ZHighlightPipe,
518
+ ZSafeHtmlPipe,
519
+ ], standalone: true, providers: [
520
+ {
521
+ provide: NG_VALUE_ACCESSOR,
522
+ useExisting: forwardRef(() => ZAutocompleteComponent),
523
+ multi: true,
524
+ },
525
+ ], 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()\"\n (blur)=\"onBlur()\"\n (click)=\"onInputClick()\"\n (keydown)=\"onKeydown($event)\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\" />\n\n @if (zLoading()) {\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=\"14\" 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.rounded-b-[6px]]=\"!isPositionTop()\"\n [class.rounded-t-[6px]]=\"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()) {\n <div class=\"flex flex-col items-center justify-center\" [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 class=\"flex flex-col items-center justify-center p-1\" [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-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 [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 (zOptionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zOptionTemplate()!; 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: inputValue() | 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-options flex flex-col gap-0.75 overflow-x-hidden overflow-y-auto overscroll-y-contain p-1\"\n [style.maxHeight.px]=\"effectiveHeightExpand()\">\n @for (opt of filteredOptions(); track opt.value; let i = $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 [style.minHeight.px]=\"effectiveOptionHeight()\"\n [attr.aria-selected]=\"isActive\"\n role=\"option\"\n (mouseenter)=\"activeIndex.set(i)\"\n (click)=\"selectOption(opt)\">\n @if (zOptionTemplate()) {\n <ng-container *ngTemplateOutlet=\"zOptionTemplate()!; 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: inputValue() | 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 }\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-enter .15s ease-out;contain:layout style;will-change:transform,opacity}@keyframes z-autocomplete-dropdown-enter{0%{opacity:0;transform:translateY(-4px)}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-option mark{background:transparent;color:hsl(var(--primary));font-weight:600}.z-autocomplete-option{transition:background-color .1s ease,color .1s ease}\n"] }]
526
+ }], 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 }] }], virtualOptionElements: [{ type: i0.ViewChildren, args: ['virtualOptionEl', { 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 }] }], 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 }] }], zOptionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zOptionTemplate", required: false }] }], zOnSearch: [{ type: i0.Output, args: ["zOnSearch"] }], zOnSelect: [{ type: i0.Output, args: ["zOnSelect"] }], zOnEnter: [{ type: i0.Output, args: ["zOnEnter"] }], zValueChange: [{ type: i0.Output, args: ["zValueChange"] }], zControl: [{ type: i0.Output, args: ["zControl"] }] } });
527
+
528
+ /**
529
+ * Generated bundle index. Do not edit.
530
+ */
531
+
532
+ export { ZAutocompleteComponent, Z_AUTOCOMPLETE_DEFAULT_CONFIG, zAutocompleteInputVariants, zAutocompleteOptionVariants };
533
+ //# sourceMappingURL=shival99-z-ui-components-z-autocomplete.mjs.map