@yoozsoft/yoozsoft-ng 5.3.5 → 6.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs +144 -114
- package/fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs +31 -31
- package/fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-directives.mjs +3 -3
- package/fesm2022/yoozsoft-yoozsoft-ng-directives.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs +113 -94
- package/fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs +8 -5
- package/fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-footer.mjs +3 -3
- package/fesm2022/yoozsoft-yoozsoft-ng-footer.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-loading.mjs +3 -3
- package/fesm2022/yoozsoft-yoozsoft-ng-loading.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs +4 -4
- package/fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs +3 -3
- package/fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-pagination.mjs +3 -3
- package/fesm2022/yoozsoft-yoozsoft-ng-pagination.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs +6 -6
- package/fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-progress.mjs +22 -18
- package/fesm2022/yoozsoft-yoozsoft-ng-progress.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-select.mjs +8 -5
- package/fesm2022/yoozsoft-yoozsoft-ng-select.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs +6 -6
- package/fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-table.mjs +316 -0
- package/fesm2022/yoozsoft-yoozsoft-ng-table.mjs.map +1 -0
- package/fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs +106 -99
- package/fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs.map +1 -1
- package/fesm2022/yoozsoft-yoozsoft-ng-toast.mjs +100 -52
- package/fesm2022/yoozsoft-yoozsoft-ng-toast.mjs.map +1 -1
- package/package.json +39 -35
- package/types/yoozsoft-yoozsoft-ng-autocomplete.d.ts +74 -0
- package/types/yoozsoft-yoozsoft-ng-dropdown.d.ts +74 -0
- package/{file-upload/index.d.ts → types/yoozsoft-yoozsoft-ng-file-upload.d.ts} +2 -1
- package/{navbar/index.d.ts → types/yoozsoft-yoozsoft-ng-navbar.d.ts} +1 -0
- package/{progress/index.d.ts → types/yoozsoft-yoozsoft-ng-progress.d.ts} +9 -9
- package/{select/index.d.ts → types/yoozsoft-yoozsoft-ng-select.d.ts} +2 -1
- package/types/yoozsoft-yoozsoft-ng-table.d.ts +124 -0
- package/types/yoozsoft-yoozsoft-ng-tiff-viewer.d.ts +48 -0
- package/types/yoozsoft-yoozsoft-ng-toast.d.ts +63 -0
- package/autocomplete/index.d.ts +0 -71
- package/dropdown/index.d.ts +0 -62
- package/tiff-viewer/index.d.ts +0 -52
- package/toast/index.d.ts +0 -53
- /package/{datepicker/index.d.ts → types/yoozsoft-yoozsoft-ng-datepicker.d.ts} +0 -0
- /package/{directives/index.d.ts → types/yoozsoft-yoozsoft-ng-directives.d.ts} +0 -0
- /package/{footer/index.d.ts → types/yoozsoft-yoozsoft-ng-footer.d.ts} +0 -0
- /package/{loading/index.d.ts → types/yoozsoft-yoozsoft-ng-loading.d.ts} +0 -0
- /package/{overlay/index.d.ts → types/yoozsoft-yoozsoft-ng-overlay.d.ts} +0 -0
- /package/{pagination/index.d.ts → types/yoozsoft-yoozsoft-ng-pagination.d.ts} +0 -0
- /package/{password-strength/index.d.ts → types/yoozsoft-yoozsoft-ng-password-strength.d.ts} +0 -0
- /package/{sidebar/index.d.ts → types/yoozsoft-yoozsoft-ng-sidebar.d.ts} +0 -0
- /package/{index.d.ts → types/yoozsoft-yoozsoft-ng.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Yoozsoft Ng
|
|
2
2
|
|
|
3
|
-
Angular widgets built up using Bootstrap 5 CSS and NG Bootstrap
|
|
4
|
-
We are using TypeScript and targeting the Ng Bootstrap
|
|
3
|
+
Angular widgets built up using Bootstrap 5 CSS and NG Bootstrap 20 widgets with APIs designed for the Angular ecosystem, that are in standalone style.
|
|
4
|
+
We are using TypeScript and targeting the Ng Bootstrap 20 widgets and Bootstrap 5 CSS framework.
|
|
5
5
|
As with Bootstrap 5 and Angular 2, this library is a work in progress.
|
|
6
6
|
|
|
7
|
-
The dependencies are [Angular](https://angular.io/), [Ng Bootstrap](https://ng-bootstrap.github.io/)
|
|
7
|
+
The dependencies are [Angular](https://angular.io/), [Ng Bootstrap](https://ng-bootstrap.github.io/) 20 widgets, [Bootstrap](https://getbootstrap.com/) 5 CSS, [Popper](https://popper.js.org/).
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
10
10
|
|
|
@@ -25,7 +25,7 @@ Visit the [Yoozsoft Website](https://www.yoozsoft.com/ys-ng) for general informa
|
|
|
25
25
|
|
|
26
26
|
## Dependencies
|
|
27
27
|
|
|
28
|
-
The only dependencies are Angular, Ng Bootstrap
|
|
28
|
+
The only dependencies are Angular, Ng Bootstrap 20 widgets, Bootstrap 5 CSS, and Popper. The supported versions are:
|
|
29
29
|
|
|
30
30
|
<table>
|
|
31
31
|
<thead>
|
|
@@ -73,6 +73,13 @@ The only dependencies are Angular, Ng Bootstrap 19 widgets, Bootstrap 5 CSS, and
|
|
|
73
73
|
<td>5.3.6</td>
|
|
74
74
|
<td>2.11.8</td>
|
|
75
75
|
</tr>
|
|
76
|
+
<tr>
|
|
77
|
+
<th scope="row">6.x.x</th>
|
|
78
|
+
<td>^21.0.0</td>
|
|
79
|
+
<td>20.0.0</td>
|
|
80
|
+
<td>5.3.8</td>
|
|
81
|
+
<td>2.11.8</td>
|
|
82
|
+
</tr>
|
|
76
83
|
</tbody>
|
|
77
84
|
</table>
|
|
78
85
|
|
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
import * as i2 from '@angular/cdk/scrolling';
|
|
2
2
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
|
3
|
-
import { NgTemplateOutlet, NgClass } from '@angular/common';
|
|
3
|
+
import { isPlatformBrowser, NgTemplateOutlet, NgClass } from '@angular/common';
|
|
4
4
|
import * as i0 from '@angular/core';
|
|
5
|
-
import { EventEmitter,
|
|
5
|
+
import { signal, EventEmitter, inject, PLATFORM_ID, DestroyRef, effect, TemplateRef, forwardRef, Output, Input, ContentChild, ViewChild, Component } from '@angular/core';
|
|
6
6
|
import * as i1 from '@angular/forms';
|
|
7
7
|
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
8
|
-
import {
|
|
8
|
+
import { catchError, of } from 'rxjs';
|
|
9
9
|
|
|
10
10
|
class YsAutocompleteComponent {
|
|
11
11
|
elRef;
|
|
12
|
-
searchTerm = '';
|
|
13
|
-
filteredOptions = [];
|
|
14
|
-
selectedOptions = [];
|
|
15
|
-
showDropdown = false;
|
|
16
|
-
activeIndex = -1;
|
|
17
|
-
error = null;
|
|
12
|
+
searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
13
|
+
filteredOptions = signal([], ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
|
|
14
|
+
selectedOptions = signal([], ...(ngDevMode ? [{ debugName: "selectedOptions" }] : []));
|
|
15
|
+
showDropdown = signal(false, ...(ngDevMode ? [{ debugName: "showDropdown" }] : []));
|
|
16
|
+
activeIndex = signal(-1, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
|
|
17
|
+
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
18
|
+
inputRef;
|
|
19
|
+
_loading = signal(false, ...(ngDevMode ? [{ debugName: "_loading" }] : []));
|
|
20
|
+
set loading(value) { this._loading.set(!!value); }
|
|
21
|
+
get loading() { return this._loading(); }
|
|
22
|
+
loadingMessage = 'Loading...';
|
|
18
23
|
/** Array or async function */
|
|
19
|
-
|
|
24
|
+
_options = [];
|
|
25
|
+
set options(value) {
|
|
26
|
+
this._options = value;
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
this.filteredOptions.set(value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
get options() {
|
|
32
|
+
return this._options;
|
|
33
|
+
}
|
|
20
34
|
/** Label display field */
|
|
21
35
|
optionLabel = 'label';
|
|
22
36
|
/** placeholder */
|
|
@@ -31,8 +45,10 @@ class YsAutocompleteComponent {
|
|
|
31
45
|
styleClass;
|
|
32
46
|
/** Badge style class on Multiple choice mode */
|
|
33
47
|
badgeStyleClass = 'text-bg-light';
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
removeIconClass = 'fa fa-times';
|
|
49
|
+
searchIconClass = 'fa fa-search';
|
|
50
|
+
spinnerIconClass = 'fa fa-spinner fa-spin';
|
|
51
|
+
multipleCheckIconClass = 'fa fa-check';
|
|
36
52
|
/** No results found message */
|
|
37
53
|
noResultMessage = 'No results found.';
|
|
38
54
|
/** Infinite scroll feature enabled */
|
|
@@ -42,50 +58,55 @@ class YsAutocompleteComponent {
|
|
|
42
58
|
// [virtualScrollOptions]="options"
|
|
43
59
|
/** Event to request more items */
|
|
44
60
|
loadMore = new EventEmitter();
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
/** Output selection after removed item */
|
|
48
|
-
removed = new EventEmitter();
|
|
49
|
-
search$ = new Subject();
|
|
61
|
+
/** Return selected options */
|
|
62
|
+
selectionChange = new EventEmitter();
|
|
50
63
|
_onChange = () => { };
|
|
51
64
|
_onTouched = () => { };
|
|
52
|
-
inputRef;
|
|
53
65
|
get isArrayItems() { return Array.isArray(this.options); }
|
|
54
66
|
get isFunctionItems() { return typeof this.options === 'function'; }
|
|
55
67
|
constructor(elRef) {
|
|
56
68
|
this.elRef = elRef;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
const platformId = inject(PLATFORM_ID);
|
|
70
|
+
if (isPlatformBrowser(platformId)) {
|
|
71
|
+
const handler = (event) => {
|
|
72
|
+
if (!this.elRef.nativeElement.contains(event.target)) {
|
|
73
|
+
this.showDropdown.set(false);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
document.addEventListener('click', handler);
|
|
77
|
+
inject(DestroyRef).onDestroy(() => {
|
|
78
|
+
document.removeEventListener('click', handler);
|
|
79
|
+
});
|
|
61
80
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
.
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
return fetchFn(term).pipe(catchError((err) => {
|
|
70
|
-
this.error = 'Error receiving data!';
|
|
81
|
+
effect(() => {
|
|
82
|
+
const term = this.searchTerm();
|
|
83
|
+
if (typeof this._options === 'function') {
|
|
84
|
+
this._loading.set(true);
|
|
85
|
+
this.error.set(null);
|
|
86
|
+
this._options(term).pipe(catchError(err => {
|
|
87
|
+
this.error.set('Error receiving data!');
|
|
71
88
|
console.error(err);
|
|
72
89
|
return of([]);
|
|
73
|
-
}))
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
})).subscribe(results => {
|
|
91
|
+
this.filteredOptions.set(results);
|
|
92
|
+
this._loading.set(false);
|
|
93
|
+
if (results.length > 0) {
|
|
94
|
+
this.showDropdown.set(true); // فقط اگر نتایج داریم
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.showDropdown.set(false); // یا همون default
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
});
|
|
81
102
|
}
|
|
82
103
|
/** For the initial value of FormControl */
|
|
83
104
|
writeValue(value) {
|
|
84
105
|
if (this.multiple) {
|
|
85
|
-
this.selectedOptions
|
|
106
|
+
this.selectedOptions.set(value ? [...value] : []);
|
|
86
107
|
}
|
|
87
108
|
else {
|
|
88
|
-
this.searchTerm
|
|
109
|
+
this.searchTerm.set(value ? this.getLabel(value) : '');
|
|
89
110
|
}
|
|
90
111
|
}
|
|
91
112
|
registerOnChange(fn) {
|
|
@@ -100,56 +121,67 @@ class YsAutocompleteComponent {
|
|
|
100
121
|
this.inputRef.nativeElement.disabled = isDisabled;
|
|
101
122
|
}
|
|
102
123
|
}
|
|
103
|
-
onSearchChange() {
|
|
104
|
-
|
|
105
|
-
if (Array.isArray(this.
|
|
124
|
+
onSearchChange(term) {
|
|
125
|
+
this.searchTerm.set(term.trim());
|
|
126
|
+
if (Array.isArray(this._options)) {
|
|
106
127
|
const lower = term.toLowerCase();
|
|
107
|
-
this.filteredOptions
|
|
108
|
-
this.showDropdown
|
|
109
|
-
}
|
|
110
|
-
else if (typeof this.options === 'function') {
|
|
111
|
-
this.search$.next(term);
|
|
128
|
+
this.filteredOptions.set(this._options.filter(item => this.getLabel(item).toLowerCase().includes(lower)));
|
|
129
|
+
this.showDropdown.set(true);
|
|
112
130
|
}
|
|
113
131
|
if (!this.multiple && !term) {
|
|
114
132
|
this.clearSelection();
|
|
115
133
|
}
|
|
116
134
|
}
|
|
117
135
|
getLabel(item) {
|
|
118
|
-
if (
|
|
136
|
+
if (item === null || item === undefined)
|
|
119
137
|
return '';
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
// string / number
|
|
139
|
+
if (typeof item === 'string' || typeof item === 'number') {
|
|
140
|
+
return String(item);
|
|
141
|
+
}
|
|
142
|
+
// object
|
|
143
|
+
if (this.optionLabel && item[this.optionLabel] != null) {
|
|
144
|
+
return String(item[this.optionLabel]);
|
|
124
145
|
}
|
|
125
146
|
return '';
|
|
126
147
|
}
|
|
148
|
+
isEqual(a, b) {
|
|
149
|
+
if (typeof a !== 'object' && typeof b !== 'object') {
|
|
150
|
+
return a === b;
|
|
151
|
+
}
|
|
152
|
+
return this.getLabel(a) === this.getLabel(b);
|
|
153
|
+
}
|
|
127
154
|
onSelect(item) {
|
|
128
155
|
if (this.multiple) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
this.
|
|
137
|
-
this.
|
|
138
|
-
this.
|
|
156
|
+
this.selectedOptions.update(list => list.some(x => this.isEqual(x, item))
|
|
157
|
+
? list.filter(x => !this.isEqual(x, item)) // ✅ حذف
|
|
158
|
+
: [...list, item] // ✅ اضافه
|
|
159
|
+
);
|
|
160
|
+
const value = this.selectedOptions();
|
|
161
|
+
this._onChange(value);
|
|
162
|
+
this._onTouched();
|
|
163
|
+
this.selectionChange.emit(value);
|
|
164
|
+
this.searchTerm.set('');
|
|
165
|
+
this.showDropdown.set(true);
|
|
166
|
+
this.onSearchChange(this.searchTerm());
|
|
139
167
|
}
|
|
140
168
|
else {
|
|
141
|
-
this.searchTerm
|
|
169
|
+
this.searchTerm.set(this.getLabel(item));
|
|
142
170
|
this._onChange(item);
|
|
143
171
|
this._onTouched();
|
|
144
|
-
this.
|
|
145
|
-
this.showDropdown
|
|
172
|
+
this.selectionChange.emit(item);
|
|
173
|
+
this.showDropdown.set(false);
|
|
146
174
|
}
|
|
147
|
-
this.activeIndex
|
|
175
|
+
this.activeIndex.set(-1);
|
|
148
176
|
}
|
|
149
177
|
removeItem(item) {
|
|
150
|
-
|
|
151
|
-
this.
|
|
152
|
-
|
|
178
|
+
const prev = this.selectedOptions();
|
|
179
|
+
this.selectedOptions.update(list => list.filter(x => this.getLabel(x) !== this.getLabel(item)));
|
|
180
|
+
if (prev !== this.selectedOptions()) {
|
|
181
|
+
const value = this.selectedOptions();
|
|
182
|
+
this._onChange(value);
|
|
183
|
+
this.selectionChange.emit(value);
|
|
184
|
+
}
|
|
153
185
|
}
|
|
154
186
|
onScroll(event) {
|
|
155
187
|
if (!this.infiniteScroll || this.loading)
|
|
@@ -158,65 +190,63 @@ class YsAutocompleteComponent {
|
|
|
158
190
|
const nearBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 10;
|
|
159
191
|
if (nearBottom) {
|
|
160
192
|
// Request more items
|
|
161
|
-
this.loadMore.emit(this.searchTerm);
|
|
193
|
+
this.loadMore.emit(this.searchTerm());
|
|
162
194
|
}
|
|
163
195
|
}
|
|
164
196
|
clearSelection() {
|
|
165
197
|
if (this.multiple) {
|
|
166
|
-
this.selectedOptions
|
|
167
|
-
this.
|
|
168
|
-
this.
|
|
198
|
+
this.selectedOptions.set([]);
|
|
199
|
+
const value = this.selectedOptions();
|
|
200
|
+
this._onChange(value);
|
|
201
|
+
this.selectionChange.emit(value);
|
|
169
202
|
}
|
|
170
203
|
else {
|
|
171
|
-
this.searchTerm
|
|
204
|
+
this.searchTerm.set('');
|
|
172
205
|
this._onChange(null);
|
|
173
|
-
this.
|
|
206
|
+
this.selectionChange.emit(null);
|
|
174
207
|
}
|
|
175
|
-
this.showDropdown
|
|
208
|
+
// this.showDropdown.set(false);
|
|
176
209
|
}
|
|
177
|
-
/** Keyboard control */
|
|
178
210
|
handleKeyboard(event) {
|
|
179
|
-
|
|
211
|
+
const list = this.filteredOptions();
|
|
212
|
+
if (!this.showDropdown() || list.length === 0)
|
|
180
213
|
return;
|
|
181
214
|
switch (event.key) {
|
|
182
215
|
case 'ArrowDown':
|
|
183
|
-
|
|
216
|
+
// برو به آیتم بعدی
|
|
217
|
+
this.activeIndex.update(i => (i + 1) % list.length);
|
|
184
218
|
event.preventDefault();
|
|
185
219
|
break;
|
|
186
220
|
case 'ArrowUp':
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
this.filteredOptions.length;
|
|
221
|
+
// برو به آیتم قبلی
|
|
222
|
+
this.activeIndex.update(i => (i - 1 + list.length) % list.length);
|
|
190
223
|
event.preventDefault();
|
|
191
224
|
break;
|
|
192
225
|
case 'Enter':
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
226
|
+
const index = this.activeIndex();
|
|
227
|
+
if (index >= 0 && index < list.length) {
|
|
228
|
+
this.onSelect(list[index]);
|
|
196
229
|
}
|
|
230
|
+
event.preventDefault();
|
|
197
231
|
break;
|
|
198
232
|
case 'Escape':
|
|
199
|
-
this.showDropdown
|
|
233
|
+
this.showDropdown.set(false);
|
|
200
234
|
break;
|
|
201
235
|
}
|
|
202
236
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const clickedInside = this.elRef.nativeElement.contains(event.target);
|
|
206
|
-
if (!clickedInside) {
|
|
207
|
-
this.showDropdown = false;
|
|
208
|
-
}
|
|
237
|
+
isSelected(item) {
|
|
238
|
+
return this.selectedOptions().some(x => this.isEqual(x, item));
|
|
209
239
|
}
|
|
210
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
211
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
240
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: YsAutocompleteComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
241
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: YsAutocompleteComponent, isStandalone: true, selector: "ys-autocomplete", inputs: { loading: "loading", loadingMessage: "loadingMessage", options: "options", optionLabel: "optionLabel", placeholder: "placeholder", multiple: "multiple", showClear: "showClear", disabled: "disabled", styleClass: "styleClass", badgeStyleClass: "badgeStyleClass", removeIconClass: "removeIconClass", searchIconClass: "searchIconClass", spinnerIconClass: "spinnerIconClass", multipleCheckIconClass: "multipleCheckIconClass", noResultMessage: "noResultMessage", infiniteScroll: "infiniteScroll", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize" }, outputs: { loadMore: "loadMore", selectionChange: "selectionChange" }, providers: [
|
|
212
242
|
{
|
|
213
243
|
provide: NG_VALUE_ACCESSOR,
|
|
214
244
|
useExisting: forwardRef(() => YsAutocompleteComponent),
|
|
215
245
|
multi: true,
|
|
216
246
|
},
|
|
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
|
|
247
|
+
], 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 $index) {\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=\"{{removeIconClass}} 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 (ngModelChange)=\"onSearchChange($event)\" (keydown)=\"handleKeyboard($event)\"\r\n (focus)=\"showDropdown.set(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=\"{{removeIconClass}}\"></span>\r\n </button>\r\n }\r\n }\r\n <span class=\"input-group-text\" (click)=\"showDropdown.set( !showDropdown())\">\r\n <i class=\"{{searchIconClass}}\"></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=\"{{spinnerIconClass}} 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 $index; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\r\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n @if(multiple){\r\n <i class=\"{{multipleCheckIconClass}} me-1 text-success\" [class.invisible]=\"!isSelected(item)\">\r\n </i>\r\n }\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 $index; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\r\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n @if(multiple){\r\n <i class=\"{{multipleCheckIconClass}} me-1 text-success\" [class.invisible]=\"!isSelected(item)\">\r\n </i>\r\n }\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 .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: 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"] }] });
|
|
218
248
|
}
|
|
219
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
249
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: YsAutocompleteComponent, decorators: [{
|
|
220
250
|
type: Component,
|
|
221
251
|
args: [{ selector: 'ys-autocomplete', imports: [FormsModule, NgTemplateOutlet, NgClass, ScrollingModule], providers: [
|
|
222
252
|
{
|
|
@@ -224,8 +254,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
|
|
|
224
254
|
useExisting: forwardRef(() => YsAutocompleteComponent),
|
|
225
255
|
multi: true,
|
|
226
256
|
},
|
|
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
|
|
228
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: {
|
|
257
|
+
], 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 $index) {\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=\"{{removeIconClass}} 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 (ngModelChange)=\"onSearchChange($event)\" (keydown)=\"handleKeyboard($event)\"\r\n (focus)=\"showDropdown.set(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=\"{{removeIconClass}}\"></span>\r\n </button>\r\n }\r\n }\r\n <span class=\"input-group-text\" (click)=\"showDropdown.set( !showDropdown())\">\r\n <i class=\"{{searchIconClass}}\"></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=\"{{spinnerIconClass}} 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 $index; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\r\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n @if(multiple){\r\n <i class=\"{{multipleCheckIconClass}} me-1 text-success\" [class.invisible]=\"!isSelected(item)\">\r\n </i>\r\n }\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 $index; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\r\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n @if(multiple){\r\n <i class=\"{{multipleCheckIconClass}} me-1 text-success\" [class.invisible]=\"!isSelected(item)\">\r\n </i>\r\n }\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 .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"] }]
|
|
258
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { inputRef: [{
|
|
259
|
+
type: ViewChild,
|
|
260
|
+
args: ['inputRef']
|
|
261
|
+
}], loading: [{
|
|
262
|
+
type: Input
|
|
263
|
+
}], loadingMessage: [{
|
|
264
|
+
type: Input
|
|
265
|
+
}], options: [{
|
|
229
266
|
type: Input
|
|
230
267
|
}], optionLabel: [{
|
|
231
268
|
type: Input
|
|
@@ -244,9 +281,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
|
|
|
244
281
|
type: Input
|
|
245
282
|
}], badgeStyleClass: [{
|
|
246
283
|
type: Input
|
|
247
|
-
}],
|
|
284
|
+
}], removeIconClass: [{
|
|
248
285
|
type: Input
|
|
249
|
-
}],
|
|
286
|
+
}], searchIconClass: [{
|
|
287
|
+
type: Input
|
|
288
|
+
}], spinnerIconClass: [{
|
|
289
|
+
type: Input
|
|
290
|
+
}], multipleCheckIconClass: [{
|
|
250
291
|
type: Input
|
|
251
292
|
}], noResultMessage: [{
|
|
252
293
|
type: Input
|
|
@@ -258,19 +299,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
|
|
|
258
299
|
type: Input
|
|
259
300
|
}], loadMore: [{
|
|
260
301
|
type: Output
|
|
261
|
-
}],
|
|
262
|
-
type: Output
|
|
263
|
-
}], removed: [{
|
|
302
|
+
}], selectionChange: [{
|
|
264
303
|
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
304
|
}] } });
|
|
275
305
|
|
|
276
306
|
/*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yoozsoft-yoozsoft-ng-autocomplete.mjs","sources":["../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/src/ys-autocomplete/ys-autocomplete.component.ts","../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/src/ys-autocomplete/ys-autocomplete.component.html","../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/public-api.ts","../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/yoozsoft-yoozsoft-ng-autocomplete.ts"],"sourcesContent":["import { ScrollingModule } from '@angular/cdk/scrolling';\r\nimport { NgClass, NgTemplateOutlet } from '@angular/common';\r\nimport { Component, ContentChild, ElementRef, EventEmitter, forwardRef, HostListener, Input, Output, TemplateRef, ViewChild } from '@angular/core';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\nimport { catchError, debounceTime, distinctUntilChanged, Observable, of, Subject, switchMap } from 'rxjs';\r\n\r\n@Component({\r\n selector: 'ys-autocomplete',\r\n imports: [FormsModule, NgTemplateOutlet, NgClass, ScrollingModule],\r\n templateUrl: './ys-autocomplete.component.html',\r\n styleUrl: './ys-autocomplete.component.scss',\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => YsAutocompleteComponent),\r\n multi: true,\r\n },\r\n ],\r\n})\r\nexport class YsAutocompleteComponent implements ControlValueAccessor {\r\n\r\n searchTerm = '';\r\n filteredOptions: any[] = [];\r\n selectedOptions: any[] = [];\r\n showDropdown = false;\r\n activeIndex = -1;\r\n error: string | null = null;\r\n\r\n /** Array or async function */\r\n @Input() options?: any[] | ((term: string) => Observable<any[]>);\r\n\r\n /** Label display field */\r\n @Input() optionLabel = 'label';\r\n\r\n /** placeholder */\r\n @Input() placeholder: string = '';\r\n\r\n /** Multiple choice mode */\r\n @Input() multiple = false;\r\n\r\n /** Button to clear selection */\r\n @Input() showClear = false;\r\n\r\n @Input() disabled: boolean = false;\r\n\r\n /** Custom template */\r\n @ContentChild(TemplateRef) itemTemplate?: TemplateRef<any>;\r\n\r\n @Input() styleClass?: string;\r\n /** Badge style class on Multiple choice mode */\r\n @Input() badgeStyleClass: string = 'text-bg-light';\r\n @Input() loading: boolean = false;\r\n @Input() loadingMessage: string = 'Loading...';\r\n /** No results found message */\r\n @Input() noResultMessage: string = 'No results found.';\r\n\r\n /** Infinite scroll feature enabled */\r\n @Input() infiniteScroll = false;\r\n\r\n @Input() virtualScroll: boolean = true;\r\n @Input() virtualScrollItemSize: number = 36;\r\n // [virtualScrollOptions]=\"options\"\r\n\r\n /** Event to request more items */\r\n @Output() loadMore = new EventEmitter<string>();\r\n\r\n /** Output selection */\r\n @Output() selected = new EventEmitter<any>();\r\n /** Output selection after removed item */\r\n @Output() removed = new EventEmitter<any>();\r\n\r\n private search$ = new Subject<string>();\r\n private _onChange: (value: any) => void = () => { };\r\n private _onTouched: () => void = () => { };\r\n\r\n @ViewChild('inputRef') inputRef!: ElementRef<HTMLInputElement>;\r\n\r\n get isArrayItems(): boolean { return Array.isArray(this.options); }\r\n get isFunctionItems(): boolean { return typeof this.options === 'function'; }\r\n\r\n constructor(private elRef: ElementRef) { }\r\n\r\n ngOnInit() {\r\n if (Array.isArray(this.options)) {\r\n this.filteredOptions = this.options;\r\n }\r\n\r\n /** Only in async function mode */\r\n if (typeof this.options === 'function') {\r\n const fetchFn = this.options as (term: string) => Observable<any[]>;\r\n this.search$\r\n .pipe(\r\n debounceTime(300),\r\n distinctUntilChanged(),\r\n switchMap((term) => {\r\n this.loading = true;\r\n this.error = null;\r\n return fetchFn(term).pipe(\r\n catchError((err) => {\r\n this.error = 'Error receiving data!';\r\n console.error(err);\r\n return of([]);\r\n })\r\n );\r\n })\r\n )\r\n .subscribe((results) => {\r\n this.filteredOptions = results;\r\n this.loading = false;\r\n this.showDropdown = true;\r\n });\r\n }\r\n\r\n }\r\n\r\n /** For the initial value of FormControl */\r\n writeValue(value: any): void {\r\n if (this.multiple) {\r\n this.selectedOptions = value ? [...value] : [];\r\n } else {\r\n this.searchTerm = value ? this.getLabel(value) : '';\r\n }\r\n }\r\n\r\n registerOnChange(fn: any): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n if (this.inputRef) {\r\n this.inputRef.nativeElement.disabled = isDisabled;\r\n }\r\n }\r\n\r\n onSearchChange() {\r\n const term = this.searchTerm.trim();\r\n\r\n if (Array.isArray(this.options)) {\r\n const lower = term.toLowerCase();\r\n this.filteredOptions = this.options.filter((item) =>\r\n this.getLabel(item).toLowerCase().includes(lower)\r\n );\r\n this.showDropdown = this.filteredOptions.length >= 0;\r\n } else if (typeof this.options === 'function') {\r\n this.search$.next(term);\r\n }\r\n\r\n if (!this.multiple && !term) {\r\n this.clearSelection();\r\n }\r\n }\r\n\r\n getLabel(item: any): string {\r\n if (!item) return '';\r\n if (typeof item === 'string') return item;\r\n if (item && this.optionLabel && item[this.optionLabel]) {\r\n return item[this.optionLabel];\r\n }\r\n return '';\r\n }\r\n\r\n onSelect(item: any) {\r\n if (this.multiple) {\r\n const exists = this.selectedOptions.some(\r\n (x) => this.getLabel(x) === this.getLabel(item)\r\n );\r\n if (!exists) {\r\n this.selectedOptions.push(item);\r\n this._onChange(this.selectedOptions);\r\n this._onTouched();\r\n this.selected.emit(this.selectedOptions);\r\n }\r\n this.searchTerm = '';\r\n this.showDropdown = true;\r\n this.onSearchChange();\r\n } else {\r\n this.searchTerm = this.getLabel(item);\r\n this._onChange(item);\r\n this._onTouched();\r\n this.selected.emit(item);\r\n this.showDropdown = false;\r\n }\r\n\r\n this.activeIndex = -1;\r\n }\r\n\r\n removeItem(item: any) {\r\n this.selectedOptions = this.selectedOptions.filter(\r\n (x) => this.getLabel(x) !== this.getLabel(item)\r\n );\r\n this._onChange(this.selectedOptions);\r\n this.removed.emit(this.selectedOptions);\r\n }\r\n\r\n onScroll(event: Event) {\r\n if (!this.infiniteScroll || this.loading) return;\r\n\r\n const target = event.target as HTMLElement;\r\n const nearBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 10;\r\n\r\n if (nearBottom) {\r\n // Request more items\r\n this.loadMore.emit(this.searchTerm);\r\n }\r\n }\r\n\r\n clearSelection() {\r\n if (this.multiple) {\r\n this.selectedOptions = [];\r\n this._onChange(this.selectedOptions);\r\n this.removed.emit(this.selectedOptions);\r\n } else {\r\n this.searchTerm = '';\r\n this._onChange(null);\r\n this.selected.emit(null);\r\n }\r\n\r\n this.showDropdown = false;\r\n }\r\n\r\n /** Keyboard control */\r\n @HostListener('keydown', ['$event'])\r\n handleKeyboard(event: KeyboardEvent) {\r\n if (!this.showDropdown || this.filteredOptions.length === 0) return;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n this.activeIndex = (this.activeIndex + 1) % this.filteredOptions.length;\r\n event.preventDefault();\r\n break;\r\n case 'ArrowUp':\r\n this.activeIndex =\r\n (this.activeIndex - 1 + this.filteredOptions.length) %\r\n this.filteredOptions.length;\r\n event.preventDefault();\r\n break;\r\n case 'Enter':\r\n if (this.activeIndex >= 0) {\r\n this.onSelect(this.filteredOptions[this.activeIndex]);\r\n event.preventDefault();\r\n }\r\n break;\r\n case 'Escape':\r\n this.showDropdown = false;\r\n break;\r\n }\r\n }\r\n\r\n /** Close by clicking outside */\r\n @HostListener('document:click', ['$event'])\r\n onClickOutside(event: MouseEvent) {\r\n const clickedInside = this.elRef.nativeElement.contains(event.target);\r\n if (!clickedInside) {\r\n this.showDropdown = false;\r\n }\r\n }\r\n\r\n}\r\n","<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 <!-- ✅ حالت Virtual Scroll برای لیستهای بزرگ -->\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 <!-- ✅ حالت معمولی برای لیستهای کوچک -->\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>","/*\r\n * Public API Surface of ys-autocomplete\r\n */\r\n\r\nexport * from './src/ys-autocomplete/ys-autocomplete.component';\r\n\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yoozsoft-yoozsoft-ng-autocomplete.mjs","sources":["../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/src/ys-autocomplete/ys-autocomplete.component.ts","../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/src/ys-autocomplete/ys-autocomplete.component.html","../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/public-api.ts","../../../../projects/yoozsoft/yoozsoft-ng/autocomplete/yoozsoft-yoozsoft-ng-autocomplete.ts"],"sourcesContent":["import { ScrollingModule } from '@angular/cdk/scrolling';\r\nimport { isPlatformBrowser, NgClass, NgTemplateOutlet } from '@angular/common';\r\nimport { Component, ContentChild, DestroyRef, effect, ElementRef, EventEmitter, forwardRef, inject, Input, Output, PLATFORM_ID, signal, TemplateRef, ViewChild } from '@angular/core';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\nimport { catchError, Observable, of } from 'rxjs';\r\n\r\n@Component({\r\n selector: 'ys-autocomplete',\r\n imports: [FormsModule, NgTemplateOutlet, NgClass, ScrollingModule],\r\n templateUrl: './ys-autocomplete.component.html',\r\n styleUrl: './ys-autocomplete.component.scss',\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => YsAutocompleteComponent),\r\n multi: true,\r\n },\r\n ],\r\n})\r\nexport class YsAutocompleteComponent implements ControlValueAccessor {\r\n\r\n searchTerm = signal('');\r\n filteredOptions = signal<any[]>([]);\r\n selectedOptions = signal<any[]>([]);\r\n showDropdown = signal(false);\r\n activeIndex = signal(-1);\r\n error = signal<string | null>(null);\r\n\r\n @ViewChild('inputRef') inputRef!: ElementRef<HTMLInputElement>;\r\n\r\n private _loading = signal(false);\r\n @Input()\r\n set loading(value: boolean) { this._loading.set(!!value); }\r\n get loading() { return this._loading(); }\r\n\r\n @Input() loadingMessage: string = 'Loading...';\r\n\r\n /** Array or async function */\r\n private _options: any[] | ((term: string) => Observable<any[]>) = [];\r\n\r\n @Input()\r\n set options(value: any[] | ((term: string) => Observable<any[]>)) {\r\n this._options = value;\r\n\r\n if (Array.isArray(value)) {\r\n this.filteredOptions.set(value);\r\n }\r\n\r\n }\r\n\r\n get options() {\r\n return this._options;\r\n }\r\n\r\n /** Label display field */\r\n @Input() optionLabel = 'label';\r\n\r\n /** placeholder */\r\n @Input() placeholder: string = '';\r\n\r\n /** Multiple choice mode */\r\n @Input() multiple = false;\r\n\r\n /** Button to clear selection */\r\n @Input() showClear = false;\r\n\r\n @Input() disabled: boolean = false;\r\n\r\n /** Custom template */\r\n @ContentChild(TemplateRef) itemTemplate?: TemplateRef<any>;\r\n\r\n @Input() styleClass?: string;\r\n /** Badge style class on Multiple choice mode */\r\n @Input() badgeStyleClass: string = 'text-bg-light';\r\n @Input() removeIconClass: string = 'fa fa-times';\r\n @Input() searchIconClass: string = 'fa fa-search';\r\n @Input() spinnerIconClass: string = 'fa fa-spinner fa-spin';\r\n @Input() multipleCheckIconClass: string = 'fa fa-check';\r\n\r\n /** No results found message */\r\n @Input() noResultMessage: string = 'No results found.';\r\n\r\n /** Infinite scroll feature enabled */\r\n @Input() infiniteScroll = false;\r\n\r\n @Input() virtualScroll: boolean = true;\r\n @Input() virtualScrollItemSize: number = 36;\r\n // [virtualScrollOptions]=\"options\"\r\n\r\n /** Event to request more items */\r\n @Output() loadMore = new EventEmitter<string>();\r\n\r\n /** Return selected options */\r\n @Output() selectionChange = new EventEmitter<any>();\r\n\r\n private _onChange: (value: any) => void = () => { };\r\n private _onTouched: () => void = () => { };\r\n\r\n get isArrayItems(): boolean { return Array.isArray(this.options); }\r\n get isFunctionItems(): boolean { return typeof this.options === 'function'; }\r\n\r\n constructor(private elRef: ElementRef) {\r\n\r\n const platformId = inject(PLATFORM_ID);\r\n\r\n if (isPlatformBrowser(platformId)) {\r\n const handler = (event: MouseEvent) => {\r\n if (!this.elRef.nativeElement.contains(event.target)) {\r\n this.showDropdown.set(false);\r\n }\r\n };\r\n\r\n document.addEventListener('click', handler);\r\n\r\n inject(DestroyRef).onDestroy(() => {\r\n document.removeEventListener('click', handler);\r\n });\r\n }\r\n\r\n effect(() => {\r\n const term = this.searchTerm();\r\n\r\n if (typeof this._options === 'function') {\r\n this._loading.set(true);\r\n this.error.set(null);\r\n\r\n this._options(term).pipe(\r\n catchError(err => {\r\n this.error.set('Error receiving data!');\r\n console.error(err);\r\n return of([]);\r\n })\r\n ).subscribe(results => {\r\n this.filteredOptions.set(results);\r\n this._loading.set(false);\r\n\r\n if (results.length > 0) {\r\n this.showDropdown.set(true); // فقط اگر نتایج داریم\r\n } else {\r\n this.showDropdown.set(false); // یا همون default\r\n }\r\n\r\n });\r\n }\r\n });\r\n\r\n }\r\n\r\n /** For the initial value of FormControl */\r\n writeValue(value: any): void {\r\n if (this.multiple) {\r\n this.selectedOptions.set(value ? [...value] : []);\r\n } else {\r\n this.searchTerm.set(value ? this.getLabel(value) : '');\r\n }\r\n }\r\n\r\n registerOnChange(fn: any): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n if (this.inputRef) {\r\n this.inputRef.nativeElement.disabled = isDisabled;\r\n }\r\n }\r\n\r\n onSearchChange(term: string) {\r\n this.searchTerm.set(term.trim());\r\n\r\n if (Array.isArray(this._options)) {\r\n const lower = term.toLowerCase();\r\n this.filteredOptions.set(\r\n this._options.filter(item =>\r\n this.getLabel(item).toLowerCase().includes(lower)\r\n )\r\n );\r\n this.showDropdown.set(true);\r\n }\r\n\r\n if (!this.multiple && !term) {\r\n this.clearSelection();\r\n }\r\n }\r\n\r\n getLabel(item: any): string {\r\n if (item === null || item === undefined) return '';\r\n\r\n // string / number\r\n if (typeof item === 'string' || typeof item === 'number') {\r\n return String(item);\r\n }\r\n\r\n // object\r\n if (this.optionLabel && item[this.optionLabel] != null) {\r\n return String(item[this.optionLabel]);\r\n }\r\n\r\n return '';\r\n }\r\n\r\n private isEqual(a: any, b: any): boolean {\r\n if (typeof a !== 'object' && typeof b !== 'object') {\r\n return a === b;\r\n }\r\n return this.getLabel(a) === this.getLabel(b);\r\n }\r\n\r\n onSelect(item: any) {\r\n if (this.multiple) {\r\n this.selectedOptions.update(list =>\r\n list.some(x => this.isEqual(x, item))\r\n ? list.filter(x => !this.isEqual(x, item)) // ✅ حذف\r\n : [...list, item] // ✅ اضافه\r\n );\r\n\r\n const value = this.selectedOptions();\r\n this._onChange(value);\r\n this._onTouched();\r\n this.selectionChange.emit(value);\r\n\r\n this.searchTerm.set('');\r\n this.showDropdown.set(true);\r\n this.onSearchChange(this.searchTerm());\r\n\r\n } else {\r\n this.searchTerm.set(this.getLabel(item));\r\n this._onChange(item);\r\n this._onTouched();\r\n this.selectionChange.emit(item);\r\n this.showDropdown.set(false);\r\n }\r\n\r\n this.activeIndex.set(-1);\r\n }\r\n\r\n\r\n removeItem(item: any) {\r\n const prev = this.selectedOptions();\r\n\r\n this.selectedOptions.update(list =>\r\n list.filter(x => this.getLabel(x) !== this.getLabel(item))\r\n );\r\n\r\n if (prev !== this.selectedOptions()) {\r\n const value = this.selectedOptions();\r\n this._onChange(value);\r\n this.selectionChange.emit(value);\r\n }\r\n }\r\n\r\n onScroll(event: Event) {\r\n if (!this.infiniteScroll || this.loading) return;\r\n\r\n const target = event.target as HTMLElement;\r\n const nearBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 10;\r\n\r\n if (nearBottom) {\r\n // Request more items\r\n this.loadMore.emit(this.searchTerm());\r\n }\r\n }\r\n\r\n clearSelection() {\r\n if (this.multiple) {\r\n this.selectedOptions.set([]);\r\n const value = this.selectedOptions();\r\n this._onChange(value);\r\n this.selectionChange.emit(value);\r\n } else {\r\n this.searchTerm.set('');\r\n this._onChange(null);\r\n this.selectionChange.emit(null);\r\n }\r\n\r\n // this.showDropdown.set(false);\r\n }\r\n\r\n handleKeyboard(event: KeyboardEvent) {\r\n const list = this.filteredOptions();\r\n if (!this.showDropdown() || list.length === 0) return;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n // برو به آیتم بعدی\r\n this.activeIndex.update(i => (i + 1) % list.length);\r\n event.preventDefault();\r\n break;\r\n case 'ArrowUp':\r\n // برو به آیتم قبلی\r\n this.activeIndex.update(i => (i - 1 + list.length) % list.length);\r\n event.preventDefault();\r\n break;\r\n case 'Enter':\r\n const index = this.activeIndex();\r\n if (index >= 0 && index < list.length) {\r\n this.onSelect(list[index]);\r\n }\r\n event.preventDefault();\r\n break;\r\n case 'Escape':\r\n this.showDropdown.set(false);\r\n break;\r\n }\r\n }\r\n\r\n isSelected(item: any): boolean {\r\n return this.selectedOptions().some(x => this.isEqual(x, item));\r\n }\r\n\r\n}\r\n","<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 $index) {\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=\"{{removeIconClass}} 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 (ngModelChange)=\"onSearchChange($event)\" (keydown)=\"handleKeyboard($event)\"\r\n (focus)=\"showDropdown.set(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=\"{{removeIconClass}}\"></span>\r\n </button>\r\n }\r\n }\r\n <span class=\"input-group-text\" (click)=\"showDropdown.set( !showDropdown())\">\r\n <i class=\"{{searchIconClass}}\"></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=\"{{spinnerIconClass}} 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 <!-- ✅ حالت Virtual Scroll برای لیستهای بزرگ -->\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 $index; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\r\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n @if(multiple){\r\n <i class=\"{{multipleCheckIconClass}} me-1 text-success\" [class.invisible]=\"!isSelected(item)\">\r\n </i>\r\n }\r\n {{ getLabel(item) }}\r\n }\r\n </li>\r\n }\r\n </ul>\r\n </cdk-virtual-scroll-viewport>\r\n }\r\n <!-- ✅ حالت معمولی برای لیستهای کوچک -->\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 $index; let i = $index) {\r\n <li class=\"list-group-item list-group-item-action\" [class.active]=\"i === activeIndex()\"\r\n [class.selected]=\"isSelected(item)\" (click)=\"onSelect(item)\">\r\n @if (itemTemplate) {\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\r\n } @else {\r\n @if(multiple){\r\n <i class=\"{{multipleCheckIconClass}} me-1 text-success\" [class.invisible]=\"!isSelected(item)\">\r\n </i>\r\n }\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>","/*\r\n * Public API Surface of ys-autocomplete\r\n */\r\n\r\nexport * from './src/ys-autocomplete/ys-autocomplete.component';\r\n\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|