@yoozsoft/yoozsoft-ng 5.3.5 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +143 -24
  2. package/assets/js/UTIF.js-master/LICENSE +21 -21
  3. package/assets/js/UTIF.js-master/README.md +72 -72
  4. package/assets/js/UTIF.js-master/UTIF.js +1762 -1762
  5. package/assets/js/UTIF.js-master/package-lock.json +13 -13
  6. package/assets/js/UTIF.js-master/package.json +24 -0
  7. package/assets/styles/components/_ys-navbar.scss +22 -0
  8. package/assets/styles/components/_ys-pagination.scss +10 -0
  9. package/assets/styles/{ys-layout.scss → utilities/ys-layout.scss} +1 -1
  10. package/assets/styles/ys-styles.scss +2 -0
  11. package/autocomplete/package.json +4 -0
  12. package/date/package.json +4 -0
  13. package/datepicker/package.json +4 -0
  14. package/dropdown/package.json +4 -0
  15. package/fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs +257 -197
  16. package/fesm2022/yoozsoft-yoozsoft-ng-autocomplete.mjs.map +1 -1
  17. package/fesm2022/yoozsoft-yoozsoft-ng-date.mjs +562 -0
  18. package/fesm2022/yoozsoft-yoozsoft-ng-date.mjs.map +1 -0
  19. package/fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs +600 -837
  20. package/fesm2022/yoozsoft-yoozsoft-ng-datepicker.mjs.map +1 -1
  21. package/fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs +161 -151
  22. package/fesm2022/yoozsoft-yoozsoft-ng-dropdown.mjs.map +1 -1
  23. package/fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs +93 -103
  24. package/fesm2022/yoozsoft-yoozsoft-ng-file-upload.mjs.map +1 -1
  25. package/fesm2022/yoozsoft-yoozsoft-ng-footer.mjs +16 -21
  26. package/fesm2022/yoozsoft-yoozsoft-ng-footer.mjs.map +1 -1
  27. package/fesm2022/yoozsoft-yoozsoft-ng-loading.mjs +20 -24
  28. package/fesm2022/yoozsoft-yoozsoft-ng-loading.mjs.map +1 -1
  29. package/fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs +60 -76
  30. package/fesm2022/yoozsoft-yoozsoft-ng-navbar.mjs.map +1 -1
  31. package/fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs +11 -15
  32. package/fesm2022/yoozsoft-yoozsoft-ng-overlay.mjs.map +1 -1
  33. package/fesm2022/yoozsoft-yoozsoft-ng-pagination.mjs +61 -55
  34. package/fesm2022/yoozsoft-yoozsoft-ng-pagination.mjs.map +1 -1
  35. package/fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs +142 -130
  36. package/fesm2022/yoozsoft-yoozsoft-ng-password-strength.mjs.map +1 -1
  37. package/fesm2022/yoozsoft-yoozsoft-ng-pipes.mjs +44 -0
  38. package/fesm2022/yoozsoft-yoozsoft-ng-pipes.mjs.map +1 -0
  39. package/fesm2022/yoozsoft-yoozsoft-ng-progress.mjs +51 -34
  40. package/fesm2022/yoozsoft-yoozsoft-ng-progress.mjs.map +1 -1
  41. package/fesm2022/yoozsoft-yoozsoft-ng-rating.mjs +155 -0
  42. package/fesm2022/yoozsoft-yoozsoft-ng-rating.mjs.map +1 -0
  43. package/fesm2022/yoozsoft-yoozsoft-ng-select.mjs +78 -80
  44. package/fesm2022/yoozsoft-yoozsoft-ng-select.mjs.map +1 -1
  45. package/fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs +99 -99
  46. package/fesm2022/yoozsoft-yoozsoft-ng-sidebar.mjs.map +1 -1
  47. package/fesm2022/yoozsoft-yoozsoft-ng-table.mjs +316 -0
  48. package/fesm2022/yoozsoft-yoozsoft-ng-table.mjs.map +1 -0
  49. package/fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs +128 -114
  50. package/fesm2022/yoozsoft-yoozsoft-ng-tiff-viewer.mjs.map +1 -1
  51. package/fesm2022/yoozsoft-yoozsoft-ng-toast.mjs +112 -62
  52. package/fesm2022/yoozsoft-yoozsoft-ng-toast.mjs.map +1 -1
  53. package/fesm2022/yoozsoft-yoozsoft-ng-validators.mjs +37 -0
  54. package/fesm2022/yoozsoft-yoozsoft-ng-validators.mjs.map +1 -0
  55. package/fesm2022/yoozsoft-yoozsoft-ng.mjs.map +1 -1
  56. package/file-upload/package.json +4 -0
  57. package/footer/package.json +4 -0
  58. package/loading/package.json +4 -0
  59. package/navbar/package.json +4 -0
  60. package/overlay/package.json +4 -0
  61. package/package.json +61 -38
  62. package/pagination/package.json +4 -0
  63. package/password-strength/package.json +4 -0
  64. package/pipes/package.json +4 -0
  65. package/progress/package.json +4 -0
  66. package/rating/package.json +4 -0
  67. package/select/package.json +4 -0
  68. package/sidebar/package.json +4 -0
  69. package/table/package.json +4 -0
  70. package/tiff-viewer/package.json +4 -0
  71. package/toast/package.json +4 -0
  72. package/types/yoozsoft-yoozsoft-ng-autocomplete.d.ts +79 -0
  73. package/types/yoozsoft-yoozsoft-ng-date.d.ts +118 -0
  74. package/types/yoozsoft-yoozsoft-ng-datepicker.d.ts +120 -0
  75. package/types/yoozsoft-yoozsoft-ng-dropdown.d.ts +76 -0
  76. package/types/yoozsoft-yoozsoft-ng-file-upload.d.ts +75 -0
  77. package/types/yoozsoft-yoozsoft-ng-footer.d.ts +26 -0
  78. package/types/yoozsoft-yoozsoft-ng-loading.d.ts +14 -0
  79. package/types/yoozsoft-yoozsoft-ng-navbar.d.ts +60 -0
  80. package/types/yoozsoft-yoozsoft-ng-overlay.d.ts +10 -0
  81. package/types/yoozsoft-yoozsoft-ng-pagination.d.ts +31 -0
  82. package/types/yoozsoft-yoozsoft-ng-password-strength.d.ts +73 -0
  83. package/types/yoozsoft-yoozsoft-ng-pipes.d.ts +11 -0
  84. package/types/yoozsoft-yoozsoft-ng-progress.d.ts +31 -0
  85. package/types/yoozsoft-yoozsoft-ng-rating.d.ts +56 -0
  86. package/types/yoozsoft-yoozsoft-ng-select.d.ts +43 -0
  87. package/types/yoozsoft-yoozsoft-ng-sidebar.d.ts +69 -0
  88. package/types/yoozsoft-yoozsoft-ng-table.d.ts +137 -0
  89. package/types/yoozsoft-yoozsoft-ng-tiff-viewer.d.ts +53 -0
  90. package/types/yoozsoft-yoozsoft-ng-toast.d.ts +66 -0
  91. package/types/yoozsoft-yoozsoft-ng-validators.d.ts +5 -0
  92. package/validators/package.json +4 -0
  93. package/autocomplete/index.d.ts +0 -71
  94. package/datepicker/index.d.ts +0 -291
  95. package/directives/index.d.ts +0 -17
  96. package/dropdown/index.d.ts +0 -62
  97. package/fesm2022/yoozsoft-yoozsoft-ng-directives.mjs +0 -57
  98. package/fesm2022/yoozsoft-yoozsoft-ng-directives.mjs.map +0 -1
  99. package/file-upload/index.d.ts +0 -72
  100. package/footer/index.d.ts +0 -25
  101. package/loading/index.d.ts +0 -13
  102. package/navbar/index.d.ts +0 -56
  103. package/overlay/index.d.ts +0 -11
  104. package/pagination/index.d.ts +0 -29
  105. package/password-strength/index.d.ts +0 -84
  106. package/progress/index.d.ts +0 -28
  107. package/select/index.d.ts +0 -39
  108. package/sidebar/index.d.ts +0 -94
  109. package/tiff-viewer/index.d.ts +0 -52
  110. package/toast/index.d.ts +0 -53
  111. /package/assets/styles/{ys-preloader-9.scss → preloaders/ys-preloader-9.scss} +0 -0
  112. /package/assets/styles/{ys-preloader.scss → preloaders/ys-preloader.scss} +0 -0
  113. /package/{index.d.ts → types/yoozsoft-yoozsoft-ng.d.ts} +0 -0
@@ -1,45 +1,101 @@
1
- import { NgTemplateOutlet } from '@angular/common';
1
+ import { isPlatformBrowser, NgTemplateOutlet, NgClass } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { EventEmitter, inject, ElementRef, forwardRef, HostListener, Output, Input, Component } from '@angular/core';
3
+ import { inject, ElementRef, PLATFORM_ID, input, output, signal, computed, effect, forwardRef, HostListener, ChangeDetectionStrategy, Component } from '@angular/core';
4
4
  import * as i1 from '@angular/forms';
5
5
  import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
 
7
- class YsDropdownComponent {
8
- /** لیست گزینه‌ها */
9
- _options = [];
10
- set options(value) { this._options = this.normalizeOptions(value); }
11
- get options() { return this._options; }
12
- optionLabel = 'label';
13
- placeholder = '';
14
- searchPlaceholder = '';
15
- selectedMaxLength = 3;
16
- selectedMaxLengthTemplate = '{length} items selected';
17
- selectionSeparator = ", ";
18
- /** انتخاب چندگانه یا تکی */
19
- multiple = false;
20
- showClear = false;
21
- /** تمپلیت سفارشی برای آیتم‌ها */
22
- itemTemplate;
23
- /** مقدار انتخاب‌شده */
24
- selected = this.multiple ? [] : null;
25
- /** قابلیت جستجو */
26
- searchable = false;
27
- disabled = false;
28
- /** رویداد خروجی هنگام تغییر انتخاب */
29
- selectionChange = new EventEmitter();
30
- searchTerm = '';
31
- isOpen = false;
32
- highlightedIndex = -1;
7
+ class YsDropdown {
33
8
  elRef = inject(ElementRef);
34
- _onChange = () => { };
35
- _onTouched = () => { };
36
- writeValue(obj) {
37
- if (this.multiple) {
38
- this.selected = obj ? [...obj] : [];
9
+ platformId = inject(PLATFORM_ID);
10
+ /** List of options */
11
+ options = input([], /* @ts-ignore */
12
+ ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
13
+ /** Field of object that display as label */
14
+ optionLabel = input('label', /* @ts-ignore */
15
+ ...(ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []));
16
+ placeholder = input('', /* @ts-ignore */
17
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
18
+ searchPlaceholder = input('', /* @ts-ignore */
19
+ ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
20
+ selectedMaxLength = input(3, /* @ts-ignore */
21
+ ...(ngDevMode ? [{ debugName: "selectedMaxLength" }] : /* istanbul ignore next */ []));
22
+ selectedMaxLengthTemplate = input('{length} items selected', /* @ts-ignore */
23
+ ...(ngDevMode ? [{ debugName: "selectedMaxLengthTemplate" }] : /* istanbul ignore next */ []));
24
+ selectionSeparator = input(', ', /* @ts-ignore */
25
+ ...(ngDevMode ? [{ debugName: "selectionSeparator" }] : /* istanbul ignore next */ []));
26
+ dropDownToggleIconClass = input('fa fa-chevron-down', /* @ts-ignore */
27
+ ...(ngDevMode ? [{ debugName: "dropDownToggleIconClass" }] : /* istanbul ignore next */ []));
28
+ clearIconClass = input('fa fa-times', /* @ts-ignore */
29
+ ...(ngDevMode ? [{ debugName: "clearIconClass" }] : /* istanbul ignore next */ []));
30
+ multipleCheckIconClass = input('fa fa-check', /* @ts-ignore */
31
+ ...(ngDevMode ? [{ debugName: "multipleCheckIconClass" }] : /* istanbul ignore next */ []));
32
+ /** Multiple choice mode */
33
+ multiple = input(false, /* @ts-ignore */
34
+ ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
35
+ showClear = input(false, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
37
+ /** Search capability */
38
+ searchable = input(false, /* @ts-ignore */
39
+ ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
40
+ disabled = input(false, /* @ts-ignore */
41
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
42
+ /** Custom template for items */
43
+ itemTemplate = input(/* @ts-ignore */
44
+ ...(ngDevMode ? [undefined, { debugName: "itemTemplate" }] : /* istanbul ignore next */ []));
45
+ /** Output event when selection changes */
46
+ selectionChange = output();
47
+ searchTerm = signal('', /* @ts-ignore */
48
+ ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
49
+ isOpen = signal(false, /* @ts-ignore */
50
+ ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
51
+ highlightedIndex = signal(-1, /* @ts-ignore */
52
+ ...(ngDevMode ? [{ debugName: "highlightedIndex" }] : /* istanbul ignore next */ []));
53
+ /** Selected value */
54
+ selected = signal(null, /* @ts-ignore */
55
+ ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
56
+ disabledState = signal(false, /* @ts-ignore */
57
+ ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
58
+ isDisabled = computed(() => this.disabled() || this.disabledState(), /* @ts-ignore */
59
+ ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
60
+ filteredOptions = computed(() => {
61
+ if (!this.searchable() || !this.searchTerm().trim()) {
62
+ return this.normalizedOptions();
39
63
  }
40
- else {
41
- this.selected = obj;
64
+ const term = this.searchTerm().toLowerCase();
65
+ return this.normalizedOptions().filter((opt) => opt.label.toLowerCase().includes(term));
66
+ }, /* @ts-ignore */
67
+ ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
68
+ normalizedOptions = computed(() => this.normalizeOptions(this.options()), /* @ts-ignore */
69
+ ...(ngDevMode ? [{ debugName: "normalizedOptions" }] : /* istanbul ignore next */ []));
70
+ hasSelection = computed(() => this.multiple()
71
+ ? Array.isArray(this.selected()) && this.selected().length > 0
72
+ : !!this.selected(), /* @ts-ignore */
73
+ ...(ngDevMode ? [{ debugName: "hasSelection" }] : /* istanbul ignore next */ []));
74
+ selectedLabels = computed(() => {
75
+ if (this.multiple()) {
76
+ if (!Array.isArray(this.selected()))
77
+ return '';
78
+ // لیست object های انتخابی را پیدا می‌کنیم
79
+ const selectedItems = this.normalizedOptions().filter((o) => this.selected().includes(o.value));
80
+ const count = selectedItems.length;
81
+ // اگر بیشتر از حد مجاز باشد → متن سفارشی
82
+ if (count > this.selectedMaxLength()) {
83
+ return this.selectedMaxLengthTemplate().replace('{length}', count + '');
84
+ }
85
+ // در غیر این‌صورت لیبل‌ها را نمایش بده
86
+ return selectedItems.map((o) => o.label).join(this.selectionSeparator());
42
87
  }
88
+ const item = this.normalizedOptions().find((o) => o.value === this.selected());
89
+ return item?.label ?? '';
90
+ }, /* @ts-ignore */
91
+ ...(ngDevMode ? [{ debugName: "selectedLabels" }] : /* istanbul ignore next */ []));
92
+ _onChange = (_) => { };
93
+ _onTouched = () => { };
94
+ constructor() {
95
+ effect(() => this.selected.set(this.multiple() ? [] : null));
96
+ }
97
+ writeValue(obj) {
98
+ this.selected.set(this.multiple() ? (Array.isArray(obj) ? obj : []) : obj);
43
99
  }
44
100
  registerOnChange(fn) {
45
101
  this._onChange = fn;
@@ -48,201 +104,155 @@ class YsDropdownComponent {
48
104
  this._onTouched = fn;
49
105
  }
50
106
  setDisabledState(isDisabled) {
51
- this.disabled = isDisabled;
107
+ this.disabledState.set(isDisabled);
52
108
  }
53
109
  normalizeOptions(list) {
54
110
  if (!Array.isArray(list))
55
111
  return [];
56
- return list.map(item => {
112
+ return list.map((item) => {
57
113
  // 1. اگر primitive بود
58
114
  if (['string', 'number', 'boolean'].includes(typeof item)) {
59
115
  return {
60
116
  raw: item,
61
117
  label: String(item),
62
- value: item
118
+ value: item,
119
+ disabled: false,
63
120
  };
64
121
  }
65
122
  // 2. اگر OptionItem<T> بود
66
- if ('value' in item) {
123
+ if (item && typeof item === 'object' && 'value' in item) {
67
124
  return {
68
125
  raw: item,
69
126
  label: item.label ?? String(item.value),
70
127
  value: item.value,
71
- ...item
128
+ disabled: item.disabled,
129
+ ...item,
72
130
  };
73
131
  }
74
132
  // 3. object معمولی
75
133
  return {
76
134
  raw: item,
77
- label: item[this.optionLabel] ?? JSON.stringify(item),
78
- value: item
135
+ label: item[this.optionLabel()] ?? JSON.stringify(item),
136
+ value: item,
137
+ disabled: false,
79
138
  };
80
139
  });
81
140
  }
82
- get selectedLabels() {
83
- if (this.multiple) {
84
- if (!Array.isArray(this.selected))
85
- return '';
86
- // لیست object های انتخابی را پیدا می‌کنیم
87
- const selectedItems = this.options.filter(o => this.selected.includes(o.value));
88
- const count = selectedItems.length;
89
- // اگر بیشتر از حد مجاز باشد → متن سفارشی
90
- if (count > this.selectedMaxLength) {
91
- return this.selectedMaxLengthTemplate.replace('{length}', count + '');
92
- }
93
- // در غیر این‌صورت لیبل‌ها را نمایش بده
94
- return selectedItems.map(o => o.label).join(this.selectionSeparator);
95
- }
96
- const item = this.options.find(o => o.value === this.selected);
97
- return item?.label ?? '';
98
- }
99
141
  toggleDropdown() {
100
- this.isOpen = !this.isOpen;
101
- if (this.isOpen) {
102
- this.highlightedIndex = -1;
103
- }
104
- }
105
- filterOptions() {
106
- let list = this.options;
107
- if (this.searchable && this.searchTerm.trim()) {
108
- const term = this.searchTerm.toLowerCase();
109
- list = this.options.filter(opt => opt[this.optionLabel].toLowerCase().includes(term));
110
- }
111
- // هر بار جستجو انجام شد index ریست بشه
112
- this.highlightedIndex = Math.min(this.highlightedIndex, list.length - 1);
113
- return list;
142
+ this.isOpen.update((v) => !v);
143
+ this.highlightedIndex.set(-1);
114
144
  }
115
145
  selectOption(option) {
116
146
  if (option.disabled)
117
147
  return;
118
- const returnedValue = option.value; // مقدار نهایی برای فرم
119
- if (this.multiple) {
120
- const exists = this.selected?.some((x) => x === returnedValue);
121
- this.selected = exists
122
- ? this.selected.filter((x) => x !== returnedValue)
123
- : [...(this.selected || []), returnedValue];
148
+ const value = option.value;
149
+ if (this.multiple()) {
150
+ this.selected.update((list) => list?.includes(value) ? list.filter((x) => x !== value) : [...(list || []), value]);
124
151
  }
125
152
  else {
126
- this.selected = returnedValue;
127
- this.isOpen = false;
153
+ this.selected.set(value);
154
+ this.isOpen.set(false);
128
155
  }
129
- this._onChange(this.selected);
130
- this.selectionChange.emit(this.selected);
156
+ this._onChange(this.selected());
157
+ this.selectionChange.emit(this.selected());
158
+ this._onTouched();
131
159
  }
132
160
  isSelected(option) {
133
- if (this.multiple) {
134
- return Array.isArray(this.selected)
135
- ? this.selected.includes(option.value)
136
- : false;
161
+ if (this.multiple()) {
162
+ return Array.isArray(this.selected()) ? this.selected().includes(option.value) : false;
137
163
  }
138
- return this.selected === option.value;
164
+ return this.selected() === option.value;
139
165
  }
140
166
  clearSelection() {
141
- this.selected = this.multiple ? [] : null;
142
- this._onChange(this.selected);
167
+ this.selected.set(this.multiple() ? [] : null);
168
+ this._onChange(this.selected());
169
+ this.selectionChange.emit(this.selected());
143
170
  this._onTouched();
144
- this.selectionChange.emit(this.selected);
145
171
  }
146
172
  onKeyDown(event) {
147
- const filtered = this.filterOptions();
148
- if (!filtered.length)
173
+ const list = this.filteredOptions();
174
+ if (!list.length)
149
175
  return;
150
176
  switch (event.key) {
151
177
  case 'ArrowDown':
152
178
  event.preventDefault();
153
- this.highlightedIndex = (this.highlightedIndex + 1) % filtered.length;
179
+ this.highlightedIndex.update((i) => (i + 1) % list.length);
154
180
  this.scrollToHighlighted();
155
181
  break;
156
182
  case 'ArrowUp':
157
183
  event.preventDefault();
158
- this.highlightedIndex = this.highlightedIndex > 0 ? this.highlightedIndex - 1 : filtered.length - 1;
184
+ this.highlightedIndex.update((i) => (i > 0 ? i - 1 : list.length - 1));
159
185
  this.scrollToHighlighted();
160
186
  break;
161
187
  case 'Enter':
162
188
  event.preventDefault();
163
- if (this.highlightedIndex >= 0 && this.highlightedIndex < filtered.length) {
164
- this.selectOption(filtered[this.highlightedIndex]);
189
+ if (!this.isOpen()) {
190
+ this.isOpen.set(true);
191
+ return;
165
192
  }
193
+ const idx = this.highlightedIndex();
194
+ if (idx >= 0)
195
+ this.selectOption(list[idx]);
196
+ break;
197
+ case 'Tab':
198
+ this.isOpen.set(false);
166
199
  break;
167
200
  case 'Escape':
168
- this.isOpen = false;
201
+ this.isOpen.set(false);
169
202
  break;
170
203
  }
171
204
  }
172
205
  scrollToHighlighted() {
173
- // تأخیر جزئی برای اطمینان از رندر کامل
174
- setTimeout(() => {
206
+ if (!isPlatformBrowser(this.platformId))
207
+ return;
208
+ queueMicrotask(() => {
175
209
  const dropdown = this.elRef.nativeElement.querySelector('.dropdown-menu');
176
210
  const items = dropdown?.querySelectorAll('.dropdown-item');
177
- const activeItem = items?.[this.highlightedIndex];
178
- if (activeItem && dropdown) {
179
- const itemTop = activeItem.offsetTop;
180
- const itemBottom = itemTop + activeItem.offsetHeight;
181
- const dropdownScrollTop = dropdown.scrollTop;
182
- const dropdownHeight = dropdown.clientHeight;
183
- if (itemBottom > dropdownScrollTop + dropdownHeight) {
184
- dropdown.scrollTop = itemBottom - dropdownHeight;
185
- }
186
- else if (itemTop < dropdownScrollTop) {
187
- dropdown.scrollTop = itemTop;
188
- }
211
+ const activeItem = items?.[this.highlightedIndex()];
212
+ if (!activeItem || !dropdown)
213
+ return;
214
+ const itemTop = activeItem.offsetTop;
215
+ const itemBottom = itemTop + activeItem.offsetHeight;
216
+ const dropdownScrollTop = dropdown.scrollTop;
217
+ const dropdownHeight = dropdown.clientHeight;
218
+ if (itemBottom > dropdownScrollTop + dropdownHeight) {
219
+ dropdown.scrollTop = itemBottom - dropdownHeight;
220
+ }
221
+ else if (itemTop < dropdownScrollTop) {
222
+ dropdown.scrollTop = itemTop;
189
223
  }
190
224
  });
191
225
  }
192
226
  /** Close by clicking outside */
193
227
  onClickOutside(event) {
228
+ if (!isPlatformBrowser(this.platformId))
229
+ return;
230
+ if (!this.isOpen())
231
+ return;
194
232
  const clickedInside = this.elRef.nativeElement.contains(event.target);
195
233
  if (!clickedInside) {
196
- this.isOpen = false;
234
+ this.isOpen.set(false);
197
235
  }
198
236
  }
199
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
200
- 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: [
237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: YsDropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: YsDropdown, isStandalone: true, selector: "ys-dropdown", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, selectedMaxLength: { classPropertyName: "selectedMaxLength", publicName: "selectedMaxLength", isSignal: true, isRequired: false, transformFunction: null }, selectedMaxLengthTemplate: { classPropertyName: "selectedMaxLengthTemplate", publicName: "selectedMaxLengthTemplate", isSignal: true, isRequired: false, transformFunction: null }, selectionSeparator: { classPropertyName: "selectionSeparator", publicName: "selectionSeparator", isSignal: true, isRequired: false, transformFunction: null }, dropDownToggleIconClass: { classPropertyName: "dropDownToggleIconClass", publicName: "dropDownToggleIconClass", isSignal: true, isRequired: false, transformFunction: null }, clearIconClass: { classPropertyName: "clearIconClass", publicName: "clearIconClass", isSignal: true, isRequired: false, transformFunction: null }, multipleCheckIconClass: { classPropertyName: "multipleCheckIconClass", publicName: "multipleCheckIconClass", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
201
239
  {
202
240
  provide: NG_VALUE_ACCESSOR,
203
- useExisting: forwardRef(() => YsDropdownComponent),
241
+ useExisting: forwardRef(() => YsDropdown),
204
242
  multi: true,
205
243
  },
206
- ], 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)\" [disabled]=\"disabled\" />\r\n\r\n @if(showClear && (multiple ? selected?.length > 0 : selected)){\r\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\" [disabled]=\"disabled\">\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 [disabled]=\"disabled\">\r\n <i class=\"fa fa-chevron-down\"></i>\r\n </button>\r\n </div>\r\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen\">\r\n\r\n @if(searchable){\r\n <div class=\"px-2\">\r\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder\" [(ngModel)]=\"searchTerm\"\r\n (keydown)=\"onKeyDown($event)\">\r\n </div>\r\n }\r\n\r\n @for (option of filterOptions(); track $index) {\r\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\r\n [class.highlighted]=\"$index === highlightedIndex\">\r\n @if(itemTemplate){\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{ option: option }\">\r\n </ng-container>\r\n }\r\n @else {\r\n @if(multiple){\r\n <i class=\"fa fa-check text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\r\n }\r\n <!-- <span>{{option[optionLabel]}}</span> -->\r\n <span>{{option.label}}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [".ys-dropdown .dropdown-toggle:after{display:none}.ys-dropdown .dropdown-menu{max-height:200px}.ys-dropdown .dropdown-item.highlighted{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
244
+ ], ngImport: i0, template: "<div class=\"dropdown ys-dropdown\">\n <div class=\"input-group w-100\">\n <input #inputRef type=\"text\" class=\"form-control\" [value]=\"selectedLabels()\" [placeholder]=\"placeholder()\"\n readonly (click)=\"isOpen.set(true)\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled()\" />\n <!-- (focus)=\"isOpen.set(true)\" replace with (click)=\"isOpen.set(true)\" (keydown.enter)=\"isOpen.set(true)\" -->\n\n @if(showClear() && hasSelection()){\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\" [disabled]=\"isDisabled()\">\n <i [ngClass]=\"clearIconClass()\"></i>\n </button>\n }\n\n <button class=\"btn btn-outline-secondary dropdown-toggle\" type=\"button\" (click)=\"toggleDropdown()\"\n [disabled]=\"isDisabled()\">\n <i [ngClass]=\"dropDownToggleIconClass()\"></i>\n </button>\n </div>\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen()\">\n\n @if(searchable()){\n <div class=\"px-2\">\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder()\" [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\" (keydown)=\"onKeyDown($event)\">\n </div>\n }\n\n @for (option of filteredOptions(); track option.value) {\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\n [class.highlighted]=\"$index === highlightedIndex()\">\n\n @if(itemTemplate()){\n <ng-container [ngTemplateOutlet]=\"itemTemplate()\" [ngTemplateOutletContext]=\"{ option: option }\">\n </ng-container>\n } @else {\n @if(multiple()){\n <i class=\"{{multipleCheckIconClass()}} text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\n }\n <!-- <span>{{option[optionLabel]}}</span> -->\n <span>{{option.label}}</span>\n }\n </div>\n }\n </div>\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]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
207
245
  }
208
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: YsDropdownComponent, decorators: [{
246
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: YsDropdown, decorators: [{
209
247
  type: Component,
210
- args: [{ selector: 'ys-dropdown', imports: [NgTemplateOutlet, FormsModule], providers: [
248
+ args: [{ selector: 'ys-dropdown', imports: [NgTemplateOutlet, FormsModule, NgClass], changeDetection: ChangeDetectionStrategy.Eager, providers: [
211
249
  {
212
250
  provide: NG_VALUE_ACCESSOR,
213
- useExisting: forwardRef(() => YsDropdownComponent),
251
+ useExisting: forwardRef(() => YsDropdown),
214
252
  multi: true,
215
253
  },
216
- ], 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)\" [disabled]=\"disabled\" />\r\n\r\n @if(showClear && (multiple ? selected?.length > 0 : selected)){\r\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\" [disabled]=\"disabled\">\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 [disabled]=\"disabled\">\r\n <i class=\"fa fa-chevron-down\"></i>\r\n </button>\r\n </div>\r\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen\">\r\n\r\n @if(searchable){\r\n <div class=\"px-2\">\r\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder\" [(ngModel)]=\"searchTerm\"\r\n (keydown)=\"onKeyDown($event)\">\r\n </div>\r\n }\r\n\r\n @for (option of filterOptions(); track $index) {\r\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\r\n [class.highlighted]=\"$index === highlightedIndex\">\r\n @if(itemTemplate){\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{ option: option }\">\r\n </ng-container>\r\n }\r\n @else {\r\n @if(multiple){\r\n <i class=\"fa fa-check text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\r\n }\r\n <!-- <span>{{option[optionLabel]}}</span> -->\r\n <span>{{option.label}}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [".ys-dropdown .dropdown-toggle:after{display:none}.ys-dropdown .dropdown-menu{max-height:200px}.ys-dropdown .dropdown-item.highlighted{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}\n"] }]
217
- }], propDecorators: { options: [{
218
- type: Input
219
- }], optionLabel: [{
220
- type: Input
221
- }], placeholder: [{
222
- type: Input
223
- }], searchPlaceholder: [{
224
- type: Input
225
- }], selectedMaxLength: [{
226
- type: Input
227
- }], selectedMaxLengthTemplate: [{
228
- type: Input
229
- }], selectionSeparator: [{
230
- type: Input
231
- }], multiple: [{
232
- type: Input
233
- }], showClear: [{
234
- type: Input
235
- }], itemTemplate: [{
236
- type: Input
237
- }], selected: [{
238
- type: Input
239
- }], searchable: [{
240
- type: Input
241
- }], disabled: [{
242
- type: Input
243
- }], selectionChange: [{
244
- type: Output
245
- }], onClickOutside: [{
254
+ ], template: "<div class=\"dropdown ys-dropdown\">\n <div class=\"input-group w-100\">\n <input #inputRef type=\"text\" class=\"form-control\" [value]=\"selectedLabels()\" [placeholder]=\"placeholder()\"\n readonly (click)=\"isOpen.set(true)\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled()\" />\n <!-- (focus)=\"isOpen.set(true)\" replace with (click)=\"isOpen.set(true)\" (keydown.enter)=\"isOpen.set(true)\" -->\n\n @if(showClear() && hasSelection()){\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\" [disabled]=\"isDisabled()\">\n <i [ngClass]=\"clearIconClass()\"></i>\n </button>\n }\n\n <button class=\"btn btn-outline-secondary dropdown-toggle\" type=\"button\" (click)=\"toggleDropdown()\"\n [disabled]=\"isDisabled()\">\n <i [ngClass]=\"dropDownToggleIconClass()\"></i>\n </button>\n </div>\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen()\">\n\n @if(searchable()){\n <div class=\"px-2\">\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder()\" [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\" (keydown)=\"onKeyDown($event)\">\n </div>\n }\n\n @for (option of filteredOptions(); track option.value) {\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\n [class.highlighted]=\"$index === highlightedIndex()\">\n\n @if(itemTemplate()){\n <ng-container [ngTemplateOutlet]=\"itemTemplate()\" [ngTemplateOutletContext]=\"{ option: option }\">\n </ng-container>\n } @else {\n @if(multiple()){\n <i class=\"{{multipleCheckIconClass()}} text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\n }\n <!-- <span>{{option[optionLabel]}}</span> -->\n <span>{{option.label}}</span>\n }\n </div>\n }\n </div>\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"] }]
255
+ }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], selectedMaxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedMaxLength", required: false }] }], selectedMaxLengthTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedMaxLengthTemplate", required: false }] }], selectionSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionSeparator", required: false }] }], dropDownToggleIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropDownToggleIconClass", required: false }] }], clearIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearIconClass", required: false }] }], multipleCheckIconClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "multipleCheckIconClass", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], onClickOutside: [{
246
256
  type: HostListener,
247
257
  args: ['document:click', ['$event']]
248
258
  }] } });
@@ -255,5 +265,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImpor
255
265
  * Generated bundle index. Do not edit.
256
266
  */
257
267
 
258
- export { YsDropdownComponent };
268
+ export { YsDropdown };
259
269
  //# sourceMappingURL=yoozsoft-yoozsoft-ng-dropdown.mjs.map
@@ -1 +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\ninterface ItemTemplate {\r\n raw: any;\r\n label: string;\r\n value: any;\r\n}\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 private _options: any[] = [];\r\n @Input()\r\n set options(value: any[]) { this._options = this.normalizeOptions(value); }\r\n get options() { return this._options; }\r\n\r\n @Input() optionLabel: string = 'label';\r\n @Input() placeholder: string = '';\r\n @Input() searchPlaceholder: string = '';\r\n @Input() selectedMaxLength: number = 3;\r\n @Input() selectedMaxLengthTemplate: string = '{length} items selected';\r\n @Input() selectionSeparator: string = \", \";\r\n\r\n /** انتخاب چندگانه یا تکی */\r\n @Input() multiple: boolean = false;\r\n\r\n @Input() showClear: boolean = false;\r\n\r\n /** تمپلیت سفارشی برای آیتم‌ها */\r\n @Input() itemTemplate?: TemplateRef<any>;\r\n\r\n /** مقدار انتخاب‌شده */\r\n @Input() selected: any[] | any = this.multiple ? [] : null;\r\n\r\n /** قابلیت جستجو */\r\n @Input() searchable: boolean = false;\r\n\r\n @Input() disabled: boolean = false;\r\n\r\n /** رویداد خروجی هنگام تغییر انتخاب */\r\n @Output() selectionChange = new EventEmitter<any>();\r\n\r\n searchTerm = '';\r\n isOpen = false;\r\n highlightedIndex: number = -1;\r\n\r\n private elRef = inject(ElementRef)\r\n\r\n private _onChange: (value: any) => void = () => { };\r\n private _onTouched: () => void = () => { };\r\n\r\n writeValue(obj: any): void {\r\n if (this.multiple) {\r\n this.selected = obj ? [...obj] : [];\r\n } else {\r\n this.selected = obj;\r\n }\r\n }\r\n registerOnChange(fn: any): void {\r\n this._onChange = fn;\r\n }\r\n registerOnTouched(fn: any): void {\r\n this._onTouched = fn;\r\n }\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n }\r\n\r\n private normalizeOptions(list: any[]): any[] {\r\n if (!Array.isArray(list)) return [];\r\n\r\n return list.map(item => {\r\n\r\n // 1. اگر primitive بود\r\n if (['string', 'number', 'boolean'].includes(typeof item)) {\r\n return <ItemTemplate>{\r\n raw: item,\r\n label: String(item),\r\n value: item\r\n };\r\n }\r\n\r\n // 2. اگر OptionItem<T> بود\r\n if ('value' in item) {\r\n return <ItemTemplate>{\r\n raw: item,\r\n label: item.label ?? String(item.value),\r\n value: item.value,\r\n ...item\r\n };\r\n }\r\n\r\n // 3. object معمولی\r\n return <ItemTemplate>{\r\n raw: item,\r\n label: item[this.optionLabel] ?? JSON.stringify(item),\r\n value: item\r\n };\r\n });\r\n }\r\n\r\n get selectedLabels(): string {\r\n if (this.multiple) {\r\n if (!Array.isArray(this.selected)) return '';\r\n\r\n // لیست object های انتخابی را پیدا می‌کنیم\r\n const selectedItems = this.options.filter(o =>\r\n this.selected.includes(o.value)\r\n );\r\n\r\n const count = selectedItems.length;\r\n\r\n // اگر بیشتر از حد مجاز باشد → متن سفارشی\r\n if (count > this.selectedMaxLength) {\r\n return this.selectedMaxLengthTemplate.replace('{length}', count + '');\r\n }\r\n\r\n // در غیر این‌صورت لیبل‌ها را نمایش بده\r\n return selectedItems.map(o => o.label).join(this.selectionSeparator);\r\n }\r\n\r\n const item = this.options.find(o => o.value === this.selected);\r\n return item?.label ?? '';\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 const returnedValue = option.value; // مقدار نهایی برای فرم\r\n\r\n if (this.multiple) {\r\n const exists = this.selected?.some((x: any) => x === returnedValue);\r\n this.selected = exists\r\n ? this.selected.filter((x: any) => x !== returnedValue)\r\n : [...(this.selected || []), returnedValue];\r\n } else {\r\n this.selected = returnedValue;\r\n this.isOpen = false;\r\n }\r\n\r\n this._onChange(this.selected);\r\n this.selectionChange.emit(this.selected);\r\n }\r\n\r\n isSelected(option: any): boolean {\r\n if (this.multiple) {\r\n return Array.isArray(this.selected)\r\n ? this.selected.includes(option.value)\r\n : false;\r\n }\r\n\r\n return this.selected === option.value;\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 /** 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)\" [disabled]=\"disabled\" />\r\n\r\n @if(showClear && (multiple ? selected?.length > 0 : selected)){\r\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\" [disabled]=\"disabled\">\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 [disabled]=\"disabled\">\r\n <i class=\"fa fa-chevron-down\"></i>\r\n </button>\r\n </div>\r\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen\">\r\n\r\n @if(searchable){\r\n <div class=\"px-2\">\r\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder\" [(ngModel)]=\"searchTerm\"\r\n (keydown)=\"onKeyDown($event)\">\r\n </div>\r\n }\r\n\r\n @for (option of filterOptions(); track $index) {\r\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\r\n [class.highlighted]=\"$index === highlightedIndex\">\r\n @if(itemTemplate){\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{ option: option }\">\r\n </ng-container>\r\n }\r\n @else {\r\n @if(multiple){\r\n <i class=\"fa fa-check text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\r\n }\r\n <!-- <span>{{option[optionLabel]}}</span> -->\r\n <span>{{option.label}}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>","/*\r\n * Public API Surface of ys-dropdown\r\n */\r\n\r\nexport * from './src/models';\r\nexport * from './src/ys-dropdown/ys-dropdown.component';\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-dropdown.mjs","sources":["../../../../projects/yoozsoft/yoozsoft-ng/dropdown/src/ys-dropdown/ys-dropdown.ts","../../../../projects/yoozsoft/yoozsoft-ng/dropdown/src/ys-dropdown/ys-dropdown.html","../../../../projects/yoozsoft/yoozsoft-ng/dropdown/public-api.ts","../../../../projects/yoozsoft/yoozsoft-ng/dropdown/yoozsoft-yoozsoft-ng-dropdown.ts"],"sourcesContent":["import { isPlatformBrowser, NgClass, NgTemplateOutlet } from '@angular/common';\r\nimport {\r\n Component,\r\n computed,\r\n effect,\r\n ElementRef,\r\n forwardRef,\r\n HostListener,\r\n inject,\r\n input,\r\n output,\r\n PLATFORM_ID,\r\n signal,\r\n TemplateRef,\r\n ChangeDetectionStrategy,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\r\n\r\ninterface ItemTemplate {\r\n raw: unknown;\r\n label: string;\r\n value: unknown;\r\n disabled: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'ys-dropdown',\r\n imports: [NgTemplateOutlet, FormsModule, NgClass],\r\n templateUrl: './ys-dropdown.html',\r\n styleUrl: './ys-dropdown.scss',\r\n changeDetection: ChangeDetectionStrategy.Eager,\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => YsDropdown),\r\n multi: true,\r\n },\r\n ],\r\n})\r\nexport class YsDropdown implements ControlValueAccessor {\r\n private elRef = inject(ElementRef);\r\n private platformId = inject(PLATFORM_ID);\r\n\r\n /** List of options */\r\n options = input<any[]>([]);\r\n /** Field of object that display as label */\r\n optionLabel = input<string>('label');\r\n placeholder = input<string>('');\r\n searchPlaceholder = input<string>('');\r\n selectedMaxLength = input<number>(3);\r\n selectedMaxLengthTemplate = input<string>('{length} items selected');\r\n selectionSeparator = input<string>(', ');\r\n dropDownToggleIconClass = input<string>('fa fa-chevron-down');\r\n clearIconClass = input<string>('fa fa-times');\r\n multipleCheckIconClass = input<string>('fa fa-check');\r\n\r\n /** Multiple choice mode */\r\n multiple = input<boolean>(false);\r\n showClear = input<boolean>(false);\r\n\r\n /** Search capability */\r\n searchable = input<boolean>(false);\r\n\r\n disabled = input<boolean>(false);\r\n\r\n /** Custom template for items */\r\n itemTemplate = input<TemplateRef<any>>();\r\n\r\n /** Output event when selection changes */\r\n selectionChange = output<unknown | unknown[] | null>();\r\n\r\n searchTerm = signal<string>('');\r\n isOpen = signal<boolean>(false);\r\n highlightedIndex = signal<number>(-1);\r\n /** Selected value */\r\n selected = signal<any[] | any>(null);\r\n\r\n private disabledState = signal(false);\r\n readonly isDisabled = computed(() => this.disabled() || this.disabledState());\r\n\r\n readonly filteredOptions = computed<ItemTemplate[]>(() => {\r\n if (!this.searchable() || !this.searchTerm().trim()) {\r\n return this.normalizedOptions();\r\n }\r\n\r\n const term = this.searchTerm().toLowerCase();\r\n\r\n return this.normalizedOptions().filter((opt) => opt.label.toLowerCase().includes(term));\r\n });\r\n\r\n readonly normalizedOptions = computed(() => this.normalizeOptions(this.options()));\r\n\r\n readonly hasSelection = computed(() =>\r\n this.multiple()\r\n ? Array.isArray(this.selected()) && this.selected().length > 0\r\n : !!this.selected(),\r\n );\r\n\r\n readonly selectedLabels = computed(() => {\r\n if (this.multiple()) {\r\n if (!Array.isArray(this.selected())) return '';\r\n\r\n // لیست object های انتخابی را پیدا می‌کنیم\r\n const selectedItems = this.normalizedOptions().filter((o) =>\r\n this.selected().includes(o.value),\r\n );\r\n\r\n const count = selectedItems.length;\r\n\r\n // اگر بیشتر از حد مجاز باشد → متن سفارشی\r\n if (count > this.selectedMaxLength()) {\r\n return this.selectedMaxLengthTemplate().replace('{length}', count + '');\r\n }\r\n\r\n // در غیر این‌صورت لیبل‌ها را نمایش بده\r\n return selectedItems.map((o) => o.label).join(this.selectionSeparator());\r\n }\r\n\r\n const item = this.normalizedOptions().find((o) => o.value === this.selected());\r\n return item?.label ?? '';\r\n });\r\n\r\n private _onChange = (_: unknown) => {};\r\n private _onTouched: () => void = () => {};\r\n\r\n constructor() {\r\n effect(() => this.selected.set(this.multiple() ? [] : null));\r\n }\r\n\r\n writeValue(obj: any): void {\r\n this.selected.set(this.multiple() ? (Array.isArray(obj) ? obj : []) : 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.disabledState.set(isDisabled);\r\n }\r\n\r\n private normalizeOptions(list: any[]): ItemTemplate[] {\r\n if (!Array.isArray(list)) return [];\r\n\r\n return list.map((item) => {\r\n // 1. اگر primitive بود\r\n if (['string', 'number', 'boolean'].includes(typeof item)) {\r\n return <ItemTemplate>{\r\n raw: item,\r\n label: String(item),\r\n value: item,\r\n disabled: false,\r\n };\r\n }\r\n\r\n // 2. اگر OptionItem<T> بود\r\n if (item && typeof item === 'object' && 'value' in item) {\r\n return <ItemTemplate>{\r\n raw: item,\r\n label: item.label ?? String(item.value),\r\n value: item.value,\r\n disabled: item.disabled,\r\n ...item,\r\n };\r\n }\r\n\r\n // 3. object معمولی\r\n return <ItemTemplate>{\r\n raw: item,\r\n label: item[this.optionLabel()] ?? JSON.stringify(item),\r\n value: item,\r\n disabled: false,\r\n };\r\n });\r\n }\r\n\r\n toggleDropdown() {\r\n this.isOpen.update((v) => !v);\r\n this.highlightedIndex.set(-1);\r\n }\r\n\r\n selectOption(option: ItemTemplate) {\r\n if (option.disabled) return;\r\n\r\n const value = option.value;\r\n\r\n if (this.multiple()) {\r\n this.selected.update((list: any[]) =>\r\n list?.includes(value) ? list.filter((x) => x !== value) : [...(list || []), value],\r\n );\r\n } else {\r\n this.selected.set(value);\r\n this.isOpen.set(false);\r\n }\r\n\r\n this._onChange(this.selected());\r\n this.selectionChange.emit(this.selected());\r\n this._onTouched();\r\n }\r\n\r\n isSelected(option: any): boolean {\r\n if (this.multiple()) {\r\n return Array.isArray(this.selected()) ? this.selected().includes(option.value) : false;\r\n }\r\n\r\n return this.selected() === option.value;\r\n }\r\n\r\n clearSelection() {\r\n this.selected.set(this.multiple() ? [] : null);\r\n this._onChange(this.selected());\r\n this.selectionChange.emit(this.selected());\r\n this._onTouched();\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent) {\r\n const list = this.filteredOptions();\r\n if (!list.length) return;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n this.highlightedIndex.update((i) => (i + 1) % list.length);\r\n this.scrollToHighlighted();\r\n break;\r\n\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this.highlightedIndex.update((i) => (i > 0 ? i - 1 : list.length - 1));\r\n this.scrollToHighlighted();\r\n break;\r\n\r\n case 'Enter':\r\n event.preventDefault();\r\n\r\n if (!this.isOpen()) {\r\n this.isOpen.set(true);\r\n return;\r\n }\r\n\r\n const idx = this.highlightedIndex();\r\n if (idx >= 0) this.selectOption(list[idx]);\r\n break;\r\n\r\n case 'Tab':\r\n this.isOpen.set(false);\r\n break;\r\n\r\n case 'Escape':\r\n this.isOpen.set(false);\r\n break;\r\n }\r\n }\r\n\r\n scrollToHighlighted() {\r\n if (!isPlatformBrowser(this.platformId)) return;\r\n\r\n queueMicrotask(() => {\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\r\n if (!activeItem || !dropdown) return;\r\n\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 /** Close by clicking outside */\r\n @HostListener('document:click', ['$event'])\r\n onClickOutside(event: MouseEvent) {\r\n if (!isPlatformBrowser(this.platformId)) return;\r\n\r\n if (!this.isOpen()) return;\r\n\r\n const clickedInside = this.elRef.nativeElement.contains(event.target);\r\n if (!clickedInside) {\r\n this.isOpen.set(false);\r\n }\r\n }\r\n}\r\n","<div class=\"dropdown ys-dropdown\">\n <div class=\"input-group w-100\">\n <input #inputRef type=\"text\" class=\"form-control\" [value]=\"selectedLabels()\" [placeholder]=\"placeholder()\"\n readonly (click)=\"isOpen.set(true)\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled()\" />\n <!-- (focus)=\"isOpen.set(true)\" replace with (click)=\"isOpen.set(true)\" (keydown.enter)=\"isOpen.set(true)\" -->\n\n @if(showClear() && hasSelection()){\n <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"clearSelection()\" [disabled]=\"isDisabled()\">\n <i [ngClass]=\"clearIconClass()\"></i>\n </button>\n }\n\n <button class=\"btn btn-outline-secondary dropdown-toggle\" type=\"button\" (click)=\"toggleDropdown()\"\n [disabled]=\"isDisabled()\">\n <i [ngClass]=\"dropDownToggleIconClass()\"></i>\n </button>\n </div>\n <div class=\"dropdown-menu w-100 overflow-auto\" [class.show]=\"isOpen()\">\n\n @if(searchable()){\n <div class=\"px-2\">\n <input type=\"text\" class=\"form-control mb-2\" [placeholder]=\"searchPlaceholder()\" [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\" (keydown)=\"onKeyDown($event)\">\n </div>\n }\n\n @for (option of filteredOptions(); track option.value) {\n <div class=\"dropdown-item\" (click)=\"selectOption(option)\" [class.active]=\"isSelected(option)\"\n [class.highlighted]=\"$index === highlightedIndex()\">\n\n @if(itemTemplate()){\n <ng-container [ngTemplateOutlet]=\"itemTemplate()\" [ngTemplateOutletContext]=\"{ option: option }\">\n </ng-container>\n } @else {\n @if(multiple()){\n <i class=\"{{multipleCheckIconClass()}} text-success me-1\" [class.invisible]=\"!isSelected(option)\"></i>\n }\n <!-- <span>{{option[optionLabel]}}</span> -->\n <span>{{option.label}}</span>\n }\n </div>\n }\n </div>\n</div>","/*\r\n * Public API Surface of ys-dropdown\r\n */\r\n\r\nexport * from './src/models';\r\nexport * from './src/ys-dropdown/ys-dropdown';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}