@yoozsoft/yoozsoft-ng 5.1.2 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,32 +102,36 @@ 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
  }
113
+ if (!this.multiple && !term) {
114
+ this.clearSelection();
115
+ }
110
116
  }
111
117
  getLabel(item) {
112
118
  if (!item)
113
119
  return '';
114
120
  if (typeof item === 'string')
115
121
  return item;
116
- if (item && this.labelField && item[this.labelField]) {
117
- return item[this.labelField];
122
+ if (item && this.optionLabel && item[this.optionLabel]) {
123
+ return item[this.optionLabel];
118
124
  }
119
125
  return '';
120
126
  }
121
127
  onSelect(item) {
122
128
  if (this.multiple) {
123
- 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));
124
130
  if (!exists) {
125
- this.selectedItems.push(item);
126
- this.onChange(this.selectedItems);
127
- this.selected.emit(this.selectedItems);
131
+ this.selectedOptions.push(item);
132
+ this._onChange(this.selectedOptions);
133
+ this._onTouched();
134
+ this.selected.emit(this.selectedOptions);
128
135
  }
129
136
  this.searchTerm = '';
130
137
  this.showDropdown = true;
@@ -132,16 +139,17 @@ class YsAutocompleteComponent {
132
139
  }
133
140
  else {
134
141
  this.searchTerm = this.getLabel(item);
135
- this.onChange(item);
142
+ this._onChange(item);
143
+ this._onTouched();
136
144
  this.selected.emit(item);
137
145
  this.showDropdown = false;
138
146
  }
139
147
  this.activeIndex = -1;
140
148
  }
141
149
  removeItem(item) {
142
- this.selectedItems = this.selectedItems.filter((x) => this.getLabel(x) !== this.getLabel(item));
143
- this.onChange(this.selectedItems);
144
- 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);
145
153
  }
146
154
  onScroll(event) {
147
155
  if (!this.infiniteScroll || this.loading)
@@ -155,36 +163,35 @@ class YsAutocompleteComponent {
155
163
  }
156
164
  clearSelection() {
157
165
  if (this.multiple) {
158
- this.selectedItems = [];
159
- this.onChange(this.selectedItems);
160
- this.removed.emit(this.selectedItems);
166
+ this.selectedOptions = [];
167
+ this._onChange(this.selectedOptions);
168
+ this.removed.emit(this.selectedOptions);
161
169
  }
162
170
  else {
163
171
  this.searchTerm = '';
164
- this.onChange(null);
172
+ this._onChange(null);
165
173
  this.selected.emit(null);
166
174
  }
167
- this.filteredItems = [];
168
175
  this.showDropdown = false;
169
176
  }
170
177
  /** Keyboard control */
171
178
  handleKeyboard(event) {
172
- if (!this.showDropdown || this.filteredItems.length === 0)
179
+ if (!this.showDropdown || this.filteredOptions.length === 0)
173
180
  return;
174
181
  switch (event.key) {
175
182
  case 'ArrowDown':
176
- this.activeIndex = (this.activeIndex + 1) % this.filteredItems.length;
183
+ this.activeIndex = (this.activeIndex + 1) % this.filteredOptions.length;
177
184
  event.preventDefault();
178
185
  break;
179
186
  case 'ArrowUp':
180
187
  this.activeIndex =
181
- (this.activeIndex - 1 + this.filteredItems.length) %
182
- this.filteredItems.length;
188
+ (this.activeIndex - 1 + this.filteredOptions.length) %
189
+ this.filteredOptions.length;
183
190
  event.preventDefault();
184
191
  break;
185
192
  case 'Enter':
186
193
  if (this.activeIndex >= 0) {
187
- this.onSelect(this.filteredItems[this.activeIndex]);
194
+ this.onSelect(this.filteredOptions[this.activeIndex]);
188
195
  event.preventDefault();
189
196
  }
190
197
  break;
@@ -201,13 +208,13 @@ class YsAutocompleteComponent {
201
208
  }
202
209
  }
203
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 });
204
- 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: [
205
212
  {
206
213
  provide: NG_VALUE_ACCESSOR,
207
214
  useExisting: forwardRef(() => YsAutocompleteComponent),
208
215
  multi: true,
209
216
  },
210
- ], 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 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-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\">\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 } @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"] }] });
211
218
  }
212
219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsAutocompleteComponent, decorators: [{
213
220
  type: Component,
@@ -217,16 +224,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
217
224
  useExisting: forwardRef(() => YsAutocompleteComponent),
218
225
  multi: true,
219
226
  },
220
- ], 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 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-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\">\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 } @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"] }]
221
- }], 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: [{
222
229
  type: Input
223
- }], labelField: [{
230
+ }], optionLabel: [{
224
231
  type: Input
225
232
  }], placeholder: [{
226
233
  type: Input
227
234
  }], multiple: [{
228
235
  type: Input
229
- }], isClear: [{
236
+ }], showClear: [{
230
237
  type: Input
231
238
  }], disabled: [{
232
239
  type: Input
@@ -245,6 +252,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
245
252
  type: Input
246
253
  }], infiniteScroll: [{
247
254
  type: Input
255
+ }], virtualScroll: [{
256
+ type: Input
257
+ }], virtualScrollItemSize: [{
258
+ type: Input
248
259
  }], loadMore: [{
249
260
  type: Output
250
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\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.filteredItems = [];\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 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-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\">\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 } @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 = true;
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(isSelected(option)){\r\n <i class=\"fa fa-check text-success ms-auto\"></i>\r\n }\r\n {{option[optionLabel]}}\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(isSelected(option)){\r\n <i class=\"fa fa-check text-success ms-auto\"></i>\r\n }\r\n {{option[optionLabel]}}\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 = true;\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(isSelected(option)){\r\n <i class=\"fa fa-check text-success ms-auto\"></i>\r\n }\r\n {{option[optionLabel]}}\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.2",
3
+ "version": "5.2.0",
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,14 +41,18 @@
40
41
  "types": "./autocomplete/index.d.ts",
41
42
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs"
42
43
  },
43
- "./directives": {
44
- "types": "./directives/index.d.ts",
45
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-directives.mjs"
46
- },
47
44
  "./datepicker": {
48
45
  "types": "./datepicker/index.d.ts",
49
46
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs"
50
47
  },
48
+ "./dropdown": {
49
+ "types": "./dropdown/index.d.ts",
50
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs"
51
+ },
52
+ "./directives": {
53
+ "types": "./directives/index.d.ts",
54
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-directives.mjs"
55
+ },
51
56
  "./file-upload": {
52
57
  "types": "./file-upload/index.d.ts",
53
58
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs"
@@ -56,34 +61,30 @@
56
61
  "types": "./footer/index.d.ts",
57
62
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-footer.mjs"
58
63
  },
59
- "./loading": {
60
- "types": "./loading/index.d.ts",
61
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-loading.mjs"
62
- },
63
64
  "./navbar": {
64
65
  "types": "./navbar/index.d.ts",
65
66
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs"
66
67
  },
68
+ "./loading": {
69
+ "types": "./loading/index.d.ts",
70
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-loading.mjs"
71
+ },
67
72
  "./overlay": {
68
73
  "types": "./overlay/index.d.ts",
69
74
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs"
70
75
  },
71
- "./password-strength": {
72
- "types": "./password-strength/index.d.ts",
73
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs"
74
- },
75
76
  "./progress": {
76
77
  "types": "./progress/index.d.ts",
77
78
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-progress.mjs"
78
79
  },
80
+ "./password-strength": {
81
+ "types": "./password-strength/index.d.ts",
82
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs"
83
+ },
79
84
  "./select": {
80
85
  "types": "./select/index.d.ts",
81
86
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-select.mjs"
82
87
  },
83
- "./sidebar": {
84
- "types": "./sidebar/index.d.ts",
85
- "default": "./fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs"
86
- },
87
88
  "./tiff-viewer": {
88
89
  "types": "./tiff-viewer/index.d.ts",
89
90
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs"
@@ -91,6 +92,10 @@
91
92
  "./toast": {
92
93
  "types": "./toast/index.d.ts",
93
94
  "default": "./fesm2022/yoozsoft-yoozsoft-ng-toast.mjs"
95
+ },
96
+ "./sidebar": {
97
+ "types": "./sidebar/index.d.ts",
98
+ "default": "./fesm2022/yoozsoft-yoozsoft-ng-sidebar.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 };