@yoozsoft/yoozsoft-ng 5.1.3 → 5.2.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.
@@ -6,33 +6,35 @@ import { Observable } from 'rxjs';
6
6
  declare class YsAutocompleteComponent implements ControlValueAccessor {
7
7
  private elRef;
8
8
  searchTerm: string;
9
- filteredItems: any[];
10
- selectedItems: any[];
9
+ filteredOptions: any[];
10
+ selectedOptions: any[];
11
11
  showDropdown: boolean;
12
12
  activeIndex: number;
13
13
  error: string | null;
14
14
  /** Array or async function */
15
- items?: any[] | ((term: string) => Observable<any[]>);
15
+ options?: any[] | ((term: string) => Observable<any[]>);
16
16
  /** Label display field */
17
- labelField: string;
17
+ optionLabel: string;
18
18
  /** placeholder */
19
- placeholder: string;
19
+ placeholder: string | null;
20
20
  /** Multiple choice mode */
21
21
  multiple: boolean;
22
22
  /** Button to clear selection */
23
- isClear: boolean;
23
+ showClear: boolean;
24
24
  disabled: boolean;
25
25
  /** Custom template */
26
26
  itemTemplate?: TemplateRef<any>;
27
27
  styleClass?: string;
28
28
  /** Badge style class on Multiple choice mode */
29
- badgeStyleClass?: string;
29
+ badgeStyleClass: string;
30
30
  loading: boolean;
31
31
  loadingMessage: string;
32
32
  /** No results found message */
33
33
  noResultMessage: string;
34
34
  /** Infinite scroll feature enabled */
35
35
  infiniteScroll: boolean;
36
+ virtualScroll: boolean;
37
+ virtualScrollItemSize: number;
36
38
  /** Event to request more items */
37
39
  loadMore: EventEmitter<string>;
38
40
  /** Output selection */
@@ -40,8 +42,8 @@ declare class YsAutocompleteComponent implements ControlValueAccessor {
40
42
  /** Output selection after removed item */
41
43
  removed: EventEmitter<any>;
42
44
  private search$;
43
- private onChange;
44
- private onTouched;
45
+ private _onChange;
46
+ private _onTouched;
45
47
  inputRef: ElementRef<HTMLInputElement>;
46
48
  get isArrayItems(): boolean;
47
49
  get isFunctionItems(): boolean;
@@ -63,7 +65,7 @@ declare class YsAutocompleteComponent implements ControlValueAccessor {
63
65
  /** Close by clicking outside */
64
66
  onClickOutside(event: MouseEvent): void;
65
67
  static ɵfac: i0.ɵɵFactoryDeclaration<YsAutocompleteComponent, never>;
66
- static ɵcmp: i0.ɵɵComponentDeclaration<YsAutocompleteComponent, "ys-autocomplete", never, { "items": { "alias": "items"; "required": false; }; "labelField": { "alias": "labelField"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "multiple": { "alias": "multiple"; "required": false; }; "isClear": { "alias": "isClear"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "styleClass": { "alias": "styleClass"; "required": false; }; "badgeStyleClass": { "alias": "badgeStyleClass"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "loadingMessage": { "alias": "loadingMessage"; "required": false; }; "noResultMessage": { "alias": "noResultMessage"; "required": false; }; "infiniteScroll": { "alias": "infiniteScroll"; "required": false; }; }, { "loadMore": "loadMore"; "selected": "selected"; "removed": "removed"; }, ["itemTemplate"], never, true, never>;
68
+ static ɵcmp: i0.ɵɵComponentDeclaration<YsAutocompleteComponent, "ys-autocomplete", never, { "options": { "alias": "options"; "required": false; }; "optionLabel": { "alias": "optionLabel"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "multiple": { "alias": "multiple"; "required": false; }; "showClear": { "alias": "showClear"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "styleClass": { "alias": "styleClass"; "required": false; }; "badgeStyleClass": { "alias": "badgeStyleClass"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "loadingMessage": { "alias": "loadingMessage"; "required": false; }; "noResultMessage": { "alias": "noResultMessage"; "required": false; }; "infiniteScroll": { "alias": "infiniteScroll"; "required": false; }; "virtualScroll": { "alias": "virtualScroll"; "required": false; }; "virtualScrollItemSize": { "alias": "virtualScrollItemSize"; "required": false; }; }, { "loadMore": "loadMore"; "selected": "selected"; "removed": "removed"; }, ["itemTemplate"], never, true, never>;
67
69
  }
68
70
 
69
71
  export { YsAutocompleteComponent };
@@ -0,0 +1,51 @@
1
+ import * as i0 from '@angular/core';
2
+ import { TemplateRef, EventEmitter } from '@angular/core';
3
+ import { ControlValueAccessor } from '@angular/forms';
4
+
5
+ declare class YsDropdownComponent implements ControlValueAccessor {
6
+ /** لیست گزینه‌ها */
7
+ options: any[];
8
+ optionLabel: string;
9
+ placeholder: string;
10
+ searchPlaceholder: string;
11
+ selectedMaxLength: number;
12
+ selectedMaxLengthTemplate: string;
13
+ selectionSeparator: string;
14
+ /** انتخاب چندگانه یا تکی */
15
+ multiple: boolean;
16
+ showClear: boolean;
17
+ /** تمپلیت سفارشی برای آیتم‌ها */
18
+ itemTemplate?: TemplateRef<any>;
19
+ /** مقدار انتخاب‌شده */
20
+ selected: any[] | any;
21
+ /** قابلیت جستجو */
22
+ searchable: boolean;
23
+ disabled: boolean;
24
+ /** رویداد خروجی هنگام تغییر انتخاب */
25
+ selectionChange: EventEmitter<any>;
26
+ searchTerm: string;
27
+ isOpen: boolean;
28
+ highlightedIndex: number;
29
+ private elRef;
30
+ private _onChange;
31
+ private _onTouched;
32
+ writeValue(obj: any): void;
33
+ registerOnChange(fn: any): void;
34
+ registerOnTouched(fn: any): void;
35
+ setDisabledState?(isDisabled: boolean): void;
36
+ get displayLabel(): string;
37
+ get selectedLabels(): string;
38
+ toggleDropdown(): void;
39
+ filterOptions(): any[];
40
+ selectOption(option: any): void;
41
+ isSelected(option: any): boolean;
42
+ clearSelection(): void;
43
+ onKeyDown(event: KeyboardEvent): void;
44
+ scrollToHighlighted(): void;
45
+ /** Close by clicking outside */
46
+ onClickOutside(event: MouseEvent): void;
47
+ static ɵfac: i0.ɵɵFactoryDeclaration<YsDropdownComponent, never>;
48
+ static ɵcmp: i0.ɵɵComponentDeclaration<YsDropdownComponent, "ys-dropdown", never, { "options": { "alias": "options"; "required": false; }; "optionLabel": { "alias": "optionLabel"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; }; "selectedMaxLength": { "alias": "selectedMaxLength"; "required": false; }; "selectedMaxLengthTemplate": { "alias": "selectedMaxLengthTemplate"; "required": false; }; "selectionSeparator": { "alias": "selectionSeparator"; "required": false; }; "multiple": { "alias": "multiple"; "required": false; }; "showClear": { "alias": "showClear"; "required": false; }; "itemTemplate": { "alias": "itemTemplate"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "searchable": { "alias": "searchable"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "selectionChange": "selectionChange"; }, never, never, true, never>;
49
+ }
50
+
51
+ export { YsDropdownComponent };
@@ -10,33 +10,36 @@ import { Subject, debounceTime, distinctUntilChanged, switchMap, catchError, of
10
10
  class YsAutocompleteComponent {
11
11
  elRef;
12
12
  searchTerm = '';
13
- filteredItems = [];
14
- selectedItems = [];
13
+ filteredOptions = [];
14
+ selectedOptions = [];
15
15
  showDropdown = false;
16
16
  activeIndex = -1;
17
17
  error = null;
18
18
  /** Array or async function */
19
- items;
19
+ options;
20
20
  /** Label display field */
21
- labelField = 'label';
21
+ optionLabel = 'label';
22
22
  /** placeholder */
23
- placeholder = 'Search...';
23
+ placeholder = null;
24
24
  /** Multiple choice mode */
25
25
  multiple = false;
26
26
  /** Button to clear selection */
27
- isClear = false;
27
+ showClear = false;
28
28
  disabled = false;
29
29
  /** Custom template */
30
30
  itemTemplate;
31
31
  styleClass;
32
32
  /** Badge style class on Multiple choice mode */
33
- badgeStyleClass;
33
+ badgeStyleClass = 'text-bg-light';
34
34
  loading = false;
35
35
  loadingMessage = 'Loading...';
36
36
  /** No results found message */
37
37
  noResultMessage = 'No results found.';
38
38
  /** Infinite scroll feature enabled */
39
39
  infiniteScroll = false;
40
+ virtualScroll = true;
41
+ virtualScrollItemSize = 36;
42
+ // [virtualScrollOptions]="options"
40
43
  /** Event to request more items */
41
44
  loadMore = new EventEmitter();
42
45
  /** Output selection */
@@ -44,21 +47,21 @@ class YsAutocompleteComponent {
44
47
  /** Output selection after removed item */
45
48
  removed = new EventEmitter();
46
49
  search$ = new Subject();
47
- onChange = () => { };
48
- onTouched = () => { };
50
+ _onChange = () => { };
51
+ _onTouched = () => { };
49
52
  inputRef;
50
- get isArrayItems() { return Array.isArray(this.items); }
51
- get isFunctionItems() { return typeof this.items === 'function'; }
53
+ get isArrayItems() { return Array.isArray(this.options); }
54
+ get isFunctionItems() { return typeof this.options === 'function'; }
52
55
  constructor(elRef) {
53
56
  this.elRef = elRef;
54
57
  }
55
58
  ngOnInit() {
56
- if (Array.isArray(this.items)) {
57
- this.filteredItems = this.items;
59
+ if (Array.isArray(this.options)) {
60
+ this.filteredOptions = this.options;
58
61
  }
59
62
  /** Only in async function mode */
60
- if (typeof this.items === 'function') {
61
- const fetchFn = this.items;
63
+ if (typeof this.options === 'function') {
64
+ const fetchFn = this.options;
62
65
  this.search$
63
66
  .pipe(debounceTime(300), distinctUntilChanged(), switchMap((term) => {
64
67
  this.loading = true;
@@ -70,7 +73,7 @@ class YsAutocompleteComponent {
70
73
  }));
71
74
  }))
72
75
  .subscribe((results) => {
73
- this.filteredItems = results;
76
+ this.filteredOptions = results;
74
77
  this.loading = false;
75
78
  this.showDropdown = true;
76
79
  });
@@ -79,17 +82,17 @@ class YsAutocompleteComponent {
79
82
  /** For the initial value of FormControl */
80
83
  writeValue(value) {
81
84
  if (this.multiple) {
82
- this.selectedItems = value ? [...value] : [];
85
+ this.selectedOptions = value ? [...value] : [];
83
86
  }
84
87
  else {
85
88
  this.searchTerm = value ? this.getLabel(value) : '';
86
89
  }
87
90
  }
88
91
  registerOnChange(fn) {
89
- this.onChange = fn;
92
+ this._onChange = fn;
90
93
  }
91
94
  registerOnTouched(fn) {
92
- this.onTouched = fn;
95
+ this._onTouched = fn;
93
96
  }
94
97
  setDisabledState(isDisabled) {
95
98
  this.disabled = isDisabled;
@@ -99,12 +102,12 @@ class YsAutocompleteComponent {
99
102
  }
100
103
  onSearchChange() {
101
104
  const term = this.searchTerm.trim();
102
- if (Array.isArray(this.items)) {
105
+ if (Array.isArray(this.options)) {
103
106
  const lower = term.toLowerCase();
104
- this.filteredItems = this.items.filter((item) => this.getLabel(item).toLowerCase().includes(lower));
105
- this.showDropdown = this.filteredItems.length >= 0;
107
+ this.filteredOptions = this.options.filter((item) => this.getLabel(item).toLowerCase().includes(lower));
108
+ this.showDropdown = this.filteredOptions.length >= 0;
106
109
  }
107
- else if (typeof this.items === 'function') {
110
+ else if (typeof this.options === 'function') {
108
111
  this.search$.next(term);
109
112
  }
110
113
  if (!this.multiple && !term) {
@@ -116,18 +119,19 @@ class YsAutocompleteComponent {
116
119
  return '';
117
120
  if (typeof item === 'string')
118
121
  return item;
119
- if (item && this.labelField && item[this.labelField]) {
120
- return item[this.labelField];
122
+ if (item && this.optionLabel && item[this.optionLabel]) {
123
+ return item[this.optionLabel];
121
124
  }
122
125
  return '';
123
126
  }
124
127
  onSelect(item) {
125
128
  if (this.multiple) {
126
- const exists = this.selectedItems.some((x) => this.getLabel(x) === this.getLabel(item));
129
+ const exists = this.selectedOptions.some((x) => this.getLabel(x) === this.getLabel(item));
127
130
  if (!exists) {
128
- this.selectedItems.push(item);
129
- this.onChange(this.selectedItems);
130
- this.selected.emit(this.selectedItems);
131
+ this.selectedOptions.push(item);
132
+ this._onChange(this.selectedOptions);
133
+ this._onTouched();
134
+ this.selected.emit(this.selectedOptions);
131
135
  }
132
136
  this.searchTerm = '';
133
137
  this.showDropdown = true;
@@ -135,16 +139,17 @@ class YsAutocompleteComponent {
135
139
  }
136
140
  else {
137
141
  this.searchTerm = this.getLabel(item);
138
- this.onChange(item);
142
+ this._onChange(item);
143
+ this._onTouched();
139
144
  this.selected.emit(item);
140
145
  this.showDropdown = false;
141
146
  }
142
147
  this.activeIndex = -1;
143
148
  }
144
149
  removeItem(item) {
145
- this.selectedItems = this.selectedItems.filter((x) => this.getLabel(x) !== this.getLabel(item));
146
- this.onChange(this.selectedItems);
147
- this.removed.emit(this.selectedItems);
150
+ this.selectedOptions = this.selectedOptions.filter((x) => this.getLabel(x) !== this.getLabel(item));
151
+ this._onChange(this.selectedOptions);
152
+ this.removed.emit(this.selectedOptions);
148
153
  }
149
154
  onScroll(event) {
150
155
  if (!this.infiniteScroll || this.loading)
@@ -158,35 +163,35 @@ class YsAutocompleteComponent {
158
163
  }
159
164
  clearSelection() {
160
165
  if (this.multiple) {
161
- this.selectedItems = [];
162
- this.onChange(this.selectedItems);
163
- this.removed.emit(this.selectedItems);
166
+ this.selectedOptions = [];
167
+ this._onChange(this.selectedOptions);
168
+ this.removed.emit(this.selectedOptions);
164
169
  }
165
170
  else {
166
171
  this.searchTerm = '';
167
- this.onChange(null);
172
+ this._onChange(null);
168
173
  this.selected.emit(null);
169
174
  }
170
175
  this.showDropdown = false;
171
176
  }
172
177
  /** Keyboard control */
173
178
  handleKeyboard(event) {
174
- if (!this.showDropdown || this.filteredItems.length === 0)
179
+ if (!this.showDropdown || this.filteredOptions.length === 0)
175
180
  return;
176
181
  switch (event.key) {
177
182
  case 'ArrowDown':
178
- this.activeIndex = (this.activeIndex + 1) % this.filteredItems.length;
183
+ this.activeIndex = (this.activeIndex + 1) % this.filteredOptions.length;
179
184
  event.preventDefault();
180
185
  break;
181
186
  case 'ArrowUp':
182
187
  this.activeIndex =
183
- (this.activeIndex - 1 + this.filteredItems.length) %
184
- this.filteredItems.length;
188
+ (this.activeIndex - 1 + this.filteredOptions.length) %
189
+ this.filteredOptions.length;
185
190
  event.preventDefault();
186
191
  break;
187
192
  case 'Enter':
188
193
  if (this.activeIndex >= 0) {
189
- this.onSelect(this.filteredItems[this.activeIndex]);
194
+ this.onSelect(this.filteredOptions[this.activeIndex]);
190
195
  event.preventDefault();
191
196
  }
192
197
  break;
@@ -203,13 +208,13 @@ class YsAutocompleteComponent {
203
208
  }
204
209
  }
205
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 });
206
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.5", type: YsAutocompleteComponent, isStandalone: true, selector: "ys-autocomplete", inputs: { items: "items", labelField: "labelField", placeholder: "placeholder", multiple: "multiple", isClear: "isClear", disabled: "disabled", styleClass: "styleClass", badgeStyleClass: "badgeStyleClass", loading: "loading", loadingMessage: "loadingMessage", noResultMessage: "noResultMessage", infiniteScroll: "infiniteScroll" }, outputs: { loadMore: "loadMore", selected: "selected", removed: "removed" }, host: { listeners: { "keydown": "handleKeyboard($event)", "document:click": "onClickOutside($event)" } }, providers: [
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: [
207
212
  {
208
213
  provide: NG_VALUE_ACCESSOR,
209
214
  useExisting: forwardRef(() => YsAutocompleteComponent),
210
215
  multi: true,
211
216
  },
212
- ], 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 && selectedItems.length > 0) {\r\n <div class=\"d-flex flex-wrap\">\r\n @for (item of selectedItems; track item) {\r\n <span class=\"badge text-bg-primary 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 (isClear) {\r\n @if ((multiple && selectedItems.length > 0) || (!multiple && searchTerm)) {\r\n <button class=\"btn btn-outline-danger btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-trash\"></span>\r\n </button>\r\n }\r\n }\r\n @if(showDropdown){\r\n <span class=\"input-group-text\" (click)=\"showDropdown = false\">\r\n <i class=\"fa fa-times\"></i>\r\n </span>\r\n }\r\n @else{\r\n <span class=\"input-group-text\" (click)=\"showDropdown = true\">\r\n <i class=\"fa fa-search\"></i>\r\n </span>\r\n }\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 } @else if (error) {\r\n <div class=\"list-group-item text-danger text-center\">{{ error }}</div>\r\n } @else if (filteredItems.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 (filteredItems.length > 100) {\r\n <cdk-virtual-scroll-viewport itemSize=\"36\" class=\"list-group w-100 overflow-y-auto\">\r\n <ul class=\"list-group w-100\">\r\n @for (item of filteredItems; 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 filteredItems; 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 .badge{font-size:.9rem;cursor:default}.ys-autocomplete .badge i{cursor:pointer;font-size:.8rem}\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"] }] });
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"] }] });
213
218
  }
214
219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsAutocompleteComponent, decorators: [{
215
220
  type: Component,
@@ -219,16 +224,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
219
224
  useExisting: forwardRef(() => YsAutocompleteComponent),
220
225
  multi: true,
221
226
  },
222
- ], template: "<div class=\"ys-autocomplete position-relative\">\r\n <div class=\"input-group flex-wrap\">\r\n @if (multiple && selectedItems.length > 0) {\r\n <div class=\"d-flex flex-wrap\">\r\n @for (item of selectedItems; track item) {\r\n <span class=\"badge text-bg-primary 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 (isClear) {\r\n @if ((multiple && selectedItems.length > 0) || (!multiple && searchTerm)) {\r\n <button class=\"btn btn-outline-danger btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-trash\"></span>\r\n </button>\r\n }\r\n }\r\n @if(showDropdown){\r\n <span class=\"input-group-text\" (click)=\"showDropdown = false\">\r\n <i class=\"fa fa-times\"></i>\r\n </span>\r\n }\r\n @else{\r\n <span class=\"input-group-text\" (click)=\"showDropdown = true\">\r\n <i class=\"fa fa-search\"></i>\r\n </span>\r\n }\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 } @else if (error) {\r\n <div class=\"list-group-item text-danger text-center\">{{ error }}</div>\r\n } @else if (filteredItems.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 (filteredItems.length > 100) {\r\n <cdk-virtual-scroll-viewport itemSize=\"36\" class=\"list-group w-100 overflow-y-auto\">\r\n <ul class=\"list-group w-100\">\r\n @for (item of filteredItems; 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 filteredItems; 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 .badge{font-size:.9rem;cursor:default}.ys-autocomplete .badge i{cursor:pointer;font-size:.8rem}\n"] }]
223
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { items: [{
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: [{
224
229
  type: Input
225
- }], labelField: [{
230
+ }], optionLabel: [{
226
231
  type: Input
227
232
  }], placeholder: [{
228
233
  type: Input
229
234
  }], multiple: [{
230
235
  type: Input
231
- }], isClear: [{
236
+ }], showClear: [{
232
237
  type: Input
233
238
  }], disabled: [{
234
239
  type: Input
@@ -247,6 +252,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
247
252
  type: Input
248
253
  }], infiniteScroll: [{
249
254
  type: Input
255
+ }], virtualScroll: [{
256
+ type: Input
257
+ }], virtualScrollItemSize: [{
258
+ type: Input
250
259
  }], loadMore: [{
251
260
  type: Output
252
261
  }], selected: [{
@@ -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 filteredItems: any[] = [];\r\n selectedItems: 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() items?: any[] | ((term: string) => Observable<any[]>);\r\n\r\n /** Label display field */\r\n @Input() labelField = 'label';\r\n\r\n /** placeholder */\r\n @Input() placeholder = 'Search...';\r\n\r\n /** Multiple choice mode */\r\n @Input() multiple = false;\r\n\r\n /** Button to clear selection */\r\n @Input() isClear = 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;\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 /** 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.items); }\r\n get isFunctionItems(): boolean { return typeof this.items === 'function'; }\r\n\r\n constructor(private elRef: ElementRef) { }\r\n\r\n ngOnInit() {\r\n if (Array.isArray(this.items)) {\r\n this.filteredItems = this.items;\r\n }\r\n\r\n /** Only in async function mode */\r\n if (typeof this.items === 'function') {\r\n const fetchFn = this.items 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.filteredItems = 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.selectedItems = 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.items)) {\r\n const lower = term.toLowerCase();\r\n this.filteredItems = this.items.filter((item) =>\r\n this.getLabel(item).toLowerCase().includes(lower)\r\n );\r\n this.showDropdown = this.filteredItems.length >= 0;\r\n } else if (typeof this.items === '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.labelField && item[this.labelField]) {\r\n return item[this.labelField];\r\n }\r\n return '';\r\n }\r\n\r\n onSelect(item: any) {\r\n if (this.multiple) {\r\n const exists = this.selectedItems.some(\r\n (x) => this.getLabel(x) === this.getLabel(item)\r\n );\r\n if (!exists) {\r\n this.selectedItems.push(item);\r\n this.onChange(this.selectedItems);\r\n this.selected.emit(this.selectedItems);\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.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.selectedItems = this.selectedItems.filter(\r\n (x) => this.getLabel(x) !== this.getLabel(item)\r\n );\r\n this.onChange(this.selectedItems);\r\n this.removed.emit(this.selectedItems);\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.selectedItems = [];\r\n this.onChange(this.selectedItems);\r\n this.removed.emit(this.selectedItems);\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.filteredItems.length === 0) return;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n this.activeIndex = (this.activeIndex + 1) % this.filteredItems.length;\r\n event.preventDefault();\r\n break;\r\n case 'ArrowUp':\r\n this.activeIndex =\r\n (this.activeIndex - 1 + this.filteredItems.length) %\r\n this.filteredItems.length;\r\n event.preventDefault();\r\n break;\r\n case 'Enter':\r\n if (this.activeIndex >= 0) {\r\n this.onSelect(this.filteredItems[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 && selectedItems.length > 0) {\r\n <div class=\"d-flex flex-wrap\">\r\n @for (item of selectedItems; track item) {\r\n <span class=\"badge text-bg-primary 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 (isClear) {\r\n @if ((multiple && selectedItems.length > 0) || (!multiple && searchTerm)) {\r\n <button class=\"btn btn-outline-danger btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearSelection()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-trash\"></span>\r\n </button>\r\n }\r\n }\r\n @if(showDropdown){\r\n <span class=\"input-group-text\" (click)=\"showDropdown = false\">\r\n <i class=\"fa fa-times\"></i>\r\n </span>\r\n }\r\n @else{\r\n <span class=\"input-group-text\" (click)=\"showDropdown = true\">\r\n <i class=\"fa fa-search\"></i>\r\n </span>\r\n }\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 } @else if (error) {\r\n <div class=\"list-group-item text-danger text-center\">{{ error }}</div>\r\n } @else if (filteredItems.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 (filteredItems.length > 100) {\r\n <cdk-virtual-scroll-viewport itemSize=\"36\" class=\"list-group w-100 overflow-y-auto\">\r\n <ul class=\"list-group w-100\">\r\n @for (item of filteredItems; 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 filteredItems; 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 { 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 | null = null;\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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"}
@@ -0,0 +1,228 @@
1
+ import { NgTemplateOutlet } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { EventEmitter, inject, ElementRef, forwardRef, HostListener, Output, Input, Component } from '@angular/core';
4
+ import * as i1 from '@angular/forms';
5
+ import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
6
+
7
+ class YsDropdownComponent {
8
+ /** لیست گزینه‌ها */
9
+ options = [];
10
+ optionLabel = 'label';
11
+ placeholder = '';
12
+ searchPlaceholder = '';
13
+ selectedMaxLength = 3;
14
+ selectedMaxLengthTemplate = '{length} items selected';
15
+ selectionSeparator = ", ";
16
+ /** انتخاب چندگانه یا تکی */
17
+ multiple = false;
18
+ showClear = false;
19
+ /** تمپلیت سفارشی برای آیتم‌ها */
20
+ itemTemplate;
21
+ /** مقدار انتخاب‌شده */
22
+ selected = this.multiple ? [] : null;
23
+ /** قابلیت جستجو */
24
+ searchable = false;
25
+ disabled = false;
26
+ /** رویداد خروجی هنگام تغییر انتخاب */
27
+ selectionChange = new EventEmitter();
28
+ searchTerm = '';
29
+ isOpen = false;
30
+ highlightedIndex = -1;
31
+ elRef = inject(ElementRef);
32
+ _onChange = () => { };
33
+ _onTouched = () => { };
34
+ writeValue(obj) {
35
+ if (this.multiple) {
36
+ this.selected = obj ? [...obj] : [];
37
+ }
38
+ else {
39
+ this.selected = obj;
40
+ }
41
+ }
42
+ registerOnChange(fn) {
43
+ this._onChange = fn;
44
+ }
45
+ registerOnTouched(fn) {
46
+ this._onTouched = fn;
47
+ }
48
+ setDisabledState(isDisabled) {
49
+ this.disabled = isDisabled;
50
+ }
51
+ get displayLabel() {
52
+ if (this.multiple) {
53
+ const count = Array.isArray(this.selected) ? this.selected.length : 0;
54
+ return count ? `${count} مورد انتخاب شده` : 'انتخاب کنید';
55
+ }
56
+ // تکه‌ی ایمن: از options (که همیشه آرایه است ولی بازهم چک می‌کنیم)
57
+ const label = this.options?.find(o => o.value === this.selected)?.label;
58
+ return label ?? 'انتخاب کنید';
59
+ }
60
+ get selectedLabels() {
61
+ if (this.multiple && Array.isArray(this.selected)) {
62
+ if (this.selected.length > this.selectedMaxLength) {
63
+ return this.selectedMaxLengthTemplate.replace('{length}', this.selected.length + '');
64
+ }
65
+ return this.selected.map(x => x[this.optionLabel]).join(this.selectionSeparator);
66
+ }
67
+ else {
68
+ return this.selected ? this.selected[this.optionLabel] : '';
69
+ }
70
+ }
71
+ toggleDropdown() {
72
+ this.isOpen = !this.isOpen;
73
+ if (this.isOpen) {
74
+ this.highlightedIndex = -1;
75
+ }
76
+ }
77
+ filterOptions() {
78
+ let list = this.options;
79
+ if (this.searchable && this.searchTerm.trim()) {
80
+ const term = this.searchTerm.toLowerCase();
81
+ list = this.options.filter(opt => opt[this.optionLabel].toLowerCase().includes(term));
82
+ }
83
+ // هر بار جستجو انجام شد index ریست بشه
84
+ this.highlightedIndex = Math.min(this.highlightedIndex, list.length - 1);
85
+ return list;
86
+ }
87
+ selectOption(option) {
88
+ if (option.disabled)
89
+ return;
90
+ if (this.multiple) {
91
+ const exists = this.selected?.some((x) => x === option);
92
+ this.selected = exists
93
+ ? this.selected.filter((x) => x !== option)
94
+ : [...(this.selected || []), option];
95
+ }
96
+ else {
97
+ this.selected = option;
98
+ this.isOpen = false;
99
+ }
100
+ this._onChange(this.selected);
101
+ this._onTouched();
102
+ this.selectionChange.emit(this.selected);
103
+ }
104
+ isSelected(option) {
105
+ return this.multiple
106
+ ? this.selected?.includes(option)
107
+ : this.selected === option;
108
+ }
109
+ clearSelection() {
110
+ this.selected = this.multiple ? [] : null;
111
+ this._onChange(this.selected);
112
+ this._onTouched();
113
+ this.selectionChange.emit(this.selected);
114
+ }
115
+ onKeyDown(event) {
116
+ const filtered = this.filterOptions();
117
+ if (!filtered.length)
118
+ return;
119
+ switch (event.key) {
120
+ case 'ArrowDown':
121
+ event.preventDefault();
122
+ this.highlightedIndex = (this.highlightedIndex + 1) % filtered.length;
123
+ this.scrollToHighlighted();
124
+ break;
125
+ case 'ArrowUp':
126
+ event.preventDefault();
127
+ this.highlightedIndex = this.highlightedIndex > 0 ? this.highlightedIndex - 1 : filtered.length - 1;
128
+ this.scrollToHighlighted();
129
+ break;
130
+ case 'Enter':
131
+ event.preventDefault();
132
+ if (this.highlightedIndex >= 0 && this.highlightedIndex < filtered.length) {
133
+ this.selectOption(filtered[this.highlightedIndex]);
134
+ }
135
+ break;
136
+ case 'Escape':
137
+ this.isOpen = false;
138
+ break;
139
+ }
140
+ }
141
+ scrollToHighlighted() {
142
+ // تأخیر جزئی برای اطمینان از رندر کامل
143
+ setTimeout(() => {
144
+ const dropdown = this.elRef.nativeElement.querySelector('.dropdown-menu');
145
+ const items = dropdown?.querySelectorAll('.dropdown-item');
146
+ const activeItem = items?.[this.highlightedIndex];
147
+ if (activeItem && dropdown) {
148
+ const itemTop = activeItem.offsetTop;
149
+ const itemBottom = itemTop + activeItem.offsetHeight;
150
+ const dropdownScrollTop = dropdown.scrollTop;
151
+ const dropdownHeight = dropdown.clientHeight;
152
+ if (itemBottom > dropdownScrollTop + dropdownHeight) {
153
+ dropdown.scrollTop = itemBottom - dropdownHeight;
154
+ }
155
+ else if (itemTop < dropdownScrollTop) {
156
+ dropdown.scrollTop = itemTop;
157
+ }
158
+ }
159
+ });
160
+ }
161
+ /** Close by clicking outside */
162
+ onClickOutside(event) {
163
+ const clickedInside = this.elRef.nativeElement.contains(event.target);
164
+ if (!clickedInside) {
165
+ this.isOpen = false;
166
+ }
167
+ }
168
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
169
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.5", type: YsDropdownComponent, isStandalone: true, selector: "ys-dropdown", inputs: { options: "options", optionLabel: "optionLabel", placeholder: "placeholder", searchPlaceholder: "searchPlaceholder", selectedMaxLength: "selectedMaxLength", selectedMaxLengthTemplate: "selectedMaxLengthTemplate", selectionSeparator: "selectionSeparator", multiple: "multiple", showClear: "showClear", itemTemplate: "itemTemplate", selected: "selected", searchable: "searchable", disabled: "disabled" }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
170
+ {
171
+ provide: NG_VALUE_ACCESSOR,
172
+ useExisting: forwardRef(() => YsDropdownComponent),
173
+ multi: true,
174
+ },
175
+ ], ngImport: i0, template: "<div class=\"dropdown ys-dropdown\">\r\n <div class=\"input-group w-100\">\r\n <input #inputRef type=\"text\" class=\"form-control\" [value]=\"selectedLabels\" [placeholder]=\"placeholder\" readonly\r\n (focus)=\"isOpen = true\" (keydown)=\"onKeyDown($event)\" />\r\n\r\n @if(showClear && (multiple ? selected?.length > 0 : selected)){\r\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\">\r\n <i class=\"fa fa-times\"></i>\r\n </button>\r\n }\r\n\r\n <button class=\"btn btn-outline-secondary dropdown-toggle\" type=\"button\" (click)=\"toggleDropdown()\">\r\n <i class=\"fa fa-chevron-down\"></i>\r\n </button>\r\n </div>\r\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen\">\r\n\r\n @if(searchable){\r\n <div class=\"px-2\">\r\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder\" [(ngModel)]=\"searchTerm\"\r\n (keydown)=\"onKeyDown($event)\">\r\n </div>\r\n }\r\n\r\n @for (option of filterOptions(); track $index) {\r\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\r\n [class.highlighted]=\"$index === highlightedIndex\">\r\n @if(itemTemplate){\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{ option: option }\">\r\n </ng-container>\r\n }\r\n @else {\r\n @if(multiple){\r\n <i class=\"fa fa-check text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\r\n }\r\n <span>{{option[optionLabel]}}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [".ys-dropdown .dropdown-toggle:after{display:none}.ys-dropdown .dropdown-menu{max-height:200px}.ys-dropdown .dropdown-item.highlighted{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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"] }] });
176
+ }
177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsDropdownComponent, decorators: [{
178
+ type: Component,
179
+ args: [{ selector: 'ys-dropdown', imports: [NgTemplateOutlet, FormsModule], providers: [
180
+ {
181
+ provide: NG_VALUE_ACCESSOR,
182
+ useExisting: forwardRef(() => YsDropdownComponent),
183
+ multi: true,
184
+ },
185
+ ], template: "<div class=\"dropdown ys-dropdown\">\r\n <div class=\"input-group w-100\">\r\n <input #inputRef type=\"text\" class=\"form-control\" [value]=\"selectedLabels\" [placeholder]=\"placeholder\" readonly\r\n (focus)=\"isOpen = true\" (keydown)=\"onKeyDown($event)\" />\r\n\r\n @if(showClear && (multiple ? selected?.length > 0 : selected)){\r\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\">\r\n <i class=\"fa fa-times\"></i>\r\n </button>\r\n }\r\n\r\n <button class=\"btn btn-outline-secondary dropdown-toggle\" type=\"button\" (click)=\"toggleDropdown()\">\r\n <i class=\"fa fa-chevron-down\"></i>\r\n </button>\r\n </div>\r\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen\">\r\n\r\n @if(searchable){\r\n <div class=\"px-2\">\r\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder\" [(ngModel)]=\"searchTerm\"\r\n (keydown)=\"onKeyDown($event)\">\r\n </div>\r\n }\r\n\r\n @for (option of filterOptions(); track $index) {\r\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\r\n [class.highlighted]=\"$index === highlightedIndex\">\r\n @if(itemTemplate){\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{ option: option }\">\r\n </ng-container>\r\n }\r\n @else {\r\n @if(multiple){\r\n <i class=\"fa fa-check text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\r\n }\r\n <span>{{option[optionLabel]}}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [".ys-dropdown .dropdown-toggle:after{display:none}.ys-dropdown .dropdown-menu{max-height:200px}.ys-dropdown .dropdown-item.highlighted{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}\n"] }]
186
+ }], propDecorators: { options: [{
187
+ type: Input
188
+ }], optionLabel: [{
189
+ type: Input
190
+ }], placeholder: [{
191
+ type: Input
192
+ }], searchPlaceholder: [{
193
+ type: Input
194
+ }], selectedMaxLength: [{
195
+ type: Input
196
+ }], selectedMaxLengthTemplate: [{
197
+ type: Input
198
+ }], selectionSeparator: [{
199
+ type: Input
200
+ }], multiple: [{
201
+ type: Input
202
+ }], showClear: [{
203
+ type: Input
204
+ }], itemTemplate: [{
205
+ type: Input
206
+ }], selected: [{
207
+ type: Input
208
+ }], searchable: [{
209
+ type: Input
210
+ }], disabled: [{
211
+ type: Input
212
+ }], selectionChange: [{
213
+ type: Output
214
+ }], onClickOutside: [{
215
+ type: HostListener,
216
+ args: ['document:click', ['$event']]
217
+ }] } });
218
+
219
+ /*
220
+ * Public API Surface of ys-dropdown
221
+ */
222
+
223
+ /**
224
+ * Generated bundle index. Do not edit.
225
+ */
226
+
227
+ export { YsDropdownComponent };
228
+ //# sourceMappingURL=yoozsoft-yoozsoft-ng-dropdown.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yoozsoft-yoozsoft-ng-dropdown.mjs","sources":["../../../../projects/yoozsoft/yoozsoft-ng/dropdown/src/ys-dropdown/ys-dropdown.component.ts","../../../../projects/yoozsoft/yoozsoft-ng/dropdown/src/ys-dropdown/ys-dropdown.component.html","../../../../projects/yoozsoft/yoozsoft-ng/dropdown/public-api.ts","../../../../projects/yoozsoft/yoozsoft-ng/dropdown/yoozsoft-yoozsoft-ng-dropdown.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\r\nimport { Component, ElementRef, EventEmitter, forwardRef, HostListener, inject, Input, Output, TemplateRef } from '@angular/core';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\n@Component({\r\n selector: 'ys-dropdown',\r\n imports: [NgTemplateOutlet, FormsModule],\r\n templateUrl: './ys-dropdown.component.html',\r\n styleUrl: './ys-dropdown.component.scss',\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => YsDropdownComponent),\r\n multi: true,\r\n },\r\n ],\r\n})\r\nexport class YsDropdownComponent implements ControlValueAccessor {\r\n\r\n /** لیست گزینه‌ها */\r\n @Input() options: any[] = [];\r\n @Input() optionLabel: string = 'label';\r\n @Input() placeholder: string = '';\r\n @Input() searchPlaceholder: string = '';\r\n @Input() selectedMaxLength: number = 3;\r\n @Input() selectedMaxLengthTemplate: string = '{length} items selected';\r\n @Input() selectionSeparator: string = \", \";\r\n\r\n /** انتخاب چندگانه یا تکی */\r\n @Input() multiple: boolean = false;\r\n\r\n @Input() showClear: boolean = false;\r\n\r\n /** تمپلیت سفارشی برای آیتم‌ها */\r\n @Input() itemTemplate?: TemplateRef<any>;\r\n\r\n /** مقدار انتخاب‌شده */\r\n @Input() selected: any[] | any = this.multiple ? [] : null;\r\n\r\n /** قابلیت جستجو */\r\n @Input() searchable: boolean = false;\r\n\r\n @Input() disabled: boolean = false;\r\n\r\n /** رویداد خروجی هنگام تغییر انتخاب */\r\n @Output() selectionChange = new EventEmitter<any>();\r\n\r\n searchTerm = '';\r\n isOpen = false;\r\n highlightedIndex: number = -1;\r\n\r\n private elRef = inject(ElementRef)\r\n\r\n private _onChange: (value: any) => void = () => { };\r\n private _onTouched: () => void = () => { };\r\n\r\n writeValue(obj: any): void {\r\n if (this.multiple) {\r\n this.selected = obj ? [...obj] : [];\r\n } else {\r\n this.selected = obj;\r\n }\r\n }\r\n registerOnChange(fn: any): void {\r\n this._onChange = fn;\r\n }\r\n registerOnTouched(fn: any): void {\r\n this._onTouched = fn;\r\n }\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n }\r\n\r\n get displayLabel(): string {\r\n if (this.multiple) {\r\n const count = Array.isArray(this.selected) ? this.selected.length : 0;\r\n return count ? `${count} مورد انتخاب شده` : 'انتخاب کنید';\r\n }\r\n\r\n // تکه‌ی ایمن: از options (که همیشه آرایه است ولی بازهم چک می‌کنیم)\r\n const label = this.options?.find(o => o.value === this.selected)?.label;\r\n return label ?? 'انتخاب کنید';\r\n }\r\n\r\n get selectedLabels(): string {\r\n if (this.multiple && Array.isArray(this.selected)) {\r\n if (this.selected.length > this.selectedMaxLength) {\r\n return this.selectedMaxLengthTemplate.replace('{length}', this.selected.length + '')\r\n }\r\n return this.selected.map(x => x[this.optionLabel]).join(this.selectionSeparator);\r\n } else {\r\n return this.selected ? this.selected[this.optionLabel] : '';\r\n }\r\n }\r\n\r\n toggleDropdown() {\r\n this.isOpen = !this.isOpen;\r\n if (this.isOpen) {\r\n this.highlightedIndex = -1;\r\n }\r\n }\r\n\r\n filterOptions(): any[] {\r\n let list = this.options;\r\n if (this.searchable && this.searchTerm.trim()) {\r\n const term = this.searchTerm.toLowerCase();\r\n list = this.options.filter(opt =>\r\n opt[this.optionLabel].toLowerCase().includes(term)\r\n );\r\n }\r\n // هر بار جستجو انجام شد index ریست بشه\r\n this.highlightedIndex = Math.min(this.highlightedIndex, list.length - 1);\r\n return list;\r\n }\r\n\r\n selectOption(option: any) {\r\n if (option.disabled) return;\r\n\r\n if (this.multiple) {\r\n const exists = this.selected?.some((x: any) => x === option);\r\n this.selected = exists\r\n ? this.selected.filter((x: any) => x !== option)\r\n : [...(this.selected || []), option];\r\n } else {\r\n this.selected = option;\r\n this.isOpen = false;\r\n }\r\n\r\n this._onChange(this.selected);\r\n this._onTouched();\r\n this.selectionChange.emit(this.selected);\r\n }\r\n\r\n isSelected(option: any): boolean {\r\n return this.multiple\r\n ? this.selected?.includes(option)\r\n : this.selected === option;\r\n }\r\n\r\n clearSelection() {\r\n this.selected = this.multiple ? [] : null;\r\n this._onChange(this.selected);\r\n this._onTouched();\r\n this.selectionChange.emit(this.selected);\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent) {\r\n const filtered = this.filterOptions();\r\n if (!filtered.length) return;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n this.highlightedIndex = (this.highlightedIndex + 1) % filtered.length;\r\n this.scrollToHighlighted();\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this.highlightedIndex = this.highlightedIndex > 0 ? this.highlightedIndex - 1 : filtered.length - 1;\r\n this.scrollToHighlighted();\r\n break;\r\n case 'Enter':\r\n event.preventDefault();\r\n if (this.highlightedIndex >= 0 && this.highlightedIndex < filtered.length) {\r\n this.selectOption(filtered[this.highlightedIndex]);\r\n }\r\n break;\r\n case 'Escape':\r\n this.isOpen = false;\r\n break;\r\n }\r\n }\r\n\r\n scrollToHighlighted() {\r\n // تأخیر جزئی برای اطمینان از رندر کامل\r\n setTimeout(() => {\r\n const dropdown = this.elRef.nativeElement.querySelector('.dropdown-menu');\r\n const items = dropdown?.querySelectorAll('.dropdown-item');\r\n const activeItem = items?.[this.highlightedIndex] as HTMLElement;\r\n if (activeItem && dropdown) {\r\n const itemTop = activeItem.offsetTop;\r\n const itemBottom = itemTop + activeItem.offsetHeight;\r\n const dropdownScrollTop = dropdown.scrollTop;\r\n const dropdownHeight = dropdown.clientHeight;\r\n\r\n if (itemBottom > dropdownScrollTop + dropdownHeight) {\r\n dropdown.scrollTop = itemBottom - dropdownHeight;\r\n } else if (itemTop < dropdownScrollTop) {\r\n dropdown.scrollTop = itemTop;\r\n }\r\n }\r\n });\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.isOpen = false;\r\n }\r\n }\r\n\r\n}\r\n","<div class=\"dropdown ys-dropdown\">\r\n <div class=\"input-group w-100\">\r\n <input #inputRef type=\"text\" class=\"form-control\" [value]=\"selectedLabels\" [placeholder]=\"placeholder\" readonly\r\n (focus)=\"isOpen = true\" (keydown)=\"onKeyDown($event)\" />\r\n\r\n @if(showClear && (multiple ? selected?.length > 0 : selected)){\r\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\">\r\n <i class=\"fa fa-times\"></i>\r\n </button>\r\n }\r\n\r\n <button class=\"btn btn-outline-secondary dropdown-toggle\" type=\"button\" (click)=\"toggleDropdown()\">\r\n <i class=\"fa fa-chevron-down\"></i>\r\n </button>\r\n </div>\r\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen\">\r\n\r\n @if(searchable){\r\n <div class=\"px-2\">\r\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder\" [(ngModel)]=\"searchTerm\"\r\n (keydown)=\"onKeyDown($event)\">\r\n </div>\r\n }\r\n\r\n @for (option of filterOptions(); track $index) {\r\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\r\n [class.highlighted]=\"$index === highlightedIndex\">\r\n @if(itemTemplate){\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{ option: option }\">\r\n </ng-container>\r\n }\r\n @else {\r\n @if(multiple){\r\n <i class=\"fa fa-check text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\r\n }\r\n <span>{{option[optionLabel]}}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>","/*\r\n * Public API Surface of ys-dropdown\r\n */\r\n\r\nexport * from './src/ys-dropdown/ys-dropdown.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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"}
@@ -21,7 +21,7 @@ class YsSelectComponent {
21
21
  /**Size of multiple attribute */
22
22
  size;
23
23
  /**Display clear button */
24
- isClear = false;
24
+ showClear = false;
25
25
  disabled = false;
26
26
  selected = new EventEmitter();
27
27
  onChange = () => { };
@@ -72,13 +72,13 @@ class YsSelectComponent {
72
72
  return typeof item == 'object';
73
73
  }
74
74
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
75
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.5", type: YsSelectComponent, isStandalone: true, selector: "ys-select", inputs: { id: "id", options: "options", optionLabel: "optionLabel", placeholder: "placeholder", styleClass: "styleClass", invalid: "invalid", invalidFeedback: "invalidFeedback", valid: "valid", validFeedback: "validFeedback", multiple: "multiple", size: "size", isClear: "isClear", disabled: "disabled" }, outputs: { selected: "selected" }, providers: [
75
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.5", type: YsSelectComponent, isStandalone: true, selector: "ys-select", inputs: { id: "id", options: "options", optionLabel: "optionLabel", placeholder: "placeholder", styleClass: "styleClass", invalid: "invalid", invalidFeedback: "invalidFeedback", valid: "valid", validFeedback: "validFeedback", multiple: "multiple", size: "size", showClear: "showClear", disabled: "disabled" }, outputs: { selected: "selected" }, providers: [
76
76
  {
77
77
  provide: NG_VALUE_ACCESSOR,
78
78
  useExisting: forwardRef(() => YsSelectComponent),
79
79
  multi: true
80
80
  }
81
- ], ngImport: i0, template: "<div class=\"ys-select\" [ngClass]=\"{'input-group': isClear, 'is-valid': valid, 'is-invalid': invalid}\">\r\n\r\n @if (!multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\" class=\"d-none\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\"\r\n [multiple]=\"multiple\" [size]=\"size\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (isClear) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearValue()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n</div>\r\n\r\n@if(valid && validFeedback){\r\n<div class=\"valid-feedback\">{{validFeedback}}</div>\r\n}\r\n@if(invalid && invalidFeedback){\r\n<div class=\"invalid-feedback\">{{invalidFeedback}}</div>\r\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
81
+ ], ngImport: i0, template: "<div class=\"ys-select\" [ngClass]=\"{'input-group': showClear, 'is-valid': valid, 'is-invalid': invalid}\">\r\n\r\n @if (!multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\" class=\"d-none\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\"\r\n [multiple]=\"multiple\" [size]=\"size\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (showClear) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearValue()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n</div>\r\n\r\n@if(valid && validFeedback){\r\n<div class=\"valid-feedback\">{{validFeedback}}</div>\r\n}\r\n@if(invalid && invalidFeedback){\r\n<div class=\"invalid-feedback\">{{invalidFeedback}}</div>\r\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
82
82
  }
83
83
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsSelectComponent, decorators: [{
84
84
  type: Component,
@@ -88,7 +88,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
88
88
  useExisting: forwardRef(() => YsSelectComponent),
89
89
  multi: true
90
90
  }
91
- ], template: "<div class=\"ys-select\" [ngClass]=\"{'input-group': isClear, 'is-valid': valid, 'is-invalid': invalid}\">\r\n\r\n @if (!multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\" class=\"d-none\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\"\r\n [multiple]=\"multiple\" [size]=\"size\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (isClear) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearValue()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n</div>\r\n\r\n@if(valid && validFeedback){\r\n<div class=\"valid-feedback\">{{validFeedback}}</div>\r\n}\r\n@if(invalid && invalidFeedback){\r\n<div class=\"invalid-feedback\">{{invalidFeedback}}</div>\r\n}" }]
91
+ ], template: "<div class=\"ys-select\" [ngClass]=\"{'input-group': showClear, 'is-valid': valid, 'is-invalid': invalid}\">\r\n\r\n @if (!multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\" class=\"d-none\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\"\r\n [multiple]=\"multiple\" [size]=\"size\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (showClear) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearValue()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n</div>\r\n\r\n@if(valid && validFeedback){\r\n<div class=\"valid-feedback\">{{validFeedback}}</div>\r\n}\r\n@if(invalid && invalidFeedback){\r\n<div class=\"invalid-feedback\">{{invalidFeedback}}</div>\r\n}" }]
92
92
  }], propDecorators: { id: [{
93
93
  type: Input
94
94
  }], options: [{
@@ -111,7 +111,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
111
111
  type: Input
112
112
  }], size: [{
113
113
  type: Input
114
- }], isClear: [{
114
+ }], showClear: [{
115
115
  type: Input
116
116
  }], disabled: [{
117
117
  type: Input
@@ -1 +1 @@
1
- {"version":3,"file":"yoozsoft-yoozsoft-ng-select.mjs","sources":["../../../../projects/yoozsoft/yoozsoft-ng/select/src/ys-select/ys-select.component.ts","../../../../projects/yoozsoft/yoozsoft-ng/select/src/ys-select/ys-select.component.html","../../../../projects/yoozsoft/yoozsoft-ng/select/public-api.ts","../../../../projects/yoozsoft/yoozsoft-ng/select/yoozsoft-yoozsoft-ng-select.ts"],"sourcesContent":["\r\nimport { NgClass } from '@angular/common';\r\nimport { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\n@Component({\r\n selector: 'ys-select',\r\n imports: [FormsModule, NgClass],\r\n templateUrl: './ys-select.component.html',\r\n styleUrl: './ys-select.component.scss',\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => YsSelectComponent),\r\n multi: true\r\n }\r\n ]\r\n})\r\nexport class YsSelectComponent implements ControlValueAccessor {\r\n\r\n /**ُSelect element id */\r\n @Input() id: string = 'ys-select';\r\n @Input() options: any[] = [];\r\n /**Name of field to display in option title */\r\n @Input() optionLabel: string = 'label';\r\n @Input() placeholder?: string;\r\n @Input() styleClass?: string;\r\n @Input() invalid?: boolean = false;\r\n @Input() invalidFeedback?: string;\r\n @Input() valid?: boolean = false;\r\n @Input() validFeedback?: string;\r\n /**Support multiple attribute */\r\n @Input() multiple?: boolean = false;\r\n /**Size of multiple attribute */\r\n @Input() size?: number;\r\n /**Display clear button */\r\n @Input() isClear?: boolean = false;\r\n\r\n @Input() disabled: boolean = false;\r\n @Output() selected: EventEmitter<any> = new EventEmitter<any>();\r\n\r\n onChange: any = () => { }\r\n onTouched: any = () => { }\r\n\r\n value?: any;\r\n\r\n writeValue(obj: any): void {\r\n if (!this.multiple && this.placeholder && !obj) {\r\n this.value = null;\r\n this.onChange(this.value);\r\n return;\r\n }\r\n\r\n if (this.multiple && !obj) {\r\n this.multiple ? this.value = [] : this.value = null;\r\n this.onChange(this.value);\r\n return;\r\n }\r\n\r\n if (!this.multiple && obj && Array.isArray(obj)) {\r\n if (obj.length) {\r\n this.value = obj[0];\r\n }\r\n else {\r\n this.value = null;\r\n }\r\n this.onChange(this.value);\r\n return;\r\n }\r\n\r\n this.value = obj;\r\n }\r\n registerOnChange(fn: any): void {\r\n this.onChange = fn;\r\n }\r\n registerOnTouched(fn: any): void {\r\n this.onTouched = fn;\r\n }\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n }\r\n\r\n onModelChange(option: any) {\r\n this.onChange(option);\r\n this.onTouched(option);\r\n this.selected.emit(option);\r\n }\r\n\r\n clearValue() {\r\n this.multiple ? this.value = [] : this.value = null;\r\n this.onModelChange(this.value);\r\n }\r\n\r\n isObject(item: any) {\r\n return typeof item == 'object';\r\n }\r\n\r\n}\r\n","<div class=\"ys-select\" [ngClass]=\"{'input-group': isClear, 'is-valid': valid, 'is-invalid': invalid}\">\r\n\r\n @if (!multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\" class=\"d-none\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\"\r\n [multiple]=\"multiple\" [size]=\"size\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (isClear) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearValue()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n</div>\r\n\r\n@if(valid && validFeedback){\r\n<div class=\"valid-feedback\">{{validFeedback}}</div>\r\n}\r\n@if(invalid && invalidFeedback){\r\n<div class=\"invalid-feedback\">{{invalidFeedback}}</div>\r\n}","/*\r\n * Public API Surface of ys-select\r\n */\r\n\r\nexport * from './src/ys-select/ys-select.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-select.mjs","sources":["../../../../projects/yoozsoft/yoozsoft-ng/select/src/ys-select/ys-select.component.ts","../../../../projects/yoozsoft/yoozsoft-ng/select/src/ys-select/ys-select.component.html","../../../../projects/yoozsoft/yoozsoft-ng/select/public-api.ts","../../../../projects/yoozsoft/yoozsoft-ng/select/yoozsoft-yoozsoft-ng-select.ts"],"sourcesContent":["\r\nimport { NgClass } from '@angular/common';\r\nimport { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\n@Component({\r\n selector: 'ys-select',\r\n imports: [FormsModule, NgClass],\r\n templateUrl: './ys-select.component.html',\r\n styleUrl: './ys-select.component.scss',\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => YsSelectComponent),\r\n multi: true\r\n }\r\n ]\r\n})\r\nexport class YsSelectComponent implements ControlValueAccessor {\r\n\r\n /**ُSelect element id */\r\n @Input() id: string = 'ys-select';\r\n @Input() options: any[] = [];\r\n /**Name of field to display in option title */\r\n @Input() optionLabel: string = 'label';\r\n @Input() placeholder?: string;\r\n @Input() styleClass?: string;\r\n @Input() invalid?: boolean = false;\r\n @Input() invalidFeedback?: string;\r\n @Input() valid?: boolean = false;\r\n @Input() validFeedback?: string;\r\n /**Support multiple attribute */\r\n @Input() multiple?: boolean = false;\r\n /**Size of multiple attribute */\r\n @Input() size?: number;\r\n /**Display clear button */\r\n @Input() showClear?: boolean = false;\r\n\r\n @Input() disabled: boolean = false;\r\n @Output() selected: EventEmitter<any> = new EventEmitter<any>();\r\n\r\n onChange: any = () => { }\r\n onTouched: any = () => { }\r\n\r\n value?: any;\r\n\r\n writeValue(obj: any): void {\r\n if (!this.multiple && this.placeholder && !obj) {\r\n this.value = null;\r\n this.onChange(this.value);\r\n return;\r\n }\r\n\r\n if (this.multiple && !obj) {\r\n this.multiple ? this.value = [] : this.value = null;\r\n this.onChange(this.value);\r\n return;\r\n }\r\n\r\n if (!this.multiple && obj && Array.isArray(obj)) {\r\n if (obj.length) {\r\n this.value = obj[0];\r\n }\r\n else {\r\n this.value = null;\r\n }\r\n this.onChange(this.value);\r\n return;\r\n }\r\n\r\n this.value = obj;\r\n }\r\n registerOnChange(fn: any): void {\r\n this.onChange = fn;\r\n }\r\n registerOnTouched(fn: any): void {\r\n this.onTouched = fn;\r\n }\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n }\r\n\r\n onModelChange(option: any) {\r\n this.onChange(option);\r\n this.onTouched(option);\r\n this.selected.emit(option);\r\n }\r\n\r\n clearValue() {\r\n this.multiple ? this.value = [] : this.value = null;\r\n this.onModelChange(this.value);\r\n }\r\n\r\n isObject(item: any) {\r\n return typeof item == 'object';\r\n }\r\n\r\n}\r\n","<div class=\"ys-select\" [ngClass]=\"{'input-group': showClear, 'is-valid': valid, 'is-invalid': invalid}\">\r\n\r\n @if (!multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\" class=\"d-none\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (multiple) {\r\n <select [id]=\"id\" class=\"form-select {{styleClass}}\" [ngClass]=\"{'is-valid': valid, 'is-invalid': invalid}\"\r\n aria-label=\"Select option\" [(ngModel)]=\"value\" (ngModelChange)=\"onModelChange($event)\" [disabled]=\"disabled\"\r\n [multiple]=\"multiple\" [size]=\"size\">\r\n @if (placeholder) {\r\n <option selected disabled [ngValue]=\"null\"> {{placeholder}}\r\n </option>\r\n }\r\n @for (item of options; track item; let i = $index) {\r\n <option [selected]=\" i === 0 && !placeholder \" [ngValue]=\"item\">\r\n {{isObject(item) ? item[optionLabel] : item}}\r\n </option>\r\n }\r\n </select>\r\n }\r\n\r\n @if (showClear) {\r\n <button class=\"btn btn-outline-secondary btn-clear\" type=\"button\" id=\"btn-clear\" (click)=\"clearValue()\"\r\n [disabled]=\"disabled\">\r\n <span class=\"fa fa-times\"></span>\r\n </button>\r\n }\r\n</div>\r\n\r\n@if(valid && validFeedback){\r\n<div class=\"valid-feedback\">{{validFeedback}}</div>\r\n}\r\n@if(invalid && invalidFeedback){\r\n<div class=\"invalid-feedback\">{{invalidFeedback}}</div>\r\n}","/*\r\n * Public API Surface of ys-select\r\n */\r\n\r\nexport * from './src/ys-select/ys-select.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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoozsoft/yoozsoft-ng",
3
- "version": "5.1.3",
3
+ "version": "5.2.1",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^20.0.0",
6
6
  "@angular/core": "^20.0.0"
@@ -15,6 +15,7 @@
15
15
  "ng-bootstrap",
16
16
  "components",
17
17
  "autocomplete",
18
+ "dropdown",
18
19
  "file-upload",
19
20
  "navbar",
20
21
  "password-strength",
@@ -40,10 +41,6 @@
40
41
  "types": "./autocomplete/index.d.ts",
41
42
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs"
42
43
  },
43
- "./file-upload": {
44
- "types": "./file-upload/index.d.ts",
45
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs"
46
- },
47
44
  "./directives": {
48
45
  "types": "./directives/index.d.ts",
49
46
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-directives.mjs"
@@ -52,45 +49,53 @@
52
49
  "types": "./datepicker/index.d.ts",
53
50
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs"
54
51
  },
52
+ "./dropdown": {
53
+ "types": "./dropdown/index.d.ts",
54
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs"
55
+ },
56
+ "./file-upload": {
57
+ "types": "./file-upload/index.d.ts",
58
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs"
59
+ },
55
60
  "./footer": {
56
61
  "types": "./footer/index.d.ts",
57
62
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-footer.mjs"
58
63
  },
59
- "./navbar": {
60
- "types": "./navbar/index.d.ts",
61
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs"
62
- },
63
64
  "./loading": {
64
65
  "types": "./loading/index.d.ts",
65
66
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-loading.mjs"
66
67
  },
68
+ "./navbar": {
69
+ "types": "./navbar/index.d.ts",
70
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs"
71
+ },
67
72
  "./overlay": {
68
73
  "types": "./overlay/index.d.ts",
69
74
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs"
70
75
  },
71
- "./sidebar": {
72
- "types": "./sidebar/index.d.ts",
73
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs"
74
- },
75
76
  "./password-strength": {
76
77
  "types": "./password-strength/index.d.ts",
77
78
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs"
78
79
  },
80
+ "./progress": {
81
+ "types": "./progress/index.d.ts",
82
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-progress.mjs"
83
+ },
79
84
  "./select": {
80
85
  "types": "./select/index.d.ts",
81
86
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-select.mjs"
82
87
  },
83
- "./tiff-viewer": {
84
- "types": "./tiff-viewer/index.d.ts",
85
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs"
88
+ "./sidebar": {
89
+ "types": "./sidebar/index.d.ts",
90
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs"
86
91
  },
87
92
  "./toast": {
88
93
  "types": "./toast/index.d.ts",
89
94
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-toast.mjs"
90
95
  },
91
- "./progress": {
92
- "types": "./progress/index.d.ts",
93
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-progress.mjs"
96
+ "./tiff-viewer": {
97
+ "types": "./tiff-viewer/index.d.ts",
98
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs"
94
99
  }
95
100
  }
96
101
  }
package/select/index.d.ts CHANGED
@@ -19,7 +19,7 @@ declare class YsSelectComponent implements ControlValueAccessor {
19
19
  /**Size of multiple attribute */
20
20
  size?: number;
21
21
  /**Display clear button */
22
- isClear?: boolean;
22
+ showClear?: boolean;
23
23
  disabled: boolean;
24
24
  selected: EventEmitter<any>;
25
25
  onChange: any;
@@ -33,7 +33,7 @@ declare class YsSelectComponent implements ControlValueAccessor {
33
33
  clearValue(): void;
34
34
  isObject(item: any): boolean;
35
35
  static ɵfac: i0.ɵɵFactoryDeclaration<YsSelectComponent, never>;
36
- static ɵcmp: i0.ɵɵComponentDeclaration<YsSelectComponent, "ys-select", never, { "id": { "alias": "id"; "required": false; }; "options": { "alias": "options"; "required": false; }; "optionLabel": { "alias": "optionLabel"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "styleClass": { "alias": "styleClass"; "required": false; }; "invalid": { "alias": "invalid"; "required": false; }; "invalidFeedback": { "alias": "invalidFeedback"; "required": false; }; "valid": { "alias": "valid"; "required": false; }; "validFeedback": { "alias": "validFeedback"; "required": false; }; "multiple": { "alias": "multiple"; "required": false; }; "size": { "alias": "size"; "required": false; }; "isClear": { "alias": "isClear"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "selected": "selected"; }, never, never, true, never>;
36
+ static ɵcmp: i0.ɵɵComponentDeclaration<YsSelectComponent, "ys-select", never, { "id": { "alias": "id"; "required": false; }; "options": { "alias": "options"; "required": false; }; "optionLabel": { "alias": "optionLabel"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "styleClass": { "alias": "styleClass"; "required": false; }; "invalid": { "alias": "invalid"; "required": false; }; "invalidFeedback": { "alias": "invalidFeedback"; "required": false; }; "valid": { "alias": "valid"; "required": false; }; "validFeedback": { "alias": "validFeedback"; "required": false; }; "multiple": { "alias": "multiple"; "required": false; }; "size": { "alias": "size"; "required": false; }; "showClear": { "alias": "showClear"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "selected": "selected"; }, never, never, true, never>;
37
37
  }
38
38
 
39
39
  export { YsSelectComponent };