smt-select 0.1.8 → 1.0.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.
package/README.md CHANGED
@@ -7,12 +7,22 @@ A high-performance, lightweight, and customizable **Angular Select Component** w
7
7
  - **🔍 Searchable**: Quickly filter through thousands of options.
8
8
  - **⚡ Virtual Scroll**: Built-in support for high-performance rendering of large datasets.
9
9
  - **✅ Multi-Select**: Support for multiple selection out of the box.
10
+ - **☑️ Select All**: Optional "Select All" toggle for multi-select mode.
11
+ - **⌨️ Keyboard Navigation**: Full keyboard support (Arrow keys, Enter, Escape).
12
+ - **🚫 Disabled Options**: Mark options as non-selectable.
13
+ - **❌ Clearable**: Optional clear button to reset selection.
10
14
  - **🎨 Custom Styling**: Fully customizable via SCSS tokens.
11
15
  - **📱 Responsive**: Works seamlessly across mobile and desktop.
12
16
  - **🛡️ Type Safe**: Developed with strict TypeScript.
13
17
 
14
18
  ---
15
19
 
20
+ ## 📺 Demo
21
+
22
+ ![smt-select demo](https://raw.githubusercontent.com/sametacar/smt-select/main/assets/smt-select_muti_demo.gif)
23
+
24
+ ---
25
+
16
26
  ## 🧩 Angular Compatibility
17
27
 
18
28
  | Angular Version | Support |
@@ -25,23 +35,25 @@ A high-performance, lightweight, and customizable **Angular Select Component** w
25
35
 
26
36
  ## 🚀 Installation
27
37
 
28
- Install the package along with Angular CDK (required dependency):
29
-
30
38
  ```bash
31
- # For Angular 18
32
- npm install @angular/cdk@^18.0.0 smt-select
39
+ npm install smt-select
40
+ ```
33
41
 
34
- # For Angular 19
35
- npm install @angular/cdk@^19.0.0 smt-select
42
+ > **Note**: Angular CDK is a peer dependency and will be automatically installed by npm 7+. Make sure it matches your Angular version.
36
43
 
37
- # For Angular 20
38
- npm install @angular/cdk@^20.0.0 smt-select
44
+ <details>
45
+ <summary>💡 Manual CDK Installation (if needed)</summary>
39
46
 
40
- # For Angular 21
41
- npm install @angular/cdk@^21.0.0 smt-select
42
- ```
47
+ If you're using npm 6 or need a specific CDK version:
43
48
 
44
- > **Important**: Angular CDK is a required dependency. Make sure to install the version that matches your Angular version.
49
+ ```bash
50
+ # Install CDK first (version should match your Angular version)
51
+ npm install @angular/cdk@^21.0.0
52
+
53
+ # Then install smt-select
54
+ npm install smt-select
55
+ ```
56
+ </details>
45
57
 
46
58
  ---
47
59
 
@@ -60,14 +72,25 @@ import { SmtSelectComponent, SmtSelectOption, SmtSelectConfig } from 'smt-select
60
72
  export class AppComponent {
61
73
  myOptions: SmtSelectOption[] = [
62
74
  { value: 1, label: 'Option 1' },
63
- { value: 2, label: 'Option 2' },
75
+ { value: 2, label: 'Option 2', disabled: true }, // Disabled option
64
76
  { value: 3, label: 'Option 3' }
65
77
  ];
66
78
 
67
79
  selectConfig: SmtSelectConfig = {
68
80
  placeholder: 'Choose an item...',
69
81
  virtualScroll: true,
70
- isMultiSelect: false
82
+ isMultiSelect: false,
83
+ clearable: true, // Enable clear button
84
+ noResultsMessage: 'No items found' // Custom no results message
85
+ };
86
+
87
+ // Multi-select configuration with Select All
88
+ multiSelectConfig: SmtSelectConfig = {
89
+ placeholder: 'Choose multiple items...',
90
+ virtualScroll: true,
91
+ isMultiSelect: true,
92
+ showSelectAll: true, // Enable Select All option
93
+ clearable: true
71
94
  };
72
95
 
73
96
  selectedValue: any = null;
@@ -90,6 +113,30 @@ export class AppComponent {
90
113
 
91
114
  ---
92
115
 
116
+ ## 🎨 Customization
117
+
118
+ You can customize the component's appearance by providing custom colors:
119
+
120
+ ```typescript
121
+ selectConfig: SmtSelectConfig = {
122
+ placeholder: 'Choose an item...',
123
+ virtualScroll: true,
124
+ isMultiSelect: false,
125
+ // Custom theme colors
126
+ optionActiveBackgroundColor: '#ff6b6b',
127
+ optionActiveTextColor: '#ffffff',
128
+ hoverBackgroundColor: '#ffe0e0',
129
+ optionTextColor: '#333333',
130
+ optionBackgroundColor: 'transparent',
131
+ inputTextColor: '#000000', // Placeholder automatically uses 60% opacity
132
+ borderColor: '#cccccc',
133
+ errorBorderColor: '#d9534f',
134
+ borderRadius: 8 // Can be number (px) or string ('8px', '0.5rem')
135
+ };
136
+ ```
137
+
138
+ ---
139
+
93
140
  ## ⚙️ API Reference
94
141
 
95
142
  ### Inputs
@@ -109,6 +156,13 @@ export class AppComponent {
109
156
  | `selectedValueChange` | `any \| any[]` | Fired when the selected value changes (for two-way binding support). |
110
157
  | `pocketOpen` | `boolean` | Fired when the dropdown is opened or closed. |
111
158
 
159
+ ### Option Structure (`SmtSelectOption`)
160
+ | Property | Type | Required | Description |
161
+ |----------|------|----------|-------------|
162
+ | `value` | `any` | Yes | The value of the option. |
163
+ | `label` | `string` | Yes | Display text for the option. |
164
+ | `disabled` | `boolean` | No | Mark option as non-selectable (default: `false`). |
165
+
112
166
  ### Configuration (`SmtSelectConfig`)
113
167
  | Property | Type | Description |
114
168
  |----------|------|-------------|
@@ -116,6 +170,35 @@ export class AppComponent {
116
170
  | `placeholder` | `string` | Text to show when no value is selected. |
117
171
  | `virtualScroll` | `boolean` | Enable/Disable CDK Virtual Scroll for large datasets. |
118
172
  | `isMultiSelect` | `boolean` | Enable multiple item selection. |
173
+ | `clearable` | `boolean` | Show clear button to reset selection (default: `false`). |
174
+ | `showSelectAll` | `boolean` | Show "Select All" option in multi-select mode (default: `false`). Only visible when `isMultiSelect` is true. |
175
+ | `noResultsMessage` | `string` | Custom message when no results found (default: `'No results found'`). |
176
+ | **Theme Colors** | | |
177
+ | `optionActiveBackgroundColor` | `string` | Background color for selected options (default: `#005f87`). |
178
+ | `optionActiveTextColor` | `string` | Text color for selected options (default: `#fff`). |
179
+ | `hoverBackgroundColor` | `string` | Background color for hovered items (default: `#f0faff`). |
180
+ | `optionTextColor` | `string` | Text color for normal options (default: `#333`). |
181
+ | `optionBackgroundColor` | `string` | Background color for normal options (default: `transparent`). |
182
+ | `inputTextColor` | `string` | Text color for search input, selected value, and placeholder (with 60% opacity) (default: `#333`). |
183
+ | `borderColor` | `string` | Border color for the component and dropdown (default: `#ccc`). |
184
+ | `errorBorderColor` | `string` | Border color when in error state (default: `#d9534f`). |
185
+ | `borderRadius` | `string \| number` | Border radius for the component and dropdown. Number will be converted to px (default: `4px`). |
186
+
187
+ ---
188
+
189
+ ## ⌨️ Keyboard Shortcuts
190
+
191
+ When the dropdown is open:
192
+ - **Arrow Down** / **Arrow Up**: Navigate through options
193
+ - **Enter**: Select highlighted option
194
+ - **Escape**: Close dropdown
195
+ - **Type to search**: Filter options in real-time
196
+
197
+ ---
198
+
199
+ ## 📋 Changelog
200
+
201
+ See [CHANGELOG.md](https://github.com/sametacar/smt-select/blob/main/projects/smt-select/CHANGELOG.md) for detailed release notes and version history.
119
202
 
120
203
  ---
121
204
 
@@ -56,7 +56,9 @@ class SmtSelectComponent {
56
56
  isPocketOpen = false;
57
57
  isOpenReverse = false;
58
58
  searchText = '';
59
+ highlightedIndex = -1;
59
60
  clickListener = null;
61
+ blurTimerSubscription = null;
60
62
  VisibilityType = SmtVisibilityType;
61
63
  constructor(el, renderer) {
62
64
  this.el = el;
@@ -64,6 +66,7 @@ class SmtSelectComponent {
64
66
  }
65
67
  ngOnDestroy() {
66
68
  this.removeOutsideClickListener();
69
+ this.cancelBlurTimer();
67
70
  }
68
71
  get hasSelection() {
69
72
  if (this.config.isMultiSelect) {
@@ -71,6 +74,36 @@ class SmtSelectComponent {
71
74
  }
72
75
  return this.selectedValue !== null && this.selectedValue !== undefined && this.selectedValue !== '';
73
76
  }
77
+ get selectAllState() {
78
+ if (!this.config.isMultiSelect)
79
+ return 'unchecked';
80
+ const filtered = this.getFilteredOptions();
81
+ const selectableOptions = filtered.filter(opt => !opt.disabled);
82
+ if (selectableOptions.length === 0)
83
+ return 'unchecked';
84
+ const selectedCount = selectableOptions.filter(opt => Array.isArray(this.selectedValue) && this.selectedValue.includes(opt.value)).length;
85
+ if (selectedCount === 0)
86
+ return 'unchecked';
87
+ if (selectedCount === selectableOptions.length)
88
+ return 'checked';
89
+ return 'indeterminate';
90
+ }
91
+ get customStyles() {
92
+ const borderRadius = typeof this.config.borderRadius === 'number'
93
+ ? `${this.config.borderRadius}px`
94
+ : (this.config.borderRadius || '4px');
95
+ return {
96
+ '--active-bg-color': this.config.optionActiveBackgroundColor || '#005f87',
97
+ '--active-text-color': this.config.optionActiveTextColor || '#fff',
98
+ '--hover-bg-color': this.config.hoverBackgroundColor || '#f0faff',
99
+ '--option-text-color': this.config.optionTextColor || '#333',
100
+ '--option-bg-color': this.config.optionBackgroundColor || 'transparent',
101
+ '--input-text-color': this.config.inputTextColor || '#333',
102
+ '--border-color': this.config.borderColor || '#ccc',
103
+ '--error-border-color': this.config.errorBorderColor || '#d9534f',
104
+ '--border-radius': borderRadius
105
+ };
106
+ }
74
107
  displayText() {
75
108
  if (!this.hasSelection)
76
109
  return this.config.placeholder || 'Select...';
@@ -97,6 +130,7 @@ class SmtSelectComponent {
97
130
  this.isPocketOpen = true;
98
131
  this.pocketOpen.emit(true);
99
132
  this.searchText = '';
133
+ this.highlightedIndex = -1;
100
134
  this.focusInput();
101
135
  this.addOutsideClickListener();
102
136
  }
@@ -106,6 +140,7 @@ class SmtSelectComponent {
106
140
  this.isPocketOpen = false;
107
141
  this.pocketOpen.emit(false);
108
142
  this.removeOutsideClickListener();
143
+ this.cancelBlurTimer();
109
144
  }
110
145
  addOutsideClickListener() {
111
146
  if (this.clickListener)
@@ -139,35 +174,99 @@ class SmtSelectComponent {
139
174
  }
140
175
  onBlur() {
141
176
  // Keyboard exit scenarios delay
142
- timer(200).pipe(take(1)).subscribe(() => {
177
+ this.blurTimerSubscription = timer(200).pipe(take(1)).subscribe(() => {
143
178
  if (this.isPocketOpen) {
144
179
  this.closePocket();
145
180
  }
146
181
  });
147
182
  }
183
+ cancelBlurTimer() {
184
+ if (this.blurTimerSubscription) {
185
+ this.blurTimerSubscription.unsubscribe();
186
+ this.blurTimerSubscription = null;
187
+ }
188
+ }
148
189
  isSelected(option) {
149
190
  if (this.config.isMultiSelect) {
150
191
  return Array.isArray(this.selectedValue) && this.selectedValue.includes(option.value);
151
192
  }
152
193
  return this.selectedValue === option.value;
153
194
  }
154
- onEnterPressed() {
195
+ getFilteredOptions() {
155
196
  if (!this.searchText)
197
+ return this.options;
198
+ const searchLower = this.searchText.toLowerCase();
199
+ return this.options.filter(option => option.label.toLowerCase().includes(searchLower) ||
200
+ (typeof option.value === 'string' && option.value.toLowerCase().includes(searchLower)));
201
+ }
202
+ getViewportHeight() {
203
+ const filteredCount = this.getFilteredOptions().length;
204
+ const itemHeight = 34; // itemSize from template
205
+ const maxHeight = 200;
206
+ const calculatedHeight = filteredCount * itemHeight;
207
+ return `${Math.min(calculatedHeight, maxHeight)}px`;
208
+ }
209
+ onEnterPressed() {
210
+ const filtered = this.getFilteredOptions();
211
+ // If an option is highlighted, select it
212
+ if (this.highlightedIndex >= 0 && this.highlightedIndex < filtered.length) {
213
+ this.selectOption(filtered[this.highlightedIndex]);
214
+ if (!this.config.isMultiSelect) {
215
+ this.closePocket();
216
+ }
156
217
  return;
157
- const filtered = this.options.filter(option => option.label.toLowerCase().includes(this.searchText.toLowerCase()) ||
158
- (typeof option.value === 'string' && option.value.toLowerCase().includes(this.searchText.toLowerCase())));
159
- if (filtered.length > 0) {
218
+ }
219
+ // Otherwise, select first match if searching
220
+ if (this.searchText && filtered.length > 0) {
160
221
  this.selectOption(filtered[0]);
161
- this.closePocket();
162
- if (this.config.isMultiSelect) {
163
- this.searchText = '';
222
+ if (!this.config.isMultiSelect) {
223
+ this.closePocket();
164
224
  }
165
225
  }
166
226
  }
227
+ onKeyDown(event) {
228
+ const filtered = this.getFilteredOptions();
229
+ switch (event.key) {
230
+ case 'ArrowDown':
231
+ event.preventDefault();
232
+ this.highlightedIndex = Math.min(this.highlightedIndex + 1, filtered.length - 1);
233
+ this.scrollToHighlighted();
234
+ break;
235
+ case 'ArrowUp':
236
+ event.preventDefault();
237
+ this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
238
+ this.scrollToHighlighted();
239
+ break;
240
+ case 'Escape':
241
+ event.preventDefault();
242
+ this.closePocket();
243
+ break;
244
+ case 'Enter':
245
+ event.preventDefault();
246
+ this.onEnterPressed();
247
+ break;
248
+ }
249
+ }
250
+ scrollToHighlighted() {
251
+ // Wait for DOM update
252
+ setTimeout(() => {
253
+ const highlightedElement = this.el.nativeElement.querySelector('.smt-select-option.highlighted');
254
+ if (highlightedElement) {
255
+ highlightedElement.scrollIntoView({
256
+ behavior: 'smooth',
257
+ block: 'nearest'
258
+ });
259
+ }
260
+ }, 0);
261
+ }
167
262
  selectOption(option, event) {
168
263
  if (event) {
169
264
  event.stopPropagation();
170
265
  }
266
+ // Don't select disabled options
267
+ if (option.disabled) {
268
+ return;
269
+ }
171
270
  if (this.config.isMultiSelect) {
172
271
  if (!Array.isArray(this.selectedValue)) {
173
272
  this.selectedValue = [];
@@ -179,22 +278,61 @@ class SmtSelectComponent {
179
278
  else {
180
279
  this.selectedValue.push(option.value);
181
280
  }
182
- // View update for spread or slice
281
+ // View update for spread or slice
183
282
  this.selectedValue = [...this.selectedValue];
184
283
  }
185
284
  else {
186
285
  this.selectedValue = option.value;
187
286
  }
188
- this.closePocket();
287
+ if (!this.config.isMultiSelect) {
288
+ this.closePocket();
289
+ }
290
+ else {
291
+ // Cancel any pending blur timer and re-focus input
292
+ this.cancelBlurTimer();
293
+ this.focusInput();
294
+ }
295
+ this.selectionChange.emit(this.selectedValue);
296
+ this.selectedValueChange.emit(this.selectedValue);
297
+ }
298
+ clearSelection(event) {
299
+ event.stopPropagation();
300
+ this.selectedValue = this.config.isMultiSelect ? [] : null;
301
+ this.selectionChange.emit(this.selectedValue);
302
+ this.selectedValueChange.emit(this.selectedValue);
303
+ }
304
+ toggleSelectAll(event) {
305
+ if (event) {
306
+ event.stopPropagation();
307
+ }
308
+ if (!this.config.isMultiSelect)
309
+ return;
310
+ const filtered = this.getFilteredOptions();
311
+ const selectableOptions = filtered.filter(opt => !opt.disabled);
312
+ if (!Array.isArray(this.selectedValue)) {
313
+ this.selectedValue = [];
314
+ }
315
+ const allSelected = this.selectAllState === 'checked';
316
+ if (allSelected) {
317
+ // Deselect all visible options
318
+ this.selectedValue = this.selectedValue.filter((val) => !selectableOptions.some(opt => opt.value === val));
319
+ }
320
+ else {
321
+ // Select all visible options
322
+ const valuesToAdd = selectableOptions
323
+ .filter((opt) => !this.selectedValue.includes(opt.value))
324
+ .map((opt) => opt.value);
325
+ this.selectedValue = [...this.selectedValue, ...valuesToAdd];
326
+ }
189
327
  this.selectionChange.emit(this.selectedValue);
190
328
  this.selectedValueChange.emit(this.selectedValue);
191
329
  }
192
330
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SmtSelectComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
193
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: SmtSelectComponent, isStandalone: true, selector: "smt-select", inputs: { options: "options", config: "config", selectedValue: "selectedValue", errorMessage: "errorMessage", isInvalid: "isInvalid", visibility: "visibility" }, outputs: { selectionChange: "selectionChange", selectedValueChange: "selectedValueChange", pocketOpen: "pocketOpen" }, viewQueries: [{ propertyName: "pocketElement", first: true, predicate: ["pocket"], descendants: true }, { propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], ngImport: i0, template: "<div *ngIf=\"visibility !== VisibilityType.HIDDEN\" class=\"smt-select-wrapper\" [id]=\"config.fieldID || ''\"\r\n (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"smt-select-control\" (click)=\"togglePocket()\" [class.disabled]=\"visibility === VisibilityType.READONLY\"\r\n [class.error]=\"errorMessage ? true : (errorMessage === undefined ? isInvalid : false)\">\r\n\r\n <!-- Search Input -->\r\n <input #input *ngIf=\"isPocketOpen\" [(ngModel)]=\"searchText\" (click)=\"$event.stopPropagation()\"\r\n (keydown.enter)=\"onEnterPressed()\" (blur)=\"onBlur()\" class=\"smt-select-input\"\r\n [placeholder]=\"config.placeholder || 'Select...'\">\r\n\r\n <!-- Selected Value Display -->\r\n <ng-container *ngIf=\"!isPocketOpen\">\r\n <span class=\"select-value\" [class.placeholder]=\"!hasSelection\">\r\n {{ displayText() }}\r\n </span>\r\n </ng-container>\r\n\r\n <div class=\"arrow-icon\" [class.up]=\"isPocketOpen\"></div>\r\n </div>\r\n\r\n <!-- Dropdown (Pocket) -->\r\n <div #pocket *ngIf=\"isPocketOpen\" class=\"smt-select-pocket\" [class.open-reverse]=\"isOpenReverse\">\r\n\r\n <!-- Standard List -->\r\n <ul *ngIf=\"!config.virtualScroll\">\r\n <li *ngFor=\"let option of options | smtSelectSearchFilter: searchText\" (click)=\"selectOption(option, $event)\"\r\n class=\"smt-select-option\" [class.active]=\"isSelected(option)\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </li>\r\n </ul>\r\n\r\n <!-- Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport *ngIf=\"config.virtualScroll\" itemSize=\"34\" class=\"virtual-scroll-viewport\">\r\n <div *cdkVirtualFor=\"let option of options | smtSelectSearchFilter: searchText\" class=\"smt-select-option\"\r\n (click)=\"selectOption(option, $event)\" [class.active]=\"isSelected(option)\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"error-message\">\r\n {{ errorMessage }}\r\n </div>\r\n</div>", styles: [".smt-select-wrapper{position:relative;width:100%;font-family:Arial,sans-serif;box-sizing:border-box}.smt-select-wrapper *{box-sizing:border-box}.smt-select-control{display:flex;align-items:center;min-height:34px;border:1px solid #ccc;padding:4px 8px;background:#fff;cursor:pointer;position:relative}.smt-select-control.disabled{background:#f5f5f5;cursor:not-allowed;opacity:.7}.smt-select-control.error{border-color:#d9534f}.smt-select-control.error:focus-within{box-shadow:0 0 0 2px #d9534f33}.smt-select-control .select-value{font-size:13px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.smt-select-control .select-value.placeholder{color:#999;font-style:italic}.smt-select-control .smt-select-input{border:none;outline:none;width:100%;font-size:13px;padding:0;background:transparent}.smt-select-control .smt-select-input::placeholder{color:#999;font-style:italic}.smt-select-control .arrow-icon{margin-left:auto;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #666;transition:transform .2s}.smt-select-control .arrow-icon.up{transform:rotate(180deg)}.smt-select-pocket{position:absolute;top:100%;left:0;width:100%;background:#fff;border:1px solid #ccc;border-top:none;z-index:1000;max-height:200px;box-shadow:0 4px 6px #0000001a}.smt-select-pocket:has(ul){overflow-y:auto}.smt-select-pocket.open-reverse{top:auto;bottom:100%;border-top:1px solid #ccc;border-bottom:none}.smt-select-pocket .smt-select-option{padding:8px 12px;font-size:13px;cursor:pointer;display:flex;align-items:center}.smt-select-pocket .smt-select-option:hover{background-color:#f0faff}.smt-select-pocket .smt-select-option.active{background-color:#005f87;color:#fff}.smt-select-pocket .smt-select-option .checkbox-container{margin-right:8px;display:flex;align-items:center}.smt-select-pocket ul{list-style:none;padding:0;margin:0}.virtual-scroll-viewport{height:200px;width:100%;outline:none}.error-message{color:#d9534f;font-size:11px;margin-top:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "pipe", type: SmtSelectSearchFilterPipe, name: "smtSelectSearchFilter" }] });
331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: SmtSelectComponent, isStandalone: true, selector: "smt-select", inputs: { options: "options", config: "config", selectedValue: "selectedValue", errorMessage: "errorMessage", isInvalid: "isInvalid", visibility: "visibility" }, outputs: { selectionChange: "selectionChange", selectedValueChange: "selectedValueChange", pocketOpen: "pocketOpen" }, viewQueries: [{ propertyName: "pocketElement", first: true, predicate: ["pocket"], descendants: true }, { propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], ngImport: i0, template: "<div *ngIf=\"visibility !== VisibilityType.HIDDEN\" class=\"smt-select-wrapper\" [id]=\"config.fieldID || ''\"\r\n [ngStyle]=\"customStyles\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"smt-select-control\" (click)=\"togglePocket()\" [class.disabled]=\"visibility === VisibilityType.READONLY\"\r\n [class.error]=\"errorMessage ? true : (errorMessage === undefined ? isInvalid : false)\">\r\n\r\n <!-- Search Input -->\r\n <input #input *ngIf=\"isPocketOpen\" [(ngModel)]=\"searchText\" (click)=\"$event.stopPropagation()\"\r\n (keydown)=\"onKeyDown($event)\" (blur)=\"onBlur()\" class=\"smt-select-input\"\r\n [placeholder]=\"config.placeholder || 'Select...'\">\r\n\r\n <!-- Selected Value Display -->\r\n <ng-container *ngIf=\"!isPocketOpen\">\r\n <span class=\"select-value\" [class.placeholder]=\"!hasSelection\">\r\n {{ displayText() }}\r\n </span>\r\n </ng-container>\r\n\r\n <!-- Clear Button -->\r\n <div *ngIf=\"config.clearable && hasSelection && !isPocketOpen\" class=\"clear-icon\" (click)=\"clearSelection($event)\">\r\n \u2715\r\n </div>\r\n\r\n <div class=\"arrow-icon\" [class.up]=\"isPocketOpen\"></div>\r\n </div>\r\n\r\n <!-- Dropdown (Pocket) -->\r\n <div #pocket *ngIf=\"isPocketOpen\" class=\"smt-select-pocket\" [class.open-reverse]=\"isOpenReverse\">\r\n\r\n <!-- Standard List -->\r\n <ul *ngIf=\"!config.virtualScroll\">\r\n <!-- Select All Option -->\r\n <li *ngIf=\"config.isMultiSelect && config.showSelectAll && getFilteredOptions().length > 0\"\r\n (click)=\"toggleSelectAll($event)\" class=\"smt-select-option select-all-option\">\r\n <div class=\"checkbox-container\">\r\n <input type=\"checkbox\"\r\n [checked]=\"selectAllState === 'checked'\"\r\n [indeterminate]=\"selectAllState === 'indeterminate'\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n <span>Select All</span>\r\n </li>\r\n\r\n <li *ngFor=\"let option of options | smtSelectSearchFilter: searchText; let i = index\" (click)=\"selectOption(option, $event)\"\r\n class=\"smt-select-option\" [class.active]=\"isSelected(option)\" [class.disabled]=\"option.disabled\" [class.highlighted]=\"i === highlightedIndex\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </li>\r\n\r\n <!-- No Results Message -->\r\n <li *ngIf=\"getFilteredOptions().length === 0\" class=\"smt-select-no-results\">\r\n {{ config.noResultsMessage || 'No results found' }}\r\n </li>\r\n </ul>\r\n\r\n <!-- Virtual Scroll -->\r\n <ng-container *ngIf=\"config.virtualScroll && getFilteredOptions().length > 0\">\r\n <!-- Select All Option (Fixed Header) -->\r\n <div *ngIf=\"config.isMultiSelect && config.showSelectAll\"\r\n (click)=\"toggleSelectAll($event)\"\r\n class=\"smt-select-option select-all-option\">\r\n <div class=\"checkbox-container\">\r\n <input type=\"checkbox\"\r\n [checked]=\"selectAllState === 'checked'\"\r\n [indeterminate]=\"selectAllState === 'indeterminate'\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n <span>Select All</span>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport itemSize=\"34\" class=\"virtual-scroll-viewport\"\r\n [style.height]=\"getViewportHeight()\">\r\n <div *cdkVirtualFor=\"let option of options | smtSelectSearchFilter: searchText; let i = index\" class=\"smt-select-option\"\r\n (click)=\"selectOption(option, $event)\" [class.active]=\"isSelected(option)\" [class.disabled]=\"option.disabled\" [class.highlighted]=\"i === highlightedIndex\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </ng-container>\r\n\r\n <!-- No Results Message for Virtual Scroll -->\r\n <div *ngIf=\"config.virtualScroll && getFilteredOptions().length === 0\" class=\"smt-select-no-results\">\r\n {{ config.noResultsMessage || 'No results found' }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"error-message\">\r\n {{ errorMessage }}\r\n </div>\r\n</div>", styles: [".smt-select-wrapper{position:relative;width:100%;font-family:Arial,sans-serif;box-sizing:border-box}.smt-select-wrapper *{box-sizing:border-box}.smt-select-control{display:flex;align-items:center;min-height:34px;border:1px solid var(--border-color, #ccc);border-radius:var(--border-radius, 4px);padding:4px 8px;background:#fff;cursor:pointer;position:relative}.smt-select-control.disabled{background:#f5f5f5;cursor:not-allowed;opacity:.7}.smt-select-control.error{border-color:var(--error-border-color, #d9534f)}.smt-select-control.error:focus-within{box-shadow:0 0 0 2px #d9534f33}.smt-select-control .select-value{font-size:13px;color:var(--input-text-color, #333);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.smt-select-control .select-value.placeholder{opacity:.6;font-style:italic}.smt-select-control .smt-select-input{border:none;outline:none;width:100%;font-size:13px;padding:0;background:transparent;color:var(--input-text-color, #333)}.smt-select-control .smt-select-input::placeholder{color:var(--input-text-color, #333);opacity:.6;font-style:italic}.smt-select-control .clear-icon{margin-left:8px;margin-right:4px;color:#666;font-size:16px;cursor:pointer;display:flex;align-items:center;padding:0 4px;flex-shrink:0}.smt-select-control .clear-icon:hover{color:#d9534f}.smt-select-control .arrow-icon{margin-left:auto;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #666;transition:transform .2s}.smt-select-control .arrow-icon.up{transform:rotate(180deg)}.smt-select-pocket{position:absolute;top:100%;left:0;width:100%;background:#fff;border:1px solid var(--border-color, #ccc);border-top:none;border-radius:0 0 var(--border-radius, 4px) var(--border-radius, 4px);z-index:1000;max-height:200px;box-shadow:0 4px 6px #0000001a}.smt-select-pocket:has(ul){overflow-y:auto}.smt-select-pocket.open-reverse{top:auto;bottom:100%;border-top:1px solid var(--border-color, #ccc);border-bottom:none;border-radius:var(--border-radius, 4px) var(--border-radius, 4px) 0 0}.smt-select-pocket .smt-select-option{padding:8px 12px;font-size:13px;cursor:pointer;display:flex;align-items:center;color:var(--option-text-color, #333);background-color:var(--option-bg-color, transparent);transition:opacity .2s ease}.smt-select-pocket .smt-select-option:hover:not(.disabled){opacity:.8}.smt-select-pocket .smt-select-option.highlighted:not(.disabled){opacity:.8;outline:2px solid var(--active-bg-color, #005f87);outline-offset:-2px}.smt-select-pocket .smt-select-option.active{background-color:var(--active-bg-color, #005f87);color:var(--active-text-color, #fff)}.smt-select-pocket .smt-select-option.disabled{opacity:.5;cursor:not-allowed;color:#999}.smt-select-pocket .smt-select-option.select-all-option{font-weight:600;border-bottom:1px solid var(--border-color, #ccc);background-color:#f9f9f9}.smt-select-pocket .smt-select-option.select-all-option:hover{background-color:var(--hover-bg-color, #f0faff)}.smt-select-pocket .smt-select-option .checkbox-container{margin-right:8px;display:flex;align-items:center}.smt-select-pocket ul{list-style:none;padding:0;margin:0}.smt-select-pocket .smt-select-no-results{padding:8px 12px;font-size:13px;color:#999;text-align:center;font-style:italic}.virtual-scroll-viewport{width:100%;outline:none}.error-message{color:#d9534f;font-size:11px;margin-top:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "pipe", type: SmtSelectSearchFilterPipe, name: "smtSelectSearchFilter" }] });
194
332
  }
195
333
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SmtSelectComponent, decorators: [{
196
334
  type: Component,
197
- args: [{ selector: 'smt-select', standalone: true, imports: [CommonModule, FormsModule, ScrollingModule, SmtSelectSearchFilterPipe], template: "<div *ngIf=\"visibility !== VisibilityType.HIDDEN\" class=\"smt-select-wrapper\" [id]=\"config.fieldID || ''\"\r\n (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"smt-select-control\" (click)=\"togglePocket()\" [class.disabled]=\"visibility === VisibilityType.READONLY\"\r\n [class.error]=\"errorMessage ? true : (errorMessage === undefined ? isInvalid : false)\">\r\n\r\n <!-- Search Input -->\r\n <input #input *ngIf=\"isPocketOpen\" [(ngModel)]=\"searchText\" (click)=\"$event.stopPropagation()\"\r\n (keydown.enter)=\"onEnterPressed()\" (blur)=\"onBlur()\" class=\"smt-select-input\"\r\n [placeholder]=\"config.placeholder || 'Select...'\">\r\n\r\n <!-- Selected Value Display -->\r\n <ng-container *ngIf=\"!isPocketOpen\">\r\n <span class=\"select-value\" [class.placeholder]=\"!hasSelection\">\r\n {{ displayText() }}\r\n </span>\r\n </ng-container>\r\n\r\n <div class=\"arrow-icon\" [class.up]=\"isPocketOpen\"></div>\r\n </div>\r\n\r\n <!-- Dropdown (Pocket) -->\r\n <div #pocket *ngIf=\"isPocketOpen\" class=\"smt-select-pocket\" [class.open-reverse]=\"isOpenReverse\">\r\n\r\n <!-- Standard List -->\r\n <ul *ngIf=\"!config.virtualScroll\">\r\n <li *ngFor=\"let option of options | smtSelectSearchFilter: searchText\" (click)=\"selectOption(option, $event)\"\r\n class=\"smt-select-option\" [class.active]=\"isSelected(option)\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </li>\r\n </ul>\r\n\r\n <!-- Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport *ngIf=\"config.virtualScroll\" itemSize=\"34\" class=\"virtual-scroll-viewport\">\r\n <div *cdkVirtualFor=\"let option of options | smtSelectSearchFilter: searchText\" class=\"smt-select-option\"\r\n (click)=\"selectOption(option, $event)\" [class.active]=\"isSelected(option)\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"error-message\">\r\n {{ errorMessage }}\r\n </div>\r\n</div>", styles: [".smt-select-wrapper{position:relative;width:100%;font-family:Arial,sans-serif;box-sizing:border-box}.smt-select-wrapper *{box-sizing:border-box}.smt-select-control{display:flex;align-items:center;min-height:34px;border:1px solid #ccc;padding:4px 8px;background:#fff;cursor:pointer;position:relative}.smt-select-control.disabled{background:#f5f5f5;cursor:not-allowed;opacity:.7}.smt-select-control.error{border-color:#d9534f}.smt-select-control.error:focus-within{box-shadow:0 0 0 2px #d9534f33}.smt-select-control .select-value{font-size:13px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.smt-select-control .select-value.placeholder{color:#999;font-style:italic}.smt-select-control .smt-select-input{border:none;outline:none;width:100%;font-size:13px;padding:0;background:transparent}.smt-select-control .smt-select-input::placeholder{color:#999;font-style:italic}.smt-select-control .arrow-icon{margin-left:auto;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #666;transition:transform .2s}.smt-select-control .arrow-icon.up{transform:rotate(180deg)}.smt-select-pocket{position:absolute;top:100%;left:0;width:100%;background:#fff;border:1px solid #ccc;border-top:none;z-index:1000;max-height:200px;box-shadow:0 4px 6px #0000001a}.smt-select-pocket:has(ul){overflow-y:auto}.smt-select-pocket.open-reverse{top:auto;bottom:100%;border-top:1px solid #ccc;border-bottom:none}.smt-select-pocket .smt-select-option{padding:8px 12px;font-size:13px;cursor:pointer;display:flex;align-items:center}.smt-select-pocket .smt-select-option:hover{background-color:#f0faff}.smt-select-pocket .smt-select-option.active{background-color:#005f87;color:#fff}.smt-select-pocket .smt-select-option .checkbox-container{margin-right:8px;display:flex;align-items:center}.smt-select-pocket ul{list-style:none;padding:0;margin:0}.virtual-scroll-viewport{height:200px;width:100%;outline:none}.error-message{color:#d9534f;font-size:11px;margin-top:4px}\n"] }]
335
+ args: [{ selector: 'smt-select', standalone: true, imports: [CommonModule, FormsModule, ScrollingModule, SmtSelectSearchFilterPipe], template: "<div *ngIf=\"visibility !== VisibilityType.HIDDEN\" class=\"smt-select-wrapper\" [id]=\"config.fieldID || ''\"\r\n [ngStyle]=\"customStyles\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"smt-select-control\" (click)=\"togglePocket()\" [class.disabled]=\"visibility === VisibilityType.READONLY\"\r\n [class.error]=\"errorMessage ? true : (errorMessage === undefined ? isInvalid : false)\">\r\n\r\n <!-- Search Input -->\r\n <input #input *ngIf=\"isPocketOpen\" [(ngModel)]=\"searchText\" (click)=\"$event.stopPropagation()\"\r\n (keydown)=\"onKeyDown($event)\" (blur)=\"onBlur()\" class=\"smt-select-input\"\r\n [placeholder]=\"config.placeholder || 'Select...'\">\r\n\r\n <!-- Selected Value Display -->\r\n <ng-container *ngIf=\"!isPocketOpen\">\r\n <span class=\"select-value\" [class.placeholder]=\"!hasSelection\">\r\n {{ displayText() }}\r\n </span>\r\n </ng-container>\r\n\r\n <!-- Clear Button -->\r\n <div *ngIf=\"config.clearable && hasSelection && !isPocketOpen\" class=\"clear-icon\" (click)=\"clearSelection($event)\">\r\n \u2715\r\n </div>\r\n\r\n <div class=\"arrow-icon\" [class.up]=\"isPocketOpen\"></div>\r\n </div>\r\n\r\n <!-- Dropdown (Pocket) -->\r\n <div #pocket *ngIf=\"isPocketOpen\" class=\"smt-select-pocket\" [class.open-reverse]=\"isOpenReverse\">\r\n\r\n <!-- Standard List -->\r\n <ul *ngIf=\"!config.virtualScroll\">\r\n <!-- Select All Option -->\r\n <li *ngIf=\"config.isMultiSelect && config.showSelectAll && getFilteredOptions().length > 0\"\r\n (click)=\"toggleSelectAll($event)\" class=\"smt-select-option select-all-option\">\r\n <div class=\"checkbox-container\">\r\n <input type=\"checkbox\"\r\n [checked]=\"selectAllState === 'checked'\"\r\n [indeterminate]=\"selectAllState === 'indeterminate'\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n <span>Select All</span>\r\n </li>\r\n\r\n <li *ngFor=\"let option of options | smtSelectSearchFilter: searchText; let i = index\" (click)=\"selectOption(option, $event)\"\r\n class=\"smt-select-option\" [class.active]=\"isSelected(option)\" [class.disabled]=\"option.disabled\" [class.highlighted]=\"i === highlightedIndex\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </li>\r\n\r\n <!-- No Results Message -->\r\n <li *ngIf=\"getFilteredOptions().length === 0\" class=\"smt-select-no-results\">\r\n {{ config.noResultsMessage || 'No results found' }}\r\n </li>\r\n </ul>\r\n\r\n <!-- Virtual Scroll -->\r\n <ng-container *ngIf=\"config.virtualScroll && getFilteredOptions().length > 0\">\r\n <!-- Select All Option (Fixed Header) -->\r\n <div *ngIf=\"config.isMultiSelect && config.showSelectAll\"\r\n (click)=\"toggleSelectAll($event)\"\r\n class=\"smt-select-option select-all-option\">\r\n <div class=\"checkbox-container\">\r\n <input type=\"checkbox\"\r\n [checked]=\"selectAllState === 'checked'\"\r\n [indeterminate]=\"selectAllState === 'indeterminate'\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n <span>Select All</span>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport itemSize=\"34\" class=\"virtual-scroll-viewport\"\r\n [style.height]=\"getViewportHeight()\">\r\n <div *cdkVirtualFor=\"let option of options | smtSelectSearchFilter: searchText; let i = index\" class=\"smt-select-option\"\r\n (click)=\"selectOption(option, $event)\" [class.active]=\"isSelected(option)\" [class.disabled]=\"option.disabled\" [class.highlighted]=\"i === highlightedIndex\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </ng-container>\r\n\r\n <!-- No Results Message for Virtual Scroll -->\r\n <div *ngIf=\"config.virtualScroll && getFilteredOptions().length === 0\" class=\"smt-select-no-results\">\r\n {{ config.noResultsMessage || 'No results found' }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"error-message\">\r\n {{ errorMessage }}\r\n </div>\r\n</div>", styles: [".smt-select-wrapper{position:relative;width:100%;font-family:Arial,sans-serif;box-sizing:border-box}.smt-select-wrapper *{box-sizing:border-box}.smt-select-control{display:flex;align-items:center;min-height:34px;border:1px solid var(--border-color, #ccc);border-radius:var(--border-radius, 4px);padding:4px 8px;background:#fff;cursor:pointer;position:relative}.smt-select-control.disabled{background:#f5f5f5;cursor:not-allowed;opacity:.7}.smt-select-control.error{border-color:var(--error-border-color, #d9534f)}.smt-select-control.error:focus-within{box-shadow:0 0 0 2px #d9534f33}.smt-select-control .select-value{font-size:13px;color:var(--input-text-color, #333);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.smt-select-control .select-value.placeholder{opacity:.6;font-style:italic}.smt-select-control .smt-select-input{border:none;outline:none;width:100%;font-size:13px;padding:0;background:transparent;color:var(--input-text-color, #333)}.smt-select-control .smt-select-input::placeholder{color:var(--input-text-color, #333);opacity:.6;font-style:italic}.smt-select-control .clear-icon{margin-left:8px;margin-right:4px;color:#666;font-size:16px;cursor:pointer;display:flex;align-items:center;padding:0 4px;flex-shrink:0}.smt-select-control .clear-icon:hover{color:#d9534f}.smt-select-control .arrow-icon{margin-left:auto;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #666;transition:transform .2s}.smt-select-control .arrow-icon.up{transform:rotate(180deg)}.smt-select-pocket{position:absolute;top:100%;left:0;width:100%;background:#fff;border:1px solid var(--border-color, #ccc);border-top:none;border-radius:0 0 var(--border-radius, 4px) var(--border-radius, 4px);z-index:1000;max-height:200px;box-shadow:0 4px 6px #0000001a}.smt-select-pocket:has(ul){overflow-y:auto}.smt-select-pocket.open-reverse{top:auto;bottom:100%;border-top:1px solid var(--border-color, #ccc);border-bottom:none;border-radius:var(--border-radius, 4px) var(--border-radius, 4px) 0 0}.smt-select-pocket .smt-select-option{padding:8px 12px;font-size:13px;cursor:pointer;display:flex;align-items:center;color:var(--option-text-color, #333);background-color:var(--option-bg-color, transparent);transition:opacity .2s ease}.smt-select-pocket .smt-select-option:hover:not(.disabled){opacity:.8}.smt-select-pocket .smt-select-option.highlighted:not(.disabled){opacity:.8;outline:2px solid var(--active-bg-color, #005f87);outline-offset:-2px}.smt-select-pocket .smt-select-option.active{background-color:var(--active-bg-color, #005f87);color:var(--active-text-color, #fff)}.smt-select-pocket .smt-select-option.disabled{opacity:.5;cursor:not-allowed;color:#999}.smt-select-pocket .smt-select-option.select-all-option{font-weight:600;border-bottom:1px solid var(--border-color, #ccc);background-color:#f9f9f9}.smt-select-pocket .smt-select-option.select-all-option:hover{background-color:var(--hover-bg-color, #f0faff)}.smt-select-pocket .smt-select-option .checkbox-container{margin-right:8px;display:flex;align-items:center}.smt-select-pocket ul{list-style:none;padding:0;margin:0}.smt-select-pocket .smt-select-no-results{padding:8px 12px;font-size:13px;color:#999;text-align:center;font-style:italic}.virtual-scroll-viewport{width:100%;outline:none}.error-message{color:#d9534f;font-size:11px;margin-top:4px}\n"] }]
198
336
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { options: [{
199
337
  type: Input
200
338
  }], config: [{
@@ -1 +1 @@
1
- {"version":3,"file":"smt-select.mjs","sources":["../../../projects/smt-select/src/lib/models/index.ts","../../../projects/smt-select/src/lib/pipes/smt-select-search-filter.pipe.ts","../../../projects/smt-select/src/lib/components/smt-select/smt-select.component.ts","../../../projects/smt-select/src/lib/components/smt-select/smt-select.component.html","../../../projects/smt-select/src/public-api.ts","../../../projects/smt-select/src/smt-select.ts"],"sourcesContent":["export interface SmtSelectOption {\r\n value: any;\r\n label: string;\r\n [key: string]: any;\r\n}\r\n\r\nexport enum SmtVisibilityType {\r\n HIDDEN = 'HIDDEN',\r\n READONLY = 'READONLY',\r\n ENABLED = 'ENABLED'\r\n}\r\n\r\nexport interface SmtSelectConfig {\r\n fieldID?: string | number;\r\n placeholder?: string;\r\n virtualScroll?: boolean;\r\n isMultiSelect?: boolean;\r\n}\r\n","import { Pipe, PipeTransform } from '@angular/core';\r\nimport { SmtSelectOption } from '../models';\r\n\r\n@Pipe({\r\n name: 'smtSelectSearchFilter',\r\n standalone: true,\r\n pure: true\r\n})\r\nexport class SmtSelectSearchFilterPipe implements PipeTransform {\r\n transform(options: SmtSelectOption[], searchText: string): SmtSelectOption[] {\r\n if (!options) return [];\r\n if (!searchText) return options;\r\n\r\n searchText = searchText.toLowerCase();\r\n\r\n return options.filter(option => {\r\n return option.label.toLowerCase().includes(searchText) ||\r\n (typeof option.value === 'string' && option.value.toLowerCase().includes(searchText));\r\n });\r\n }\r\n}\r\n","import {\r\n Component, Input, Output, EventEmitter,\r\n ElementRef, Renderer2, ViewChild, OnDestroy\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { ScrollingModule } from '@angular/cdk/scrolling';\r\nimport {\r\n SmtSelectOption, SmtSelectConfig,\r\n SmtVisibilityType\r\n} from '../../models';\r\nimport { SmtSelectSearchFilterPipe } from '../../pipes/smt-select-search-filter.pipe';\r\nimport { timer, take } from 'rxjs';\r\n\r\n@Component({\r\n selector: 'smt-select',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, ScrollingModule, SmtSelectSearchFilterPipe],\r\n templateUrl: './smt-select.component.html',\r\n styleUrls: ['./smt-select.component.scss']\r\n})\r\nexport class SmtSelectComponent implements OnDestroy {\r\n @Input() options: SmtSelectOption[] = [];\r\n @Input() config: SmtSelectConfig = {};\r\n @Input() selectedValue: any | any[] = null;\r\n @Input() errorMessage?: string | null;\r\n @Input() isInvalid = false;\r\n @Input() visibility: SmtVisibilityType = SmtVisibilityType.ENABLED;\r\n\r\n @Output() selectionChange = new EventEmitter<any | any[]>();\r\n @Output() selectedValueChange = new EventEmitter<any | any[]>();\r\n @Output() pocketOpen = new EventEmitter<boolean>();\r\n\r\n @ViewChild('pocket') pocketElement!: ElementRef;\r\n @ViewChild('input') inputElement!: ElementRef;\r\n\r\n isPocketOpen = false;\r\n isOpenReverse = false;\r\n searchText = '';\r\n\r\n private clickListener: (() => void) | null = null;\r\n public VisibilityType = SmtVisibilityType;\r\n\r\n constructor(private el: ElementRef, private renderer: Renderer2) { }\r\n\r\n ngOnDestroy(): void {\r\n this.removeOutsideClickListener();\r\n }\r\n\r\n get hasSelection(): boolean {\r\n if (this.config.isMultiSelect) {\r\n return Array.isArray(this.selectedValue) && this.selectedValue.length > 0;\r\n }\r\n return this.selectedValue !== null && this.selectedValue !== undefined && this.selectedValue !== '';\r\n }\r\n\r\n displayText(): string {\r\n if (!this.hasSelection) return this.config.placeholder || 'Select...';\r\n\r\n if (this.config.isMultiSelect) {\r\n const selectedOptions = this.options.filter(opt =>\r\n (this.selectedValue as any[]).includes(opt.value)\r\n );\r\n return selectedOptions.map(opt => opt.label).join(', ');\r\n }\r\n\r\n const selectedOption = this.options.find(opt => opt.value === this.selectedValue);\r\n return selectedOption ? selectedOption.label : (this.selectedValue as string);\r\n }\r\n\r\n togglePocket(): void {\r\n if (this.visibility === SmtVisibilityType.READONLY) {\r\n return;\r\n }\r\n\r\n if (this.isPocketOpen) {\r\n this.closePocket();\r\n } else {\r\n this.openPocket();\r\n }\r\n }\r\n\r\n private openPocket(): void {\r\n this.calculateDirection();\r\n this.isPocketOpen = true;\r\n this.pocketOpen.emit(true);\r\n this.searchText = '';\r\n this.focusInput();\r\n this.addOutsideClickListener();\r\n }\r\n\r\n private closePocket(): void {\r\n if (!this.isPocketOpen) return;\r\n this.isPocketOpen = false;\r\n this.pocketOpen.emit(false);\r\n this.removeOutsideClickListener();\r\n }\r\n\r\n private addOutsideClickListener(): void {\r\n if (this.clickListener) return;\r\n\r\n // Only clicks outside can reach the document, so we can close directly\r\n this.clickListener = this.renderer.listen('document', 'mousedown', () => {\r\n this.closePocket();\r\n });\r\n }\r\n\r\n private removeOutsideClickListener(): void {\r\n if (this.clickListener) {\r\n this.clickListener();\r\n this.clickListener = null;\r\n }\r\n }\r\n\r\n private calculateDirection(): void {\r\n const rect = this.el.nativeElement.getBoundingClientRect();\r\n const windowHeight = window.innerHeight;\r\n const pocketHeight = 200; // max-height \r\n\r\n if (windowHeight - rect.bottom < pocketHeight && rect.top > pocketHeight) {\r\n this.isOpenReverse = true;\r\n } else {\r\n this.isOpenReverse = false;\r\n }\r\n }\r\n\r\n private focusInput(): void {\r\n timer(100).pipe(take(1)).subscribe(() => {\r\n this.inputElement?.nativeElement.focus();\r\n });\r\n }\r\n\r\n onBlur(): void {\r\n // Keyboard exit scenarios delay\r\n timer(200).pipe(take(1)).subscribe(() => {\r\n if (this.isPocketOpen) {\r\n this.closePocket();\r\n }\r\n });\r\n }\r\n\r\n isSelected(option: SmtSelectOption): boolean {\r\n if (this.config.isMultiSelect) {\r\n return Array.isArray(this.selectedValue) && this.selectedValue.includes(option.value);\r\n }\r\n return this.selectedValue === option.value;\r\n }\r\n\r\n onEnterPressed(): void {\r\n if (!this.searchText) return;\r\n\r\n const filtered = this.options.filter(option =>\r\n option.label.toLowerCase().includes(this.searchText.toLowerCase()) ||\r\n (typeof option.value === 'string' && option.value.toLowerCase().includes(this.searchText.toLowerCase()))\r\n );\r\n\r\n if (filtered.length > 0) {\r\n this.selectOption(filtered[0]);\r\n this.closePocket();\r\n if (this.config.isMultiSelect) {\r\n this.searchText = '';\r\n }\r\n }\r\n }\r\n\r\n selectOption(option: SmtSelectOption, event?: MouseEvent): void {\r\n if (event) {\r\n event.stopPropagation();\r\n }\r\n\r\n if (this.config.isMultiSelect) {\r\n if (!Array.isArray(this.selectedValue)) {\r\n this.selectedValue = [];\r\n }\r\n\r\n const index = this.selectedValue.indexOf(option.value);\r\n if (index > -1) {\r\n this.selectedValue.splice(index, 1);\r\n } else {\r\n this.selectedValue.push(option.value);\r\n }\r\n\r\n // View update for spread or slice \r\n this.selectedValue = [...this.selectedValue];\r\n } else {\r\n this.selectedValue = option.value;\r\n }\r\n\r\n this.closePocket();\r\n this.selectionChange.emit(this.selectedValue);\r\n this.selectedValueChange.emit(this.selectedValue);\r\n }\r\n}\r\n","<div *ngIf=\"visibility !== VisibilityType.HIDDEN\" class=\"smt-select-wrapper\" [id]=\"config.fieldID || ''\"\r\n (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"smt-select-control\" (click)=\"togglePocket()\" [class.disabled]=\"visibility === VisibilityType.READONLY\"\r\n [class.error]=\"errorMessage ? true : (errorMessage === undefined ? isInvalid : false)\">\r\n\r\n <!-- Search Input -->\r\n <input #input *ngIf=\"isPocketOpen\" [(ngModel)]=\"searchText\" (click)=\"$event.stopPropagation()\"\r\n (keydown.enter)=\"onEnterPressed()\" (blur)=\"onBlur()\" class=\"smt-select-input\"\r\n [placeholder]=\"config.placeholder || 'Select...'\">\r\n\r\n <!-- Selected Value Display -->\r\n <ng-container *ngIf=\"!isPocketOpen\">\r\n <span class=\"select-value\" [class.placeholder]=\"!hasSelection\">\r\n {{ displayText() }}\r\n </span>\r\n </ng-container>\r\n\r\n <div class=\"arrow-icon\" [class.up]=\"isPocketOpen\"></div>\r\n </div>\r\n\r\n <!-- Dropdown (Pocket) -->\r\n <div #pocket *ngIf=\"isPocketOpen\" class=\"smt-select-pocket\" [class.open-reverse]=\"isOpenReverse\">\r\n\r\n <!-- Standard List -->\r\n <ul *ngIf=\"!config.virtualScroll\">\r\n <li *ngFor=\"let option of options | smtSelectSearchFilter: searchText\" (click)=\"selectOption(option, $event)\"\r\n class=\"smt-select-option\" [class.active]=\"isSelected(option)\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </li>\r\n </ul>\r\n\r\n <!-- Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport *ngIf=\"config.virtualScroll\" itemSize=\"34\" class=\"virtual-scroll-viewport\">\r\n <div *cdkVirtualFor=\"let option of options | smtSelectSearchFilter: searchText\" class=\"smt-select-option\"\r\n (click)=\"selectOption(option, $event)\" [class.active]=\"isSelected(option)\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"error-message\">\r\n {{ errorMessage }}\r\n </div>\r\n</div>","/*\r\n * Public API Surface of smt-select\r\n */\r\n\r\nexport * from './lib/models';\r\nexport * from './lib/components/smt-select/smt-select.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":"smt-select.mjs","sources":["../../../projects/smt-select/src/lib/models/index.ts","../../../projects/smt-select/src/lib/pipes/smt-select-search-filter.pipe.ts","../../../projects/smt-select/src/lib/components/smt-select/smt-select.component.ts","../../../projects/smt-select/src/lib/components/smt-select/smt-select.component.html","../../../projects/smt-select/src/public-api.ts","../../../projects/smt-select/src/smt-select.ts"],"sourcesContent":["export interface SmtSelectOption {\r\n value: any;\r\n label: string;\r\n disabled?: boolean;\r\n [key: string]: any;\r\n}\r\n\r\nexport enum SmtVisibilityType {\r\n HIDDEN = 'HIDDEN',\r\n READONLY = 'READONLY',\r\n ENABLED = 'ENABLED'\r\n}\r\n\r\nexport interface SmtSelectConfig {\r\n fieldID?: string | number;\r\n placeholder?: string;\r\n virtualScroll?: boolean;\r\n isMultiSelect?: boolean;\r\n clearable?: boolean;\r\n showSelectAll?: boolean;\r\n noResultsMessage?: string;\r\n // Theme customization\r\n optionActiveBackgroundColor?: string;\r\n optionActiveTextColor?: string;\r\n hoverBackgroundColor?: string;\r\n optionTextColor?: string;\r\n optionBackgroundColor?: string;\r\n inputTextColor?: string;\r\n borderColor?: string;\r\n errorBorderColor?: string;\r\n borderRadius?: string | number;\r\n}\r\n","import { Pipe, PipeTransform } from '@angular/core';\r\nimport { SmtSelectOption } from '../models';\r\n\r\n@Pipe({\r\n name: 'smtSelectSearchFilter',\r\n standalone: true,\r\n pure: true\r\n})\r\nexport class SmtSelectSearchFilterPipe implements PipeTransform {\r\n transform(options: SmtSelectOption[], searchText: string): SmtSelectOption[] {\r\n if (!options) return [];\r\n if (!searchText) return options;\r\n\r\n searchText = searchText.toLowerCase();\r\n\r\n return options.filter(option => {\r\n return option.label.toLowerCase().includes(searchText) ||\r\n (typeof option.value === 'string' && option.value.toLowerCase().includes(searchText));\r\n });\r\n }\r\n}\r\n","import {\r\n Component, Input, Output, EventEmitter,\r\n ElementRef, Renderer2, ViewChild, OnDestroy\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { ScrollingModule } from '@angular/cdk/scrolling';\r\nimport {\r\n SmtSelectOption, SmtSelectConfig,\r\n SmtVisibilityType\r\n} from '../../models';\r\nimport { SmtSelectSearchFilterPipe } from '../../pipes/smt-select-search-filter.pipe';\r\nimport { timer, take, Subscription } from 'rxjs';\r\n\r\n@Component({\r\n selector: 'smt-select',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, ScrollingModule, SmtSelectSearchFilterPipe],\r\n templateUrl: './smt-select.component.html',\r\n styleUrls: ['./smt-select.component.scss']\r\n})\r\nexport class SmtSelectComponent implements OnDestroy {\r\n @Input() options: SmtSelectOption[] = [];\r\n @Input() config: SmtSelectConfig = {};\r\n @Input() selectedValue: any | any[] = null;\r\n @Input() errorMessage?: string | null;\r\n @Input() isInvalid = false;\r\n @Input() visibility: SmtVisibilityType = SmtVisibilityType.ENABLED;\r\n\r\n @Output() selectionChange = new EventEmitter<any | any[]>();\r\n @Output() selectedValueChange = new EventEmitter<any | any[]>();\r\n @Output() pocketOpen = new EventEmitter<boolean>();\r\n\r\n @ViewChild('pocket') pocketElement!: ElementRef;\r\n @ViewChild('input') inputElement!: ElementRef;\r\n\r\n isPocketOpen = false;\r\n isOpenReverse = false;\r\n searchText = '';\r\n highlightedIndex = -1;\r\n\r\n private clickListener: (() => void) | null = null;\r\n private blurTimerSubscription: Subscription | null = null;\r\n public VisibilityType = SmtVisibilityType;\r\n\r\n constructor(private el: ElementRef, private renderer: Renderer2) { }\r\n\r\n ngOnDestroy(): void {\r\n this.removeOutsideClickListener();\r\n this.cancelBlurTimer();\r\n }\r\n\r\n get hasSelection(): boolean {\r\n if (this.config.isMultiSelect) {\r\n return Array.isArray(this.selectedValue) && this.selectedValue.length > 0;\r\n }\r\n return this.selectedValue !== null && this.selectedValue !== undefined && this.selectedValue !== '';\r\n }\r\n\r\n get selectAllState(): 'checked' | 'indeterminate' | 'unchecked' {\r\n if (!this.config.isMultiSelect) return 'unchecked';\r\n\r\n const filtered = this.getFilteredOptions();\r\n const selectableOptions = filtered.filter(opt => !opt.disabled);\r\n\r\n if (selectableOptions.length === 0) return 'unchecked';\r\n\r\n const selectedCount = selectableOptions.filter(opt =>\r\n Array.isArray(this.selectedValue) && this.selectedValue.includes(opt.value)\r\n ).length;\r\n\r\n if (selectedCount === 0) return 'unchecked';\r\n if (selectedCount === selectableOptions.length) return 'checked';\r\n return 'indeterminate';\r\n }\r\n\r\n get customStyles(): { [key: string]: string } {\r\n const borderRadius = typeof this.config.borderRadius === 'number'\r\n ? `${this.config.borderRadius}px`\r\n : (this.config.borderRadius || '4px');\r\n\r\n return {\r\n '--active-bg-color': this.config.optionActiveBackgroundColor || '#005f87',\r\n '--active-text-color': this.config.optionActiveTextColor || '#fff',\r\n '--hover-bg-color': this.config.hoverBackgroundColor || '#f0faff',\r\n '--option-text-color': this.config.optionTextColor || '#333',\r\n '--option-bg-color': this.config.optionBackgroundColor || 'transparent',\r\n '--input-text-color': this.config.inputTextColor || '#333',\r\n '--border-color': this.config.borderColor || '#ccc',\r\n '--error-border-color': this.config.errorBorderColor || '#d9534f',\r\n '--border-radius': borderRadius\r\n };\r\n }\r\n\r\n displayText(): string {\r\n if (!this.hasSelection) return this.config.placeholder || 'Select...';\r\n\r\n if (this.config.isMultiSelect) {\r\n const selectedOptions = this.options.filter(opt =>\r\n (this.selectedValue as any[]).includes(opt.value)\r\n );\r\n return selectedOptions.map(opt => opt.label).join(', ');\r\n }\r\n\r\n const selectedOption = this.options.find(opt => opt.value === this.selectedValue);\r\n return selectedOption ? selectedOption.label : (this.selectedValue as string);\r\n }\r\n\r\n togglePocket(): void {\r\n if (this.visibility === SmtVisibilityType.READONLY) {\r\n return;\r\n }\r\n\r\n if (this.isPocketOpen) {\r\n this.closePocket();\r\n } else {\r\n this.openPocket();\r\n }\r\n }\r\n\r\n private openPocket(): void {\r\n this.calculateDirection();\r\n this.isPocketOpen = true;\r\n this.pocketOpen.emit(true);\r\n this.searchText = '';\r\n this.highlightedIndex = -1;\r\n this.focusInput();\r\n this.addOutsideClickListener();\r\n }\r\n\r\n private closePocket(): void {\r\n if (!this.isPocketOpen) return;\r\n this.isPocketOpen = false;\r\n this.pocketOpen.emit(false);\r\n this.removeOutsideClickListener();\r\n this.cancelBlurTimer();\r\n }\r\n\r\n private addOutsideClickListener(): void {\r\n if (this.clickListener) return;\r\n\r\n // Only clicks outside can reach the document, so we can close directly\r\n this.clickListener = this.renderer.listen('document', 'mousedown', () => {\r\n this.closePocket();\r\n });\r\n }\r\n\r\n private removeOutsideClickListener(): void {\r\n if (this.clickListener) {\r\n this.clickListener();\r\n this.clickListener = null;\r\n }\r\n }\r\n\r\n private calculateDirection(): void {\r\n const rect = this.el.nativeElement.getBoundingClientRect();\r\n const windowHeight = window.innerHeight;\r\n const pocketHeight = 200; // max-height \r\n\r\n if (windowHeight - rect.bottom < pocketHeight && rect.top > pocketHeight) {\r\n this.isOpenReverse = true;\r\n } else {\r\n this.isOpenReverse = false;\r\n }\r\n }\r\n\r\n private focusInput(): void {\r\n timer(100).pipe(take(1)).subscribe(() => {\r\n this.inputElement?.nativeElement.focus();\r\n });\r\n }\r\n\r\n onBlur(): void {\r\n // Keyboard exit scenarios delay\r\n this.blurTimerSubscription = timer(200).pipe(take(1)).subscribe(() => {\r\n if (this.isPocketOpen) {\r\n this.closePocket();\r\n }\r\n });\r\n }\r\n\r\n private cancelBlurTimer(): void {\r\n if (this.blurTimerSubscription) {\r\n this.blurTimerSubscription.unsubscribe();\r\n this.blurTimerSubscription = null;\r\n }\r\n }\r\n\r\n isSelected(option: SmtSelectOption): boolean {\r\n if (this.config.isMultiSelect) {\r\n return Array.isArray(this.selectedValue) && this.selectedValue.includes(option.value);\r\n }\r\n return this.selectedValue === option.value;\r\n }\r\n\r\n getFilteredOptions(): SmtSelectOption[] {\r\n if (!this.searchText) return this.options;\r\n\r\n const searchLower = this.searchText.toLowerCase();\r\n return this.options.filter(option =>\r\n option.label.toLowerCase().includes(searchLower) ||\r\n (typeof option.value === 'string' && option.value.toLowerCase().includes(searchLower))\r\n );\r\n }\r\n\r\n getViewportHeight(): string {\r\n const filteredCount = this.getFilteredOptions().length;\r\n const itemHeight = 34; // itemSize from template\r\n const maxHeight = 200;\r\n const calculatedHeight = filteredCount * itemHeight;\r\n return `${Math.min(calculatedHeight, maxHeight)}px`;\r\n }\r\n\r\n onEnterPressed(): void {\r\n const filtered = this.getFilteredOptions();\r\n\r\n // If an option is highlighted, select it\r\n if (this.highlightedIndex >= 0 && this.highlightedIndex < filtered.length) {\r\n this.selectOption(filtered[this.highlightedIndex]);\r\n if (!this.config.isMultiSelect) {\r\n this.closePocket();\r\n }\r\n return;\r\n }\r\n\r\n // Otherwise, select first match if searching\r\n if (this.searchText && filtered.length > 0) {\r\n this.selectOption(filtered[0]);\r\n if (!this.config.isMultiSelect) {\r\n this.closePocket();\r\n }\r\n }\r\n }\r\n\r\n onKeyDown(event: KeyboardEvent): void {\r\n const filtered = this.getFilteredOptions();\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n this.highlightedIndex = Math.min(this.highlightedIndex + 1, filtered.length - 1);\r\n this.scrollToHighlighted();\r\n break;\r\n\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);\r\n this.scrollToHighlighted();\r\n break;\r\n\r\n case 'Escape':\r\n event.preventDefault();\r\n this.closePocket();\r\n break;\r\n\r\n case 'Enter':\r\n event.preventDefault();\r\n this.onEnterPressed();\r\n break;\r\n }\r\n }\r\n\r\n private scrollToHighlighted(): void {\r\n // Wait for DOM update\r\n setTimeout(() => {\r\n const highlightedElement = this.el.nativeElement.querySelector('.smt-select-option.highlighted');\r\n if (highlightedElement) {\r\n highlightedElement.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'nearest'\r\n });\r\n }\r\n }, 0);\r\n }\r\n\r\n selectOption(option: SmtSelectOption, event?: MouseEvent): void {\r\n if (event) {\r\n event.stopPropagation();\r\n }\r\n\r\n // Don't select disabled options\r\n if (option.disabled) {\r\n return;\r\n }\r\n\r\n if (this.config.isMultiSelect) {\r\n if (!Array.isArray(this.selectedValue)) {\r\n this.selectedValue = [];\r\n }\r\n\r\n const index = this.selectedValue.indexOf(option.value);\r\n if (index > -1) {\r\n this.selectedValue.splice(index, 1);\r\n } else {\r\n this.selectedValue.push(option.value);\r\n }\r\n\r\n // View update for spread or slice\r\n this.selectedValue = [...this.selectedValue];\r\n } else {\r\n this.selectedValue = option.value;\r\n }\r\n\r\n if (!this.config.isMultiSelect) {\r\n this.closePocket();\r\n } else {\r\n // Cancel any pending blur timer and re-focus input\r\n this.cancelBlurTimer();\r\n this.focusInput();\r\n }\r\n this.selectionChange.emit(this.selectedValue);\r\n this.selectedValueChange.emit(this.selectedValue);\r\n }\r\n\r\n clearSelection(event: MouseEvent): void {\r\n event.stopPropagation();\r\n this.selectedValue = this.config.isMultiSelect ? [] : null;\r\n this.selectionChange.emit(this.selectedValue);\r\n this.selectedValueChange.emit(this.selectedValue);\r\n }\r\n\r\n toggleSelectAll(event?: MouseEvent): void {\r\n if (event) {\r\n event.stopPropagation();\r\n }\r\n\r\n if (!this.config.isMultiSelect) return;\r\n\r\n const filtered = this.getFilteredOptions();\r\n const selectableOptions = filtered.filter(opt => !opt.disabled);\r\n\r\n if (!Array.isArray(this.selectedValue)) {\r\n this.selectedValue = [];\r\n }\r\n\r\n const allSelected = this.selectAllState === 'checked';\r\n\r\n if (allSelected) {\r\n // Deselect all visible options\r\n this.selectedValue = this.selectedValue.filter(\r\n (val: any) => !selectableOptions.some(opt => opt.value === val)\r\n );\r\n } else {\r\n // Select all visible options\r\n const valuesToAdd = selectableOptions\r\n .filter((opt: SmtSelectOption) => !this.selectedValue.includes(opt.value))\r\n .map((opt: SmtSelectOption) => opt.value);\r\n this.selectedValue = [...this.selectedValue, ...valuesToAdd];\r\n }\r\n\r\n this.selectionChange.emit(this.selectedValue);\r\n this.selectedValueChange.emit(this.selectedValue);\r\n }\r\n}\r\n","<div *ngIf=\"visibility !== VisibilityType.HIDDEN\" class=\"smt-select-wrapper\" [id]=\"config.fieldID || ''\"\r\n [ngStyle]=\"customStyles\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"smt-select-control\" (click)=\"togglePocket()\" [class.disabled]=\"visibility === VisibilityType.READONLY\"\r\n [class.error]=\"errorMessage ? true : (errorMessage === undefined ? isInvalid : false)\">\r\n\r\n <!-- Search Input -->\r\n <input #input *ngIf=\"isPocketOpen\" [(ngModel)]=\"searchText\" (click)=\"$event.stopPropagation()\"\r\n (keydown)=\"onKeyDown($event)\" (blur)=\"onBlur()\" class=\"smt-select-input\"\r\n [placeholder]=\"config.placeholder || 'Select...'\">\r\n\r\n <!-- Selected Value Display -->\r\n <ng-container *ngIf=\"!isPocketOpen\">\r\n <span class=\"select-value\" [class.placeholder]=\"!hasSelection\">\r\n {{ displayText() }}\r\n </span>\r\n </ng-container>\r\n\r\n <!-- Clear Button -->\r\n <div *ngIf=\"config.clearable && hasSelection && !isPocketOpen\" class=\"clear-icon\" (click)=\"clearSelection($event)\">\r\n ✕\r\n </div>\r\n\r\n <div class=\"arrow-icon\" [class.up]=\"isPocketOpen\"></div>\r\n </div>\r\n\r\n <!-- Dropdown (Pocket) -->\r\n <div #pocket *ngIf=\"isPocketOpen\" class=\"smt-select-pocket\" [class.open-reverse]=\"isOpenReverse\">\r\n\r\n <!-- Standard List -->\r\n <ul *ngIf=\"!config.virtualScroll\">\r\n <!-- Select All Option -->\r\n <li *ngIf=\"config.isMultiSelect && config.showSelectAll && getFilteredOptions().length > 0\"\r\n (click)=\"toggleSelectAll($event)\" class=\"smt-select-option select-all-option\">\r\n <div class=\"checkbox-container\">\r\n <input type=\"checkbox\"\r\n [checked]=\"selectAllState === 'checked'\"\r\n [indeterminate]=\"selectAllState === 'indeterminate'\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n <span>Select All</span>\r\n </li>\r\n\r\n <li *ngFor=\"let option of options | smtSelectSearchFilter: searchText; let i = index\" (click)=\"selectOption(option, $event)\"\r\n class=\"smt-select-option\" [class.active]=\"isSelected(option)\" [class.disabled]=\"option.disabled\" [class.highlighted]=\"i === highlightedIndex\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </li>\r\n\r\n <!-- No Results Message -->\r\n <li *ngIf=\"getFilteredOptions().length === 0\" class=\"smt-select-no-results\">\r\n {{ config.noResultsMessage || 'No results found' }}\r\n </li>\r\n </ul>\r\n\r\n <!-- Virtual Scroll -->\r\n <ng-container *ngIf=\"config.virtualScroll && getFilteredOptions().length > 0\">\r\n <!-- Select All Option (Fixed Header) -->\r\n <div *ngIf=\"config.isMultiSelect && config.showSelectAll\"\r\n (click)=\"toggleSelectAll($event)\"\r\n class=\"smt-select-option select-all-option\">\r\n <div class=\"checkbox-container\">\r\n <input type=\"checkbox\"\r\n [checked]=\"selectAllState === 'checked'\"\r\n [indeterminate]=\"selectAllState === 'indeterminate'\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n <span>Select All</span>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport itemSize=\"34\" class=\"virtual-scroll-viewport\"\r\n [style.height]=\"getViewportHeight()\">\r\n <div *cdkVirtualFor=\"let option of options | smtSelectSearchFilter: searchText; let i = index\" class=\"smt-select-option\"\r\n (click)=\"selectOption(option, $event)\" [class.active]=\"isSelected(option)\" [class.disabled]=\"option.disabled\" [class.highlighted]=\"i === highlightedIndex\">\r\n\r\n <div *ngIf=\"config.isMultiSelect\" class=\"checkbox-container\">\r\n <input type=\"checkbox\" [checked]=\"isSelected(option)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n\r\n <span>{{ option.label }}</span>\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </ng-container>\r\n\r\n <!-- No Results Message for Virtual Scroll -->\r\n <div *ngIf=\"config.virtualScroll && getFilteredOptions().length === 0\" class=\"smt-select-no-results\">\r\n {{ config.noResultsMessage || 'No results found' }}\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"errorMessage\" class=\"error-message\">\r\n {{ errorMessage }}\r\n </div>\r\n</div>","/*\r\n * Public API Surface of smt-select\r\n */\r\n\r\nexport * from './lib/models';\r\nexport * from './lib/components/smt-select/smt-select.component';\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": "smt-select",
3
- "version": "0.1.8",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
5
  "author": "Samet Acar",
6
6
  "peerDependencies": {
@@ -20,6 +20,7 @@
20
20
  "keywords": [
21
21
  "angular-dropdown-select",
22
22
  "Angular Dropdown Select",
23
+ "Angular Dropdown Multi Select",
23
24
  "Angular Selectbox",
24
25
  "Angular Select",
25
26
  "angular select",
@@ -33,6 +34,7 @@
33
34
  "Angular",
34
35
  "dropdown",
35
36
  "select",
37
+ "multi select",
36
38
  "multi-select",
37
39
  "javascript",
38
40
  "typescript"
@@ -4,6 +4,7 @@ import { OnDestroy, EventEmitter, ElementRef, Renderer2 } from '@angular/core';
4
4
  interface SmtSelectOption {
5
5
  value: any;
6
6
  label: string;
7
+ disabled?: boolean;
7
8
  [key: string]: any;
8
9
  }
9
10
  declare enum SmtVisibilityType {
@@ -16,6 +17,18 @@ interface SmtSelectConfig {
16
17
  placeholder?: string;
17
18
  virtualScroll?: boolean;
18
19
  isMultiSelect?: boolean;
20
+ clearable?: boolean;
21
+ showSelectAll?: boolean;
22
+ noResultsMessage?: string;
23
+ optionActiveBackgroundColor?: string;
24
+ optionActiveTextColor?: string;
25
+ hoverBackgroundColor?: string;
26
+ optionTextColor?: string;
27
+ optionBackgroundColor?: string;
28
+ inputTextColor?: string;
29
+ borderColor?: string;
30
+ errorBorderColor?: string;
31
+ borderRadius?: string | number;
19
32
  }
20
33
 
21
34
  declare class SmtSelectComponent implements OnDestroy {
@@ -35,11 +48,17 @@ declare class SmtSelectComponent implements OnDestroy {
35
48
  isPocketOpen: boolean;
36
49
  isOpenReverse: boolean;
37
50
  searchText: string;
51
+ highlightedIndex: number;
38
52
  private clickListener;
53
+ private blurTimerSubscription;
39
54
  VisibilityType: typeof SmtVisibilityType;
40
55
  constructor(el: ElementRef, renderer: Renderer2);
41
56
  ngOnDestroy(): void;
42
57
  get hasSelection(): boolean;
58
+ get selectAllState(): 'checked' | 'indeterminate' | 'unchecked';
59
+ get customStyles(): {
60
+ [key: string]: string;
61
+ };
43
62
  displayText(): string;
44
63
  togglePocket(): void;
45
64
  private openPocket;
@@ -49,9 +68,16 @@ declare class SmtSelectComponent implements OnDestroy {
49
68
  private calculateDirection;
50
69
  private focusInput;
51
70
  onBlur(): void;
71
+ private cancelBlurTimer;
52
72
  isSelected(option: SmtSelectOption): boolean;
73
+ getFilteredOptions(): SmtSelectOption[];
74
+ getViewportHeight(): string;
53
75
  onEnterPressed(): void;
76
+ onKeyDown(event: KeyboardEvent): void;
77
+ private scrollToHighlighted;
54
78
  selectOption(option: SmtSelectOption, event?: MouseEvent): void;
79
+ clearSelection(event: MouseEvent): void;
80
+ toggleSelectAll(event?: MouseEvent): void;
55
81
  static ɵfac: i0.ɵɵFactoryDeclaration<SmtSelectComponent, never>;
56
82
  static ɵcmp: i0.ɵɵComponentDeclaration<SmtSelectComponent, "smt-select", never, { "options": { "alias": "options"; "required": false; }; "config": { "alias": "config"; "required": false; }; "selectedValue": { "alias": "selectedValue"; "required": false; }; "errorMessage": { "alias": "errorMessage"; "required": false; }; "isInvalid": { "alias": "isInvalid"; "required": false; }; "visibility": { "alias": "visibility"; "required": false; }; }, { "selectionChange": "selectionChange"; "selectedValueChange": "selectedValueChange"; "pocketOpen": "pocketOpen"; }, never, never, true, never>;
57
83
  }