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 +97 -14
- package/fesm2022/smt-select.mjs +150 -12
- package/fesm2022/smt-select.mjs.map +1 -1
- package/package.json +3 -1
- package/types/smt-select.d.ts +26 -0
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
|
+

|
|
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
|
-
|
|
32
|
-
|
|
39
|
+
npm install smt-select
|
|
40
|
+
```
|
|
33
41
|
|
|
34
|
-
|
|
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
|
-
|
|
38
|
-
|
|
44
|
+
<details>
|
|
45
|
+
<summary>💡 Manual CDK Installation (if needed)</summary>
|
|
39
46
|
|
|
40
|
-
|
|
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
|
-
|
|
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
|
|
package/fesm2022/smt-select.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
158
|
-
|
|
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.
|
|
162
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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"
|
package/types/smt-select.d.ts
CHANGED
|
@@ -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
|
}
|