@yoozsoft/yoozsoft-ng 5.3.5 → 7.1.1

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 (113) hide show
  1. package/README.md +143 -24
  2. package/assets/js/UTIF.js-master/LICENSE +21 -21
  3. package/assets/js/UTIF.js-master/README.md +72 -72
  4. package/assets/js/UTIF.js-master/UTIF.js +1762 -1762
  5. package/assets/js/UTIF.js-master/package-lock.json +13 -13
  6. package/assets/js/UTIF.js-master/package.json +24 -0
  7. package/assets/styles/components/_ys-navbar.scss +22 -0
  8. package/assets/styles/components/_ys-pagination.scss +10 -0
  9. package/assets/styles/{ys-layout.scss → utilities/ys-layout.scss} +1 -1
  10. package/assets/styles/ys-styles.scss +2 -0
  11. package/autocomplete/package.json +4 -0
  12. package/date/package.json +4 -0
  13. package/datepicker/package.json +4 -0
  14. package/dropdown/package.json +4 -0
  15. package/fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs +257 -197
  16. package/fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs.map +1 -1
  17. package/fesm2022/yoozsoft-yoozsoft-ng-date.mjs +562 -0
  18. package/fesm2022/yoozsoft-yoozsoft-ng-date.mjs.map +1 -0
  19. package/fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs +600 -837
  20. package/fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs.map +1 -1
  21. package/fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs +161 -151
  22. package/fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs.map +1 -1
  23. package/fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs +93 -103
  24. package/fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs.map +1 -1
  25. package/fesm2022/yoozsoft-yoozsoft-ng-footer.mjs +16 -21
  26. package/fesm2022/yoozsoft-yoozsoft-ng-footer.mjs.map +1 -1
  27. package/fesm2022/yoozsoft-yoozsoft-ng-loading.mjs +20 -24
  28. package/fesm2022/yoozsoft-yoozsoft-ng-loading.mjs.map +1 -1
  29. package/fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs +60 -76
  30. package/fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs.map +1 -1
  31. package/fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs +11 -15
  32. package/fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs.map +1 -1
  33. package/fesm2022/yoozsoft-yoozsoft-ng-pagination.mjs +61 -55
  34. package/fesm2022/yoozsoft-yoozsoft-ng-pagination.mjs.map +1 -1
  35. package/fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs +142 -130
  36. package/fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs.map +1 -1
  37. package/fesm2022/yoozsoft-yoozsoft-ng-pipes.mjs +44 -0
  38. package/fesm2022/yoozsoft-yoozsoft-ng-pipes.mjs.map +1 -0
  39. package/fesm2022/yoozsoft-yoozsoft-ng-progress.mjs +51 -34
  40. package/fesm2022/yoozsoft-yoozsoft-ng-progress.mjs.map +1 -1
  41. package/fesm2022/yoozsoft-yoozsoft-ng-rating.mjs +155 -0
  42. package/fesm2022/yoozsoft-yoozsoft-ng-rating.mjs.map +1 -0
  43. package/fesm2022/yoozsoft-yoozsoft-ng-select.mjs +78 -80
  44. package/fesm2022/yoozsoft-yoozsoft-ng-select.mjs.map +1 -1
  45. package/fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs +99 -99
  46. package/fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs.map +1 -1
  47. package/fesm2022/yoozsoft-yoozsoft-ng-table.mjs +316 -0
  48. package/fesm2022/yoozsoft-yoozsoft-ng-table.mjs.map +1 -0
  49. package/fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs +128 -114
  50. package/fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs.map +1 -1
  51. package/fesm2022/yoozsoft-yoozsoft-ng-toast.mjs +112 -62
  52. package/fesm2022/yoozsoft-yoozsoft-ng-toast.mjs.map +1 -1
  53. package/fesm2022/yoozsoft-yoozsoft-ng-validators.mjs +37 -0
  54. package/fesm2022/yoozsoft-yoozsoft-ng-validators.mjs.map +1 -0
  55. package/fesm2022/yoozsoft-yoozsoft-ng.mjs.map +1 -1
  56. package/file-upload/package.json +4 -0
  57. package/footer/package.json +4 -0
  58. package/loading/package.json +4 -0
  59. package/navbar/package.json +4 -0
  60. package/overlay/package.json +4 -0
  61. package/package.json +61 -38
  62. package/pagination/package.json +4 -0
  63. package/password-strength/package.json +4 -0
  64. package/pipes/package.json +4 -0
  65. package/progress/package.json +4 -0
  66. package/rating/package.json +4 -0
  67. package/select/package.json +4 -0
  68. package/sidebar/package.json +4 -0
  69. package/table/package.json +4 -0
  70. package/tiff-viewer/package.json +4 -0
  71. package/toast/package.json +4 -0
  72. package/types/yoozsoft-yoozsoft-ng-autocomplete.d.ts +79 -0
  73. package/types/yoozsoft-yoozsoft-ng-date.d.ts +118 -0
  74. package/types/yoozsoft-yoozsoft-ng-datepicker.d.ts +120 -0
  75. package/types/yoozsoft-yoozsoft-ng-dropdown.d.ts +76 -0
  76. package/types/yoozsoft-yoozsoft-ng-file-upload.d.ts +75 -0
  77. package/types/yoozsoft-yoozsoft-ng-footer.d.ts +26 -0
  78. package/types/yoozsoft-yoozsoft-ng-loading.d.ts +14 -0
  79. package/types/yoozsoft-yoozsoft-ng-navbar.d.ts +60 -0
  80. package/types/yoozsoft-yoozsoft-ng-overlay.d.ts +10 -0
  81. package/types/yoozsoft-yoozsoft-ng-pagination.d.ts +31 -0
  82. package/types/yoozsoft-yoozsoft-ng-password-strength.d.ts +73 -0
  83. package/types/yoozsoft-yoozsoft-ng-pipes.d.ts +11 -0
  84. package/types/yoozsoft-yoozsoft-ng-progress.d.ts +31 -0
  85. package/types/yoozsoft-yoozsoft-ng-rating.d.ts +56 -0
  86. package/types/yoozsoft-yoozsoft-ng-select.d.ts +43 -0
  87. package/types/yoozsoft-yoozsoft-ng-sidebar.d.ts +69 -0
  88. package/types/yoozsoft-yoozsoft-ng-table.d.ts +137 -0
  89. package/types/yoozsoft-yoozsoft-ng-tiff-viewer.d.ts +53 -0
  90. package/types/yoozsoft-yoozsoft-ng-toast.d.ts +66 -0
  91. package/types/yoozsoft-yoozsoft-ng-validators.d.ts +5 -0
  92. package/validators/package.json +4 -0
  93. package/autocomplete/index.d.ts +0 -71
  94. package/datepicker/index.d.ts +0 -291
  95. package/directives/index.d.ts +0 -17
  96. package/dropdown/index.d.ts +0 -62
  97. package/fesm2022/yoozsoft-yoozsoft-ng-directives.mjs +0 -57
  98. package/fesm2022/yoozsoft-yoozsoft-ng-directives.mjs.map +0 -1
  99. package/file-upload/index.d.ts +0 -72
  100. package/footer/index.d.ts +0 -25
  101. package/loading/index.d.ts +0 -13
  102. package/navbar/index.d.ts +0 -56
  103. package/overlay/index.d.ts +0 -11
  104. package/pagination/index.d.ts +0 -29
  105. package/password-strength/index.d.ts +0 -84
  106. package/progress/index.d.ts +0 -28
  107. package/select/index.d.ts +0 -39
  108. package/sidebar/index.d.ts +0 -94
  109. package/tiff-viewer/index.d.ts +0 -52
  110. package/toast/index.d.ts +0 -53
  111. /package/assets/styles/{ys-preloader-9.scss → preloaders/ys-preloader-9.scss} +0 -0
  112. /package/assets/styles/{ys-preloader.scss → preloaders/ys-preloader.scss} +0 -0
  113. /package/{index.d.ts → types/yoozsoft-yoozsoft-ng.d.ts} +0 -0
@@ -1,276 +1,336 @@
1
- import * as i2 from '@angular/cdk/scrolling';
1
+ import * as i1 from '@angular/cdk/scrolling';
2
2
  import { ScrollingModule } from '@angular/cdk/scrolling';
3
- import { NgTemplateOutlet, NgClass } from '@angular/common';
3
+ import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
4
4
  import * as i0 from '@angular/core';
5
- import { EventEmitter, TemplateRef, forwardRef, HostListener, ViewChild, Output, Input, ContentChild, Component } from '@angular/core';
6
- import * as i1 from '@angular/forms';
5
+ import { input, output, signal, computed, viewChild, inject, DestroyRef, ElementRef, PLATFORM_ID, TemplateRef, forwardRef, ContentChild, ChangeDetectionStrategy, Component } from '@angular/core';
6
+ import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
7
7
  import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
8
- import { Subject, debounceTime, distinctUntilChanged, switchMap, catchError, of } from 'rxjs';
8
+ import { fromEvent, debounceTime, distinctUntilChanged, switchMap, of, catchError, finalize } from 'rxjs';
9
9
 
10
- class YsAutocompleteComponent {
11
- elRef;
12
- searchTerm = '';
13
- filteredOptions = [];
14
- selectedOptions = [];
15
- showDropdown = false;
16
- activeIndex = -1;
17
- error = null;
18
- /** Array or async function */
19
- options;
20
- /** Label display field */
21
- optionLabel = 'label';
22
- /** placeholder */
23
- placeholder = '';
24
- /** Multiple choice mode */
25
- multiple = false;
26
- /** Button to clear selection */
27
- showClear = false;
28
- disabled = false;
10
+ class YsAutocomplete {
11
+ /********************* Inputs */
12
+ options = input([], /* @ts-ignore */
13
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
14
+ loading = input(false, /* @ts-ignore */
15
+ ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
16
+ loadingMessage = input('Loading...', /* @ts-ignore */
17
+ ...(ngDevMode ? [{ debugName: "loadingMessage" }] : /* istanbul ignore next */ []));
18
+ noResultMessage = input('No results found.', /* @ts-ignore */
19
+ ...(ngDevMode ? [{ debugName: "noResultMessage" }] : /* istanbul ignore next */ []));
20
+ optionLabel = input('label', /* @ts-ignore */
21
+ ...(ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []));
22
+ placeholder = input('', /* @ts-ignore */
23
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
24
+ multiple = input(false, /* @ts-ignore */
25
+ ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
26
+ showClear = input(false, /* @ts-ignore */
27
+ ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
28
+ disabled = input(false, /* @ts-ignore */
29
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
30
+ styleClass = input(/* @ts-ignore */
31
+ ...(ngDevMode ? [undefined, { debugName: "styleClass" }] : /* istanbul ignore next */ []));
32
+ selectionStyleClass = input('text-bg-light', /* @ts-ignore */
33
+ ...(ngDevMode ? [{ debugName: "selectionStyleClass" }] : /* istanbul ignore next */ []));
34
+ clearIconClass = input('fa fa-times', /* @ts-ignore */
35
+ ...(ngDevMode ? [{ debugName: "clearIconClass" }] : /* istanbul ignore next */ []));
36
+ searchIconClass = input('fa fa-search', /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "searchIconClass" }] : /* istanbul ignore next */ []));
38
+ loadingIconClass = input('fa fa-spinner fa-spin', /* @ts-ignore */
39
+ ...(ngDevMode ? [{ debugName: "loadingIconClass" }] : /* istanbul ignore next */ []));
40
+ multipleCheckIconClass = input('fa fa-check', /* @ts-ignore */
41
+ ...(ngDevMode ? [{ debugName: "multipleCheckIconClass" }] : /* istanbul ignore next */ []));
42
+ infiniteScroll = input(false, /* @ts-ignore */
43
+ ...(ngDevMode ? [{ debugName: "infiniteScroll" }] : /* istanbul ignore next */ []));
44
+ virtualScroll = input(true, /* @ts-ignore */
45
+ ...(ngDevMode ? [{ debugName: "virtualScroll" }] : /* istanbul ignore next */ []));
46
+ virtualScrollItemSize = input(36, /* @ts-ignore */
47
+ ...(ngDevMode ? [{ debugName: "virtualScrollItemSize" }] : /* istanbul ignore next */ []));
48
+ virtualScrollThreshold = input(100, /* @ts-ignore */
49
+ ...(ngDevMode ? [{ debugName: "virtualScrollThreshold" }] : /* istanbul ignore next */ []));
50
+ trackBy = input(/* @ts-ignore */
51
+ ...(ngDevMode ? [undefined, { debugName: "trackBy" }] : /* istanbul ignore next */ []));
52
+ compareWith = input(/* @ts-ignore */
53
+ ...(ngDevMode ? [undefined, { debugName: "compareWith" }] : /* istanbul ignore next */ []));
54
+ /********************* Outputs */
55
+ /** Event to request more items */
56
+ loadMore = output();
57
+ /** Return selected options */
58
+ selectionChange = output();
59
+ /********************* Signals */
60
+ searchTerm = signal('', /* @ts-ignore */
61
+ ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
62
+ filteredOptions = signal([], /* @ts-ignore */
63
+ ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
64
+ selectedOptions = signal([], /* @ts-ignore */
65
+ ...(ngDevMode ? [{ debugName: "selectedOptions" }] : /* istanbul ignore next */ []));
66
+ showDropdown = signal(false, /* @ts-ignore */
67
+ ...(ngDevMode ? [{ debugName: "showDropdown" }] : /* istanbul ignore next */ []));
68
+ activeIndex = signal(-1, /* @ts-ignore */
69
+ ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
70
+ error = signal(null, /* @ts-ignore */
71
+ ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
72
+ internalLoading = signal(false, /* @ts-ignore */
73
+ ...(ngDevMode ? [{ debugName: "internalLoading" }] : /* istanbul ignore next */ []));
74
+ isLoading = computed(() => this.loading() || this.internalLoading(), /* @ts-ignore */
75
+ ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
76
+ disabledState = signal(false, /* @ts-ignore */
77
+ ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
78
+ isDisabled = computed(() => this.disabled() || this.disabledState(), /* @ts-ignore */
79
+ ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
80
+ static nextId = 0;
81
+ componentId = `ys-autocomplete-${YsAutocomplete.nextId++}`;
82
+ activeOptionId = computed(() => {
83
+ const index = this.activeIndex();
84
+ return index >= 0
85
+ ? `${this.componentId}-option-${index}`
86
+ : null;
87
+ }, /* @ts-ignore */
88
+ ...(ngDevMode ? [{ debugName: "activeOptionId" }] : /* istanbul ignore next */ []));
89
+ /********************* ViewChild */
90
+ inputRef = viewChild('inputRef', /* @ts-ignore */
91
+ ...(ngDevMode ? [{ debugName: "inputRef" }] : /* istanbul ignore next */ []));
92
+ /********************* Inject */
93
+ destroyRef = inject(DestroyRef);
94
+ host = inject((ElementRef));
95
+ platformId = inject(PLATFORM_ID);
96
+ isBrowser = isPlatformBrowser(this.platformId);
29
97
  /** Custom template */
30
98
  itemTemplate;
31
- styleClass;
32
- /** Badge style class on Multiple choice mode */
33
- badgeStyleClass = 'text-bg-light';
34
- loading = false;
35
- loadingMessage = 'Loading...';
36
- /** No results found message */
37
- noResultMessage = 'No results found.';
38
- /** Infinite scroll feature enabled */
39
- infiniteScroll = false;
40
- virtualScroll = true;
41
- virtualScrollItemSize = 36;
42
- // [virtualScrollOptions]="options"
43
- /** Event to request more items */
44
- loadMore = new EventEmitter();
45
- /** Output selection */
46
- selected = new EventEmitter();
47
- /** Output selection after removed item */
48
- removed = new EventEmitter();
49
- search$ = new Subject();
50
- _onChange = () => { };
51
- _onTouched = () => { };
52
- inputRef;
53
- get isArrayItems() { return Array.isArray(this.options); }
54
- get isFunctionItems() { return typeof this.options === 'function'; }
55
- constructor(elRef) {
56
- this.elRef = elRef;
57
- }
58
- ngOnInit() {
59
- if (Array.isArray(this.options)) {
60
- this.filteredOptions = this.options;
61
- }
62
- /** Only in async function mode */
63
- if (typeof this.options === 'function') {
64
- const fetchFn = this.options;
65
- this.search$
66
- .pipe(debounceTime(300), distinctUntilChanged(), switchMap((term) => {
67
- this.loading = true;
68
- this.error = null;
69
- return fetchFn(term).pipe(catchError((err) => {
70
- this.error = 'Error receiving data!';
71
- console.error(err);
72
- return of([]);
73
- }));
74
- }))
75
- .subscribe((results) => {
76
- this.filteredOptions = results;
77
- this.loading = false;
78
- this.showDropdown = true;
99
+ onChange = (_) => { };
100
+ onTouched = () => { };
101
+ constructor() {
102
+ if (this.isBrowser) {
103
+ fromEvent(document, 'click')
104
+ .pipe(takeUntilDestroyed(this.destroyRef))
105
+ .subscribe(event => {
106
+ const target = event.target;
107
+ if (!this.host.nativeElement.contains(target)) {
108
+ this.showDropdown.set(false);
109
+ }
79
110
  });
80
111
  }
112
+ toObservable(this.searchTerm)
113
+ .pipe(debounceTime(300), distinctUntilChanged(), switchMap(term => {
114
+ const source = this.options();
115
+ if (Array.isArray(source)) {
116
+ const lower = term.toLowerCase();
117
+ return of(source.filter(item => this
118
+ .getLabel(item)
119
+ .toLowerCase()
120
+ .includes(lower)));
121
+ }
122
+ this.internalLoading.set(true);
123
+ this.error.set(null);
124
+ return source(term).pipe(catchError(error => {
125
+ console.error(error);
126
+ this.error.set('Error receiving data!');
127
+ return of([]);
128
+ }), finalize(() => {
129
+ this.internalLoading.set(false);
130
+ }));
131
+ }), takeUntilDestroyed(this.destroyRef))
132
+ .subscribe(result => {
133
+ this.filteredOptions.set(result);
134
+ // this.showDropdown.set(
135
+ // result.length > 0
136
+ // );
137
+ });
81
138
  }
82
- /** For the initial value of FormControl */
83
139
  writeValue(value) {
84
- if (this.multiple) {
85
- this.selectedOptions = value ? [...value] : [];
86
- }
87
- else {
88
- this.searchTerm = value ? this.getLabel(value) : '';
140
+ if (this.multiple()) {
141
+ this.selectedOptions.set(Array.isArray(value)
142
+ ? [...value]
143
+ : []);
144
+ return;
89
145
  }
146
+ this.searchTerm.set(value
147
+ ? this.getLabel(value)
148
+ : '');
90
149
  }
91
150
  registerOnChange(fn) {
92
- this._onChange = fn;
151
+ this.onChange = fn;
93
152
  }
94
153
  registerOnTouched(fn) {
95
- this._onTouched = fn;
154
+ this.onTouched = fn;
96
155
  }
97
156
  setDisabledState(isDisabled) {
98
- this.disabled = isDisabled;
99
- if (this.inputRef) {
100
- this.inputRef.nativeElement.disabled = isDisabled;
101
- }
157
+ this.disabledState.set(isDisabled);
102
158
  }
103
- onSearchChange() {
104
- const term = this.searchTerm.trim();
105
- if (Array.isArray(this.options)) {
159
+ onInput(event) {
160
+ const value = event.target.value;
161
+ this.onSearchChange(value);
162
+ }
163
+ onSearchChange(term) {
164
+ this.searchTerm.set(term.trim());
165
+ if (Array.isArray(this.options())) {
106
166
  const lower = term.toLowerCase();
107
- this.filteredOptions = this.options.filter((item) => this.getLabel(item).toLowerCase().includes(lower));
108
- this.showDropdown = this.filteredOptions.length >= 0;
109
- }
110
- else if (typeof this.options === 'function') {
111
- this.search$.next(term);
167
+ this.filteredOptions.set(this.options().filter(item => this.getLabel(item).toLowerCase().includes(lower)));
168
+ this.showDropdown.set(true);
112
169
  }
113
170
  if (!this.multiple && !term) {
114
171
  this.clearSelection();
115
172
  }
116
173
  }
117
174
  getLabel(item) {
118
- if (!item)
175
+ if (item === null || item === undefined) {
119
176
  return '';
120
- if (typeof item === 'string')
121
- return item;
122
- if (item && this.optionLabel && item[this.optionLabel]) {
123
- return item[this.optionLabel];
124
177
  }
125
- return '';
178
+ if (typeof item === 'string' || typeof item === 'number') {
179
+ return String(item);
180
+ }
181
+ const key = this.optionLabel();
182
+ const value = item?.[key];
183
+ return value != null
184
+ ? String(value)
185
+ : '';
186
+ }
187
+ isEqual(a, b) {
188
+ const comparer = this.compareWith();
189
+ if (comparer) {
190
+ return comparer(a, b);
191
+ }
192
+ return this.getLabel(a) === this.getLabel(b);
126
193
  }
127
194
  onSelect(item) {
128
- if (this.multiple) {
129
- const exists = this.selectedOptions.some((x) => this.getLabel(x) === this.getLabel(item));
130
- if (!exists) {
131
- this.selectedOptions.push(item);
132
- this._onChange(this.selectedOptions);
133
- this._onTouched();
134
- this.selected.emit(this.selectedOptions);
135
- }
136
- this.searchTerm = '';
137
- this.showDropdown = true;
138
- this.onSearchChange();
195
+ if (this.multiple()) {
196
+ this.selectedOptions.update(list => list.some(x => this.isEqual(x, item))
197
+ ? list.filter(x => !this.isEqual(x, item)) // ✅ حذف
198
+ : [...list, item] // ✅ اضافه
199
+ );
200
+ const value = this.selectedOptions();
201
+ this.onChange(value);
202
+ this.onTouched();
203
+ this.selectionChange.emit(value);
204
+ this.searchTerm.set('');
205
+ this.showDropdown.set(true);
206
+ this.onSearchChange(this.searchTerm());
139
207
  }
140
208
  else {
141
- this.searchTerm = this.getLabel(item);
142
- this._onChange(item);
143
- this._onTouched();
144
- this.selected.emit(item);
145
- this.showDropdown = false;
209
+ this.searchTerm.set(this.getLabel(item));
210
+ this.onChange(item);
211
+ this.onTouched();
212
+ this.selectionChange.emit(item);
213
+ this.showDropdown.set(false);
146
214
  }
147
- this.activeIndex = -1;
215
+ this.activeIndex.set(-1);
216
+ this.inputRef()?.nativeElement.focus();
148
217
  }
149
218
  removeItem(item) {
150
- this.selectedOptions = this.selectedOptions.filter((x) => this.getLabel(x) !== this.getLabel(item));
151
- this._onChange(this.selectedOptions);
152
- this.removed.emit(this.selectedOptions);
219
+ const prev = this.selectedOptions();
220
+ this.selectedOptions.update(list => list.filter(x => !this.isEqual(x, item)));
221
+ if (prev !== this.selectedOptions()) {
222
+ const value = this.selectedOptions();
223
+ this.onChange(value);
224
+ this.selectionChange.emit(value);
225
+ }
153
226
  }
154
227
  onScroll(event) {
155
- if (!this.infiniteScroll || this.loading)
228
+ if (!this.infiniteScroll || this.isLoading())
156
229
  return;
157
230
  const target = event.target;
158
231
  const nearBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 10;
159
232
  if (nearBottom) {
160
233
  // Request more items
161
- this.loadMore.emit(this.searchTerm);
234
+ this.loadMore.emit(this.searchTerm());
162
235
  }
163
236
  }
164
237
  clearSelection() {
165
- if (this.multiple) {
166
- this.selectedOptions = [];
167
- this._onChange(this.selectedOptions);
168
- this.removed.emit(this.selectedOptions);
238
+ if (this.multiple()) {
239
+ this.selectedOptions.set([]);
240
+ const value = this.selectedOptions();
241
+ this.onChange(value);
242
+ this.selectionChange.emit(value);
169
243
  }
170
244
  else {
171
- this.searchTerm = '';
172
- this._onChange(null);
173
- this.selected.emit(null);
245
+ this.searchTerm.set('');
246
+ this.onChange(null);
247
+ this.selectionChange.emit(null);
174
248
  }
175
- this.showDropdown = false;
249
+ // this.showDropdown.set(false);
176
250
  }
177
- /** Keyboard control */
178
251
  handleKeyboard(event) {
179
- if (!this.showDropdown || this.filteredOptions.length === 0)
252
+ const list = this.filteredOptions();
253
+ if (list.length === 0) {
180
254
  return;
255
+ }
256
+ if (!this.showDropdown()) {
257
+ this.showDropdown.set(true);
258
+ }
181
259
  switch (event.key) {
182
260
  case 'ArrowDown':
183
- this.activeIndex = (this.activeIndex + 1) % this.filteredOptions.length;
261
+ // برو به آیتم بعدی
262
+ this.activeIndex.update(i => (i + 1) % list.length);
184
263
  event.preventDefault();
185
264
  break;
186
265
  case 'ArrowUp':
187
- this.activeIndex =
188
- (this.activeIndex - 1 + this.filteredOptions.length) %
189
- this.filteredOptions.length;
266
+ // برو به آیتم قبلی
267
+ this.activeIndex.update(i => (i - 1 + list.length) % list.length);
190
268
  event.preventDefault();
191
269
  break;
192
270
  case 'Enter':
193
- if (this.activeIndex >= 0) {
194
- this.onSelect(this.filteredOptions[this.activeIndex]);
195
- event.preventDefault();
271
+ const index = this.activeIndex();
272
+ if (index >= 0 && index < list.length) {
273
+ this.onSelect(list[index]);
196
274
  }
275
+ event.preventDefault();
197
276
  break;
198
277
  case 'Escape':
199
- this.showDropdown = false;
278
+ this.showDropdown.set(false);
279
+ break;
280
+ case 'Home':
281
+ this.activeIndex.set(0);
282
+ event.preventDefault();
283
+ break;
284
+ case 'End':
285
+ this.activeIndex.set(list.length - 1);
286
+ event.preventDefault();
287
+ break;
288
+ case 'Tab':
289
+ this.showDropdown.set(false);
290
+ break;
291
+ case 'PageUp':
292
+ this.activeIndex.update(i => Math.max(0, i - 10));
293
+ event.preventDefault();
294
+ break;
295
+ case 'PageDown':
296
+ this.activeIndex.update(i => Math.min(list.length - 1, i + 10));
297
+ event.preventDefault();
200
298
  break;
201
299
  }
202
300
  }
203
- /** Close by clicking outside */
204
- onClickOutside(event) {
205
- const clickedInside = this.elRef.nativeElement.contains(event.target);
206
- if (!clickedInside) {
207
- this.showDropdown = false;
208
- }
301
+ isSelected(item) {
302
+ return this.selectedOptions()
303
+ .some(x => this.isEqual(x, item));
304
+ }
305
+ trackItem(item) {
306
+ return this.trackBy()?.(item)
307
+ ?? this.getLabel(item);
209
308
  }
210
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsAutocompleteComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
211
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.5", type: YsAutocompleteComponent, isStandalone: true, selector: "ys-autocomplete", inputs: { options: "options", optionLabel: "optionLabel", placeholder: "placeholder", multiple: "multiple", showClear: "showClear", disabled: "disabled", styleClass: "styleClass", badgeStyleClass: "badgeStyleClass", loading: "loading", loadingMessage: "loadingMessage", noResultMessage: "noResultMessage", infiniteScroll: "infiniteScroll", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize" }, outputs: { loadMore: "loadMore", selected: "selected", removed: "removed" }, host: { listeners: { "keydown": "handleKeyboard($event)", "document:click": "onClickOutside($event)" } }, providers: [
309
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: YsAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component });
310
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: YsAutocomplete, isStandalone: true, selector: "ys-autocomplete", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingMessage: { classPropertyName: "loadingMessage", publicName: "loadingMessage", isSignal: true, isRequired: false, transformFunction: null }, noResultMessage: { classPropertyName: "noResultMessage", publicName: "noResultMessage", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, selectionStyleClass: { classPropertyName: "selectionStyleClass", publicName: "selectionStyleClass", isSignal: true, isRequired: false, transformFunction: null }, clearIconClass: { classPropertyName: "clearIconClass", publicName: "clearIconClass", isSignal: true, isRequired: false, transformFunction: null }, searchIconClass: { classPropertyName: "searchIconClass", publicName: "searchIconClass", isSignal: true, isRequired: false, transformFunction: null }, loadingIconClass: { classPropertyName: "loadingIconClass", publicName: "loadingIconClass", isSignal: true, isRequired: false, transformFunction: null }, multipleCheckIconClass: { classPropertyName: "multipleCheckIconClass", publicName: "multipleCheckIconClass", isSignal: true, isRequired: false, transformFunction: null }, infiniteScroll: { classPropertyName: "infiniteScroll", publicName: "infiniteScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollThreshold: { classPropertyName: "virtualScrollThreshold", publicName: "virtualScrollThreshold", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadMore: "loadMore", selectionChange: "selectionChange" }, providers: [
212
311
  {
213
312
  provide: NG_VALUE_ACCESSOR,
214
- useExisting: forwardRef(() => YsAutocompleteComponent),
313
+ useExisting: forwardRef(() => YsAutocomplete),
215
314
  multi: true,
216
315
  },
217
- ], queries: [{ propertyName: "itemTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true }], ngImport: i0, template: "<div class=\"ys-autocomplete position-relative\">\r\n <div class=\"input-group flex-wrap\">\r\n @if (multiple && selectedOptions.length > 0) {\r\n <div class=\"d-flex flex-wrap\">\r\n @for (item of selectedOptions; track item) {\r\n <span class=\"badge me-1 mb-1 p-2 d-flex align-items-center\" [ngClass]=\"badgeStyleClass\">\r\n {{ getLabel(item) }}\r\n <i class=\"fa fa-times ms-2 cursor-pointer\" (click)=\"removeItem(item)\"></i>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"input-group w-100\">\r\n <input #inputRef type=\"text\" class=\"form-control\" [placeholder]=\"placeholder\" [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearchChange()\" (focus)=\"showDropdown = true\" [ngClass]=\"styleClass\" />\r\n\r\n @if (showClear) {\r\n @if ((multiple && selectedOptions.length > 0) || (!multiple && searchTerm)) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n }\r\n <span class=\"input-group-text\" (click)=\"showDropdown = !showDropdown\">\r\n <i class=\"fa fa-search\"></i>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (showDropdown) {\r\n <div class=\"dropdown-container position-absolute w-100 shadow-sm bg-white border rounded\">\r\n @if (loading) {\r\n <div class=\"list-group-item text-center\">\r\n <i class=\"fa fa-spinner fa-spin me-2\"></i>{{ loadingMessage }}\r\n </div>\r\n }\r\n @else if (error) {\r\n <div class=\"list-group-item text-danger text-center\">{{ error }}</div>\r\n }\r\n @else if (filteredOptions.length === 0) {\r\n <div class=\"list-group-item text-muted text-center\">\r\n {{ noResultMessage }}\r\n </div>\r\n }\r\n <!-- \u2705 \u062D\u0627\u0644\u062A Virtual Scroll \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u0628\u0632\u0631\u06AF -->\r\n @else if (virtualScroll && filteredOptions.length > 100) {\r\n <cdk-virtual-scroll-viewport [itemSize]=\"virtualScrollItemSize\" class=\"list-group w-100 overflow-y-auto\">\r\n <ul class=\"list-group w-100\">\r\n @for (item of filteredOptions; track item; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex\"\r\n (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n {{ getLabel(item) }}\r\n }\r\n </li>\r\n }\r\n </ul>\r\n </cdk-virtual-scroll-viewport>\r\n }\r\n <!-- \u2705 \u062D\u0627\u0644\u062A \u0645\u0639\u0645\u0648\u0644\u06CC \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9 -->\r\n @else {\r\n <ul class=\"list-group w-100 overflow-y-auto\" [class.scrollable]=\"infiniteScroll\" (scroll)=\"onScroll($event)\">\r\n @for (item of filteredOptions; track item; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex\"\r\n (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n {{ getLabel(item) }}\r\n }\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </div>\r\n }\r\n\r\n</div>", styles: [".ys-autocomplete .dropdown-container,.ys-autocomplete .list-group{z-index:1000;max-height:200px}.ys-autocomplete cdk-virtual-scroll-viewport{height:200px;display:block}.ys-autocomplete .btn-clear:hover{background-color:var(--bs-btn-hover-bg)}.ys-autocomplete .badge{font-size:.9rem;cursor:default;font-weight:var(--bs-body-font-weight)}.ys-autocomplete .badge i{cursor:pointer;font-size:.8rem}.ys-autocomplete .badge:hover{font-weight:var(--bs-badge-font-weight)}\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: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "component", type: i2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
316
+ ], queries: [{ propertyName: "itemTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ys-autocomplete position-relative\">\n <div class=\"input-group flex-wrap\">\n @if (multiple() && selectedOptions().length > 0) {\n <div class=\"d-flex flex-wrap\">\n @for (item of selectedOptions(); track trackItem(item)) {\n <span class=\"badge me-1 mb-1 p-2 d-flex align-items-center\" [class]=\"selectionStyleClass()\">\n {{ getLabel(item) }}\n <i class=\"ms-2 cursor-pointer\" [class]=\"clearIconClass()\" (click)=\"removeItem(item)\"></i>\n </span>\n }\n </div>\n }\n\n <div class=\"input-group w-100\">\n <input #inputRef type=\"text\" class=\"form-control\" [class]=\"styleClass()\" [placeholder]=\"placeholder()\"\n [value]=\"searchTerm()\" (input)=\"onInput($event)\" (keydown)=\"handleKeyboard($event)\"\n (focus)=\"showDropdown.set(true)\" (click)=\"showDropdown.set(true)\" role=\"combobox\"\n aria-autocomplete=\"list\" [attr.aria-expanded]=\"showDropdown()\" aria-haspopup=\"listbox\"\n [attr.aria-activedescendant]=\"activeOptionId()\" [disabled]=\"isDisabled()\" />\n\n @if (showClear()) {\n @if ((multiple() && selectedOptions().length > 0) || (!multiple() && searchTerm())) {\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\n [disabled]=\"isDisabled()\">\n <span [class]=\"clearIconClass()\"></span>\n </button>\n }\n }\n <span class=\"input-group-text\" (click)=\"showDropdown.set( !showDropdown())\">\n <i [class]=\"searchIconClass()\"></i>\n </span>\n </div>\n </div>\n\n @if (showDropdown()) {\n <div class=\"dropdown-container position-absolute w-100 shadow-sm bg-white border rounded\">\n @if (isLoading()) {\n <div class=\"list-group-item text-center\">\n <i class=\"me-2\" [class]=\"loadingIconClass()\"></i>{{ loadingMessage() }}\n </div>\n }\n @else if (error()) {\n <div class=\"list-group-item text-danger text-center\">{{ error() }}</div>\n }\n @else if (filteredOptions().length === 0) {\n <div class=\"list-group-item text-muted text-center\">\n {{ noResultMessage() }}\n </div>\n }\n <!-- \u2705 \u062D\u0627\u0644\u062A Virtual Scroll \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u0628\u0632\u0631\u06AF -->\n @else if (virtualScroll() && filteredOptions().length > virtualScrollThreshold()) {\n <cdk-virtual-scroll-viewport [itemSize]=\"virtualScrollItemSize()\" class=\"list-group w-100\">\n\n <div [id]=\"componentId + '-option-' + i\" *cdkVirtualFor=\"let item of filteredOptions(); let i = index\"\n class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\n\n @if (itemTemplate) {\n\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: item}\"> </ng-container>\n\n } @else {\n\n @if(multiple()){\n <i class=\"me-1 text-success\" [class]=\"multipleCheckIconClass()\" [class.invisible]=\"!isSelected(item)\">\n </i>\n }\n\n {{ getLabel(item) }}\n\n }\n\n </div>\n\n </cdk-virtual-scroll-viewport>\n\n }\n <!-- \u2705 \u062D\u0627\u0644\u062A \u0645\u0639\u0645\u0648\u0644\u06CC \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9 -->\n @else {\n <ul class=\"list-group w-100 overflow-y-auto\" [class.scrollable]=\"infiniteScroll()\" (scroll)=\"onScroll($event)\"\n role=\"listbox\">\n @for (item of filteredOptions(); track trackItem(item); let i = $index) {\n <li [id]=\"componentId + '-option-' + i\" class=\"list-group-item list-group-item-action\"\n [class.active]=\"i === activeIndex()\" [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\"\n role=\"option\" [attr.aria-selected]=\"isSelected(item)\">\n @if (itemTemplate) {\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\n } @else {\n @if(multiple()){\n <i class=\"me-1 text-success\" [class]=\"multipleCheckIconClass()\" [class.invisible]=\"!isSelected(item)\">\n </i>\n }\n {{ getLabel(item) }}\n }\n </li>\n }\n </ul>\n }\n </div>\n\n }\n\n</div>", styles: [".ys-autocomplete .dropdown-container,.ys-autocomplete .list-group{z-index:1000;max-height:200px}.ys-autocomplete cdk-virtual-scroll-viewport{height:200px;display:block}.ys-autocomplete .list-group-item-action{font-size:13px;font-weight:500;line-height:22px;text-transform:uppercase}.ys-autocomplete .list-group-item-action.selected{color:var(--bs-list-group-action-hover-color);background-color:var(--bs-list-group-action-hover-bg)}.ys-autocomplete .btn-clear:hover{background-color:var(--bs-btn-hover-bg)}.ys-autocomplete .badge{font-size:.9rem;cursor:default;font-weight:var(--bs-body-font-weight)}.ys-autocomplete .badge i{cursor:pointer;font-size:.8rem}.ys-autocomplete .badge:hover{font-weight:var(--bs-badge-font-weight)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
218
317
  }
219
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsAutocompleteComponent, decorators: [{
318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: YsAutocomplete, decorators: [{
220
319
  type: Component,
221
- args: [{ selector: 'ys-autocomplete', imports: [FormsModule, NgTemplateOutlet, NgClass, ScrollingModule], providers: [
320
+ args: [{ selector: 'ys-autocomplete', imports: [
321
+ FormsModule,
322
+ NgTemplateOutlet,
323
+ ScrollingModule
324
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
222
325
  {
223
326
  provide: NG_VALUE_ACCESSOR,
224
- useExisting: forwardRef(() => YsAutocompleteComponent),
327
+ useExisting: forwardRef(() => YsAutocomplete),
225
328
  multi: true,
226
329
  },
227
- ], template: "<div class=\"ys-autocomplete position-relative\">\r\n <div class=\"input-group flex-wrap\">\r\n @if (multiple && selectedOptions.length > 0) {\r\n <div class=\"d-flex flex-wrap\">\r\n @for (item of selectedOptions; track item) {\r\n <span class=\"badge me-1 mb-1 p-2 d-flex align-items-center\" [ngClass]=\"badgeStyleClass\">\r\n {{ getLabel(item) }}\r\n <i class=\"fa fa-times ms-2 cursor-pointer\" (click)=\"removeItem(item)\"></i>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"input-group w-100\">\r\n <input #inputRef type=\"text\" class=\"form-control\" [placeholder]=\"placeholder\" [(ngModel)]=\"searchTerm\"\r\n (input)=\"onSearchChange()\" (focus)=\"showDropdown = true\" [ngClass]=\"styleClass\" />\r\n\r\n @if (showClear) {\r\n @if ((multiple && selectedOptions.length > 0) || (!multiple && searchTerm)) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n }\r\n <span class=\"input-group-text\" (click)=\"showDropdown = !showDropdown\">\r\n <i class=\"fa fa-search\"></i>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (showDropdown) {\r\n <div class=\"dropdown-container position-absolute w-100 shadow-sm bg-white border rounded\">\r\n @if (loading) {\r\n <div class=\"list-group-item text-center\">\r\n <i class=\"fa fa-spinner fa-spin me-2\"></i>{{ loadingMessage }}\r\n </div>\r\n }\r\n @else if (error) {\r\n <div class=\"list-group-item text-danger text-center\">{{ error }}</div>\r\n }\r\n @else if (filteredOptions.length === 0) {\r\n <div class=\"list-group-item text-muted text-center\">\r\n {{ noResultMessage }}\r\n </div>\r\n }\r\n <!-- \u2705 \u062D\u0627\u0644\u062A Virtual Scroll \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u0628\u0632\u0631\u06AF -->\r\n @else if (virtualScroll && filteredOptions.length > 100) {\r\n <cdk-virtual-scroll-viewport [itemSize]=\"virtualScrollItemSize\" class=\"list-group w-100 overflow-y-auto\">\r\n <ul class=\"list-group w-100\">\r\n @for (item of filteredOptions; track item; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex\"\r\n (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n {{ getLabel(item) }}\r\n }\r\n </li>\r\n }\r\n </ul>\r\n </cdk-virtual-scroll-viewport>\r\n }\r\n <!-- \u2705 \u062D\u0627\u0644\u062A \u0645\u0639\u0645\u0648\u0644\u06CC \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9 -->\r\n @else {\r\n <ul class=\"list-group w-100 overflow-y-auto\" [class.scrollable]=\"infiniteScroll\" (scroll)=\"onScroll($event)\">\r\n @for (item of filteredOptions; track item; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex\"\r\n (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n {{ getLabel(item) }}\r\n }\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </div>\r\n }\r\n\r\n</div>", styles: [".ys-autocomplete .dropdown-container,.ys-autocomplete .list-group{z-index:1000;max-height:200px}.ys-autocomplete cdk-virtual-scroll-viewport{height:200px;display:block}.ys-autocomplete .btn-clear:hover{background-color:var(--bs-btn-hover-bg)}.ys-autocomplete .badge{font-size:.9rem;cursor:default;font-weight:var(--bs-body-font-weight)}.ys-autocomplete .badge i{cursor:pointer;font-size:.8rem}.ys-autocomplete .badge:hover{font-weight:var(--bs-badge-font-weight)}\n"] }]
228
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { options: [{
229
- type: Input
230
- }], optionLabel: [{
231
- type: Input
232
- }], placeholder: [{
233
- type: Input
234
- }], multiple: [{
235
- type: Input
236
- }], showClear: [{
237
- type: Input
238
- }], disabled: [{
239
- type: Input
240
- }], itemTemplate: [{
330
+ ], template: "<div class=\"ys-autocomplete position-relative\">\n <div class=\"input-group flex-wrap\">\n @if (multiple() && selectedOptions().length > 0) {\n <div class=\"d-flex flex-wrap\">\n @for (item of selectedOptions(); track trackItem(item)) {\n <span class=\"badge me-1 mb-1 p-2 d-flex align-items-center\" [class]=\"selectionStyleClass()\">\n {{ getLabel(item) }}\n <i class=\"ms-2 cursor-pointer\" [class]=\"clearIconClass()\" (click)=\"removeItem(item)\"></i>\n </span>\n }\n </div>\n }\n\n <div class=\"input-group w-100\">\n <input #inputRef type=\"text\" class=\"form-control\" [class]=\"styleClass()\" [placeholder]=\"placeholder()\"\n [value]=\"searchTerm()\" (input)=\"onInput($event)\" (keydown)=\"handleKeyboard($event)\"\n (focus)=\"showDropdown.set(true)\" (click)=\"showDropdown.set(true)\" role=\"combobox\"\n aria-autocomplete=\"list\" [attr.aria-expanded]=\"showDropdown()\" aria-haspopup=\"listbox\"\n [attr.aria-activedescendant]=\"activeOptionId()\" [disabled]=\"isDisabled()\" />\n\n @if (showClear()) {\n @if ((multiple() && selectedOptions().length > 0) || (!multiple() && searchTerm())) {\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\n [disabled]=\"isDisabled()\">\n <span [class]=\"clearIconClass()\"></span>\n </button>\n }\n }\n <span class=\"input-group-text\" (click)=\"showDropdown.set( !showDropdown())\">\n <i [class]=\"searchIconClass()\"></i>\n </span>\n </div>\n </div>\n\n @if (showDropdown()) {\n <div class=\"dropdown-container position-absolute w-100 shadow-sm bg-white border rounded\">\n @if (isLoading()) {\n <div class=\"list-group-item text-center\">\n <i class=\"me-2\" [class]=\"loadingIconClass()\"></i>{{ loadingMessage() }}\n </div>\n }\n @else if (error()) {\n <div class=\"list-group-item text-danger text-center\">{{ error() }}</div>\n }\n @else if (filteredOptions().length === 0) {\n <div class=\"list-group-item text-muted text-center\">\n {{ noResultMessage() }}\n </div>\n }\n <!-- \u2705 \u062D\u0627\u0644\u062A Virtual Scroll \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u0628\u0632\u0631\u06AF -->\n @else if (virtualScroll() && filteredOptions().length > virtualScrollThreshold()) {\n <cdk-virtual-scroll-viewport [itemSize]=\"virtualScrollItemSize()\" class=\"list-group w-100\">\n\n <div [id]=\"componentId + '-option-' + i\" *cdkVirtualFor=\"let item of filteredOptions(); let i = index\"\n class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\n\n @if (itemTemplate) {\n\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: item}\"> </ng-container>\n\n } @else {\n\n @if(multiple()){\n <i class=\"me-1 text-success\" [class]=\"multipleCheckIconClass()\" [class.invisible]=\"!isSelected(item)\">\n </i>\n }\n\n {{ getLabel(item) }}\n\n }\n\n </div>\n\n </cdk-virtual-scroll-viewport>\n\n }\n <!-- \u2705 \u062D\u0627\u0644\u062A \u0645\u0639\u0645\u0648\u0644\u06CC \u0628\u0631\u0627\u06CC \u0644\u06CC\u0633\u062A\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9 -->\n @else {\n <ul class=\"list-group w-100 overflow-y-auto\" [class.scrollable]=\"infiniteScroll()\" (scroll)=\"onScroll($event)\"\n role=\"listbox\">\n @for (item of filteredOptions(); track trackItem(item); let i = $index) {\n <li [id]=\"componentId + '-option-' + i\" class=\"list-group-item list-group-item-action\"\n [class.active]=\"i === activeIndex()\" [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\"\n role=\"option\" [attr.aria-selected]=\"isSelected(item)\">\n @if (itemTemplate) {\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\n } @else {\n @if(multiple()){\n <i class=\"me-1 text-success\" [class]=\"multipleCheckIconClass()\" [class.invisible]=\"!isSelected(item)\">\n </i>\n }\n {{ getLabel(item) }}\n }\n </li>\n }\n </ul>\n }\n </div>\n\n }\n\n</div>", styles: [".ys-autocomplete .dropdown-container,.ys-autocomplete .list-group{z-index:1000;max-height:200px}.ys-autocomplete cdk-virtual-scroll-viewport{height:200px;display:block}.ys-autocomplete .list-group-item-action{font-size:13px;font-weight:500;line-height:22px;text-transform:uppercase}.ys-autocomplete .list-group-item-action.selected{color:var(--bs-list-group-action-hover-color);background-color:var(--bs-list-group-action-hover-bg)}.ys-autocomplete .btn-clear:hover{background-color:var(--bs-btn-hover-bg)}.ys-autocomplete .badge{font-size:.9rem;cursor:default;font-weight:var(--bs-body-font-weight)}.ys-autocomplete .badge i{cursor:pointer;font-size:.8rem}.ys-autocomplete .badge:hover{font-weight:var(--bs-badge-font-weight)}\n"] }]
331
+ }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingMessage", required: false }] }], noResultMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultMessage", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], selectionStyleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionStyleClass", required: false }] }], clearIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearIconClass", required: false }] }], searchIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchIconClass", required: false }] }], loadingIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingIconClass", required: false }] }], multipleCheckIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "multipleCheckIconClass", required: false }] }], infiniteScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "infiniteScroll", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollItemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollItemSize", required: false }] }], virtualScrollThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollThreshold", required: false }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], inputRef: [{ type: i0.ViewChild, args: ['inputRef', { isSignal: true }] }], itemTemplate: [{
241
332
  type: ContentChild,
242
333
  args: [TemplateRef]
243
- }], styleClass: [{
244
- type: Input
245
- }], badgeStyleClass: [{
246
- type: Input
247
- }], loading: [{
248
- type: Input
249
- }], loadingMessage: [{
250
- type: Input
251
- }], noResultMessage: [{
252
- type: Input
253
- }], infiniteScroll: [{
254
- type: Input
255
- }], virtualScroll: [{
256
- type: Input
257
- }], virtualScrollItemSize: [{
258
- type: Input
259
- }], loadMore: [{
260
- type: Output
261
- }], selected: [{
262
- type: Output
263
- }], removed: [{
264
- type: Output
265
- }], inputRef: [{
266
- type: ViewChild,
267
- args: ['inputRef']
268
- }], handleKeyboard: [{
269
- type: HostListener,
270
- args: ['keydown', ['$event']]
271
- }], onClickOutside: [{
272
- type: HostListener,
273
- args: ['document:click', ['$event']]
274
334
  }] } });
275
335
 
276
336
  /*
@@ -281,5 +341,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
281
341
  * Generated bundle index. Do not edit.
282
342
  */
283
343
 
284
- export { YsAutocompleteComponent };
344
+ export { YsAutocomplete };
285
345
  //# sourceMappingURL=yoozsoft-yoozsoft-ng-autocomplete.mjs.map