ngx-ntk-icon-picker 20.25.3 → 20.25.4
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 +669 -33
- package/fesm2022/ngx-ntk-icon-picker.mjs +19 -19
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,63 +1,699 @@
|
|
|
1
|
-
#
|
|
1
|
+
# NGX NTK Icon Picker
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**ngx-ntk-icon-picker** - Advanced Angular icon picker component with support for multiple icon libraries including FontAwesome, Material Icons, and PrimeIcons
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 📋 Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The NGX NTK Icon Picker is a powerful Angular component for selecting icons from multiple popular icon libraries. It provides a user-friendly interface with search functionality, customizable styling, and support for FontAwesome (v4, v5, v6), Material Icons, and PrimeIcons. Perfect for applications requiring icon selection capabilities.
|
|
8
|
+
|
|
9
|
+
## 🚀 Installation
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
|
|
12
|
+
npm install ngx-ntk-icon-picker
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
### Dependencies
|
|
16
|
+
|
|
17
|
+
This library requires the following peer dependencies:
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
|
-
|
|
20
|
+
npm install @fortawesome/angular-fontawesome @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons primeicons
|
|
17
21
|
```
|
|
18
22
|
|
|
19
|
-
##
|
|
23
|
+
## 📦 Features
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
### Core Features
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
- **Multi-Icon Library Support** - FontAwesome v4, v5, v6, Material Icons, PrimeIcons
|
|
28
|
+
- **Search Functionality** - Real-time icon search and filtering
|
|
29
|
+
- **Customizable Interface** - Flexible styling and positioning options
|
|
30
|
+
- **Icon Preview** - Visual preview of selected icons
|
|
31
|
+
- **Responsive Design** - Mobile-friendly interface
|
|
32
|
+
- **Accessibility** - ARIA support and keyboard navigation
|
|
33
|
+
|
|
34
|
+
### Advanced Features
|
|
35
|
+
|
|
36
|
+
- **Custom Icon Packs** - Extensible architecture for custom icon libraries
|
|
37
|
+
- **Positioning Options** - Configurable popup positioning
|
|
38
|
+
- **Size Customization** - Adjustable icon and container sizes
|
|
39
|
+
- **Fallback Icons** - Default icon when none is selected
|
|
40
|
+
- **Search Filter Persistence** - Option to maintain search state
|
|
41
|
+
- **Template Customization** - Custom templates for icon display
|
|
42
|
+
|
|
43
|
+
## 🔧 Usage
|
|
44
|
+
|
|
45
|
+
### Basic Setup
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { NgModule } from "@angular/core";
|
|
49
|
+
import { IconPickerModule } from "ngx-ntk-icon-picker";
|
|
50
|
+
|
|
51
|
+
@NgModule({
|
|
52
|
+
imports: [IconPickerModule],
|
|
53
|
+
})
|
|
54
|
+
export class AppModule {}
|
|
25
55
|
```
|
|
26
56
|
|
|
27
|
-
|
|
57
|
+
### Basic Implementation
|
|
28
58
|
|
|
29
|
-
|
|
59
|
+
```html
|
|
60
|
+
<icon-picker [(icon)]="selectedIcon" [ipIconPack]="['fa', 'fa5', 'fa6']" [ipPlaceHolder]="'Select an icon'" (iconSelected)="onIconSelected($event)"> </icon-picker>
|
|
61
|
+
```
|
|
30
62
|
|
|
31
|
-
|
|
63
|
+
### Advanced Configuration
|
|
32
64
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```
|
|
65
|
+
```typescript
|
|
66
|
+
import { Component } from "@angular/core";
|
|
67
|
+
import { Icon, IconType } from "ngx-ntk-icon-picker";
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
69
|
+
@Component({
|
|
70
|
+
selector: "app-icon-selector",
|
|
71
|
+
template: ` <icon-picker [(icon)]="selectedIcon" [ipIconPack]="['fa', 'fa5', 'fa6', 'mat', 'pi']" [ipPosition]="'bottom'" [ipHeight]="400" [ipMaxHeight]="500" [ipWidth]="350" [ipIconSize]="20" [ipIconVerticalPadding]="8" [ipIconHorizontalPadding]="8" [ipPlaceHolder]="'Choose an icon'" [ipFallbackIcon]="'fa fa-star'" [ipKeepSearchFilter]="true" [ipButtonStyleClass]="'btn btn-primary'" [ipInputSearchStyleClass]="'form-control'" [ipDivSearchStyleClass]="'search-container'" (iconSelected)="onIconSelected($event)" (iconPickerOpen)="onIconPickerOpen()" (iconPickerClose)="onIconPickerClose()"> </icon-picker> `,
|
|
72
|
+
})
|
|
73
|
+
export class IconSelectorComponent {
|
|
74
|
+
selectedIcon: string = "fa fa-home";
|
|
42
75
|
|
|
43
|
-
|
|
76
|
+
onIconSelected(icon: Icon): void {
|
|
77
|
+
console.log("Icon selected:", icon);
|
|
78
|
+
// Handle icon selection
|
|
79
|
+
}
|
|
44
80
|
|
|
45
|
-
|
|
81
|
+
onIconPickerOpen(): void {
|
|
82
|
+
console.log("Icon picker opened");
|
|
83
|
+
}
|
|
46
84
|
|
|
47
|
-
|
|
48
|
-
|
|
85
|
+
onIconPickerClose(): void {
|
|
86
|
+
console.log("Icon picker closed");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
49
89
|
```
|
|
50
90
|
|
|
51
|
-
##
|
|
91
|
+
## 📚 API Reference
|
|
52
92
|
|
|
53
|
-
|
|
93
|
+
### Input Properties
|
|
54
94
|
|
|
55
|
-
|
|
56
|
-
|
|
95
|
+
| Property | Type | Default | Description |
|
|
96
|
+
| ------------------------- | -------- | ---------------- | ------------------------------------------------- |
|
|
97
|
+
| `icon` | string | - | Selected icon value (two-way binding) |
|
|
98
|
+
| `ipIconPack` | string[] | ['fa'] | Icon packs to include |
|
|
99
|
+
| `ipPosition` | string | 'bottom' | Popup position ('top', 'bottom', 'left', 'right') |
|
|
100
|
+
| `ipHeight` | number | 300 | Popup height in pixels |
|
|
101
|
+
| `ipMaxHeight` | number | 400 | Maximum popup height in pixels |
|
|
102
|
+
| `ipWidth` | number | 250 | Popup width in pixels |
|
|
103
|
+
| `ipIconSize` | number | 16 | Icon size in pixels |
|
|
104
|
+
| `ipIconVerticalPadding` | number | 4 | Vertical padding around icons |
|
|
105
|
+
| `ipIconHorizontalPadding` | number | 4 | Horizontal padding around icons |
|
|
106
|
+
| `ipPlaceHolder` | string | 'Select an icon' | Placeholder text |
|
|
107
|
+
| `ipFallbackIcon` | string | - | Fallback icon when none selected |
|
|
108
|
+
| `ipKeepSearchFilter` | boolean | false | Keep search filter when reopening |
|
|
109
|
+
| `ipButtonStyleClass` | string | - | CSS class for the button |
|
|
110
|
+
| `ipInputSearchStyleClass` | string | - | CSS class for search input |
|
|
111
|
+
| `ipDivSearchStyleClass` | string | - | CSS class for search container |
|
|
112
|
+
| `ipUseRootViewContainer` | boolean | false | Use root view container for popup |
|
|
113
|
+
|
|
114
|
+
### Output Events
|
|
115
|
+
|
|
116
|
+
| Event | Type | Description |
|
|
117
|
+
| ----------------- | ------------ | ------------------------ |
|
|
118
|
+
| `iconSelected` | EventEmitter | Icon selection event |
|
|
119
|
+
| `iconPickerOpen` | EventEmitter | Icon picker opened event |
|
|
120
|
+
| `iconPickerClose` | EventEmitter | Icon picker closed event |
|
|
121
|
+
|
|
122
|
+
### Icon Interface
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
export class Icon {
|
|
126
|
+
name: string; // Icon name
|
|
127
|
+
id: string; // Unique identifier
|
|
128
|
+
filter?: string[]; // Search filters
|
|
129
|
+
aliases?: string[]; // Alternative names
|
|
130
|
+
type?: IconType; // Icon library type
|
|
131
|
+
iconName?: IconName; // FontAwesome icon name
|
|
132
|
+
prefix?: string; // Icon prefix
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export enum IconType {
|
|
136
|
+
FontAwesome, // FontAwesome v4
|
|
137
|
+
FontAwesome5 = 2, // FontAwesome v5
|
|
138
|
+
Material, // Material Icons
|
|
139
|
+
FontAwesome6, // FontAwesome v6
|
|
140
|
+
PrimeIcons, // PrimeIcons
|
|
141
|
+
}
|
|
57
142
|
```
|
|
58
143
|
|
|
59
|
-
|
|
144
|
+
## 🎨 Customization
|
|
145
|
+
|
|
146
|
+
### Custom Styling
|
|
147
|
+
|
|
148
|
+
```scss
|
|
149
|
+
// Custom icon picker styles
|
|
150
|
+
.icon-picker {
|
|
151
|
+
.icon-picker-button {
|
|
152
|
+
display: flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
gap: 8px;
|
|
155
|
+
padding: 8px 12px;
|
|
156
|
+
border: 1px solid #ddd;
|
|
157
|
+
border-radius: 4px;
|
|
158
|
+
background-color: #fff;
|
|
159
|
+
cursor: pointer;
|
|
160
|
+
transition: all 0.3s ease;
|
|
161
|
+
|
|
162
|
+
&:hover {
|
|
163
|
+
border-color: #2196f3;
|
|
164
|
+
background-color: #f5f5f5;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.selected-icon {
|
|
168
|
+
font-size: 16px;
|
|
169
|
+
color: #333;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.placeholder {
|
|
173
|
+
color: #999;
|
|
174
|
+
font-style: italic;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.icon-picker-popup {
|
|
179
|
+
position: absolute;
|
|
180
|
+
background-color: #fff;
|
|
181
|
+
border: 1px solid #ddd;
|
|
182
|
+
border-radius: 8px;
|
|
183
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
184
|
+
z-index: 1000;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
|
|
187
|
+
.search-container {
|
|
188
|
+
padding: 12px;
|
|
189
|
+
border-bottom: 1px solid #eee;
|
|
190
|
+
|
|
191
|
+
.search-input {
|
|
192
|
+
width: 100%;
|
|
193
|
+
padding: 8px 12px;
|
|
194
|
+
border: 1px solid #ddd;
|
|
195
|
+
border-radius: 4px;
|
|
196
|
+
font-size: 14px;
|
|
197
|
+
|
|
198
|
+
&:focus {
|
|
199
|
+
outline: none;
|
|
200
|
+
border-color: #2196f3;
|
|
201
|
+
box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.2);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.icons-container {
|
|
207
|
+
max-height: 300px;
|
|
208
|
+
overflow-y: auto;
|
|
209
|
+
padding: 8px;
|
|
210
|
+
|
|
211
|
+
.icon-item {
|
|
212
|
+
display: inline-flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
justify-content: center;
|
|
215
|
+
width: 32px;
|
|
216
|
+
height: 32px;
|
|
217
|
+
margin: 2px;
|
|
218
|
+
border: 1px solid transparent;
|
|
219
|
+
border-radius: 4px;
|
|
220
|
+
cursor: pointer;
|
|
221
|
+
transition: all 0.2s ease;
|
|
222
|
+
|
|
223
|
+
&:hover {
|
|
224
|
+
border-color: #2196f3;
|
|
225
|
+
background-color: #f0f8ff;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
&.selected {
|
|
229
|
+
border-color: #2196f3;
|
|
230
|
+
background-color: #e3f2fd;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
i {
|
|
234
|
+
font-size: 16px;
|
|
235
|
+
color: #333;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Custom Icon Pack
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { Injectable } from "@angular/core";
|
|
247
|
+
import { Icon, IconType } from "ngx-ntk-icon-picker";
|
|
248
|
+
import { IconsPack } from "ngx-ntk-icon-picker";
|
|
249
|
+
|
|
250
|
+
@Injectable()
|
|
251
|
+
export class CustomIconsPack implements IconsPack {
|
|
252
|
+
getIcons(): Icon[] {
|
|
253
|
+
return [
|
|
254
|
+
{
|
|
255
|
+
name: "custom-icon-1",
|
|
256
|
+
id: "custom-1",
|
|
257
|
+
filter: ["custom", "icon", "one"],
|
|
258
|
+
type: IconType.FontAwesome,
|
|
259
|
+
prefix: "custom",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "custom-icon-2",
|
|
263
|
+
id: "custom-2",
|
|
264
|
+
filter: ["custom", "icon", "two"],
|
|
265
|
+
type: IconType.FontAwesome,
|
|
266
|
+
prefix: "custom",
|
|
267
|
+
},
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## 🌐 Icon Libraries Support
|
|
274
|
+
|
|
275
|
+
### FontAwesome v4 (fa)
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// Include FontAwesome v4 icons
|
|
279
|
+
[ipIconPack] = "['fa']";
|
|
280
|
+
|
|
281
|
+
// Example icons
|
|
282
|
+
("fa fa-home");
|
|
283
|
+
("fa fa-user");
|
|
284
|
+
("fa fa-cog");
|
|
285
|
+
("fa fa-heart");
|
|
286
|
+
("fa fa-star");
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### FontAwesome v5 (fa5)
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// Include FontAwesome v5 icons
|
|
293
|
+
[ipIconPack] = "['fa5']";
|
|
294
|
+
|
|
295
|
+
// Example icons
|
|
296
|
+
("fas fa-home");
|
|
297
|
+
("far fa-user");
|
|
298
|
+
("fab fa-angular");
|
|
299
|
+
("fal fa-cog");
|
|
300
|
+
("fad fa-heart");
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### FontAwesome v6 (fa6)
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
// Include FontAwesome v6 icons
|
|
307
|
+
[ipIconPack] = "['fa6']";
|
|
308
|
+
|
|
309
|
+
// Example icons
|
|
310
|
+
("fa-solid fa-home");
|
|
311
|
+
("fa-regular fa-user");
|
|
312
|
+
("fa-brands fa-angular");
|
|
313
|
+
("fa-light fa-cog");
|
|
314
|
+
("fa-duotone fa-heart");
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Material Icons (mat)
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// Include Material Icons
|
|
321
|
+
[ipIconPack] = "['mat']";
|
|
322
|
+
|
|
323
|
+
// Example icons
|
|
324
|
+
("mat home");
|
|
325
|
+
("mat person");
|
|
326
|
+
("mat settings");
|
|
327
|
+
("mat favorite");
|
|
328
|
+
("mat star");
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### PrimeIcons (pi)
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
// Include PrimeIcons
|
|
335
|
+
[ipIconPack] = "['pi']";
|
|
336
|
+
|
|
337
|
+
// Example icons
|
|
338
|
+
("pi pi-home");
|
|
339
|
+
("pi pi-user");
|
|
340
|
+
("pi pi-cog");
|
|
341
|
+
("pi pi-heart");
|
|
342
|
+
("pi pi-star");
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Multiple Icon Packs
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Include all icon packs
|
|
349
|
+
[ipIconPack] = // Or use 'all' shorthand
|
|
350
|
+
"['fa', 'fa5', 'fa6', 'mat', 'pi']"[ipIconPack] = "['all']";
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## 🔒 Security & Validation
|
|
354
|
+
|
|
355
|
+
### Icon Validation
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
// Custom icon validation
|
|
359
|
+
validateIcon(icon: string): boolean {
|
|
360
|
+
// Check if icon exists in selected packs
|
|
361
|
+
const validIcons = this.getValidIcons();
|
|
362
|
+
return validIcons.some(validIcon => validIcon.name === icon);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Sanitize icon input
|
|
366
|
+
sanitizeIcon(icon: string): string {
|
|
367
|
+
// Remove potentially dangerous characters
|
|
368
|
+
return icon.replace(/[<>\"'&]/g, '');
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 🧪 Testing
|
|
373
|
+
|
|
374
|
+
### Unit Tests
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
|
378
|
+
import { IconPickerModule } from "ngx-ntk-icon-picker";
|
|
379
|
+
|
|
380
|
+
describe("IconSelectorComponent", () => {
|
|
381
|
+
let component: IconSelectorComponent;
|
|
382
|
+
let fixture: ComponentFixture<IconSelectorComponent>;
|
|
383
|
+
|
|
384
|
+
beforeEach(async () => {
|
|
385
|
+
await TestBed.configureTestingModule({
|
|
386
|
+
imports: [IconPickerModule],
|
|
387
|
+
declarations: [IconSelectorComponent],
|
|
388
|
+
}).compileComponents();
|
|
389
|
+
|
|
390
|
+
fixture = TestBed.createComponent(IconSelectorComponent);
|
|
391
|
+
component = fixture.componentInstance;
|
|
392
|
+
fixture.detectChanges();
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it("should create", () => {
|
|
396
|
+
expect(component).toBeTruthy();
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it("should emit iconSelected event", () => {
|
|
400
|
+
const mockIcon = { name: "fa fa-home", id: "home", type: IconType.FontAwesome };
|
|
401
|
+
spyOn(component.iconSelected, "emit");
|
|
402
|
+
|
|
403
|
+
component.onIconSelected(mockIcon);
|
|
404
|
+
|
|
405
|
+
expect(component.iconSelected.emit).toHaveBeenCalledWith(mockIcon);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("should filter icons by search term", () => {
|
|
409
|
+
component.search = "home";
|
|
410
|
+
const filteredIcons = component.getFilteredIcons();
|
|
411
|
+
|
|
412
|
+
expect(filteredIcons.every((icon) => icon.name.toLowerCase().includes("home") || icon.filter?.some((filter) => filter.toLowerCase().includes("home")))).toBe(true);
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Integration Tests
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
|
421
|
+
import { IconPickerModule } from "ngx-ntk-icon-picker";
|
|
422
|
+
|
|
423
|
+
describe("IconPicker Integration", () => {
|
|
424
|
+
let fixture: ComponentFixture<IconSelectorComponent>;
|
|
425
|
+
|
|
426
|
+
beforeEach(async () => {
|
|
427
|
+
await TestBed.configureTestingModule({
|
|
428
|
+
imports: [IconPickerModule],
|
|
429
|
+
declarations: [IconSelectorComponent],
|
|
430
|
+
}).compileComponents();
|
|
431
|
+
|
|
432
|
+
fixture = TestBed.createComponent(IconSelectorComponent);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("should display selected icon", () => {
|
|
436
|
+
fixture.componentInstance.selectedIcon = "fa fa-home";
|
|
437
|
+
fixture.detectChanges();
|
|
438
|
+
|
|
439
|
+
const iconElement = fixture.nativeElement.querySelector(".selected-icon");
|
|
440
|
+
expect(iconElement).toBeTruthy();
|
|
441
|
+
expect(iconElement.textContent).toContain("home");
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it("should open popup on button click", () => {
|
|
445
|
+
const button = fixture.nativeElement.querySelector(".icon-picker-button");
|
|
446
|
+
button.click();
|
|
447
|
+
fixture.detectChanges();
|
|
448
|
+
|
|
449
|
+
const popup = fixture.nativeElement.querySelector(".icon-picker-popup");
|
|
450
|
+
expect(popup).toBeTruthy();
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it("should filter icons when searching", () => {
|
|
454
|
+
// Open popup
|
|
455
|
+
const button = fixture.nativeElement.querySelector(".icon-picker-button");
|
|
456
|
+
button.click();
|
|
457
|
+
fixture.detectChanges();
|
|
458
|
+
|
|
459
|
+
// Enter search term
|
|
460
|
+
const searchInput = fixture.nativeElement.querySelector(".search-input");
|
|
461
|
+
searchInput.value = "home";
|
|
462
|
+
searchInput.dispatchEvent(new Event("input"));
|
|
463
|
+
fixture.detectChanges();
|
|
464
|
+
|
|
465
|
+
// Check filtered results
|
|
466
|
+
const iconItems = fixture.nativeElement.querySelectorAll(".icon-item");
|
|
467
|
+
expect(iconItems.length).toBeGreaterThan(0);
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## ⚡ Performance
|
|
473
|
+
|
|
474
|
+
### Optimization Tips
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
// Use OnPush change detection for better performance
|
|
478
|
+
@Component({
|
|
479
|
+
selector: "app-icon-selector",
|
|
480
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
481
|
+
})
|
|
482
|
+
export class IconSelectorComponent {
|
|
483
|
+
// Implement trackBy function for ngFor
|
|
484
|
+
trackByIcon(index: number, icon: Icon): string {
|
|
485
|
+
return icon.id;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Debounce search input
|
|
489
|
+
private searchSubject = new Subject<string>();
|
|
490
|
+
|
|
491
|
+
ngOnInit(): void {
|
|
492
|
+
this.searchSubject.pipe(debounceTime(300), distinctUntilChanged()).subscribe((searchTerm) => {
|
|
493
|
+
this.performSearch(searchTerm);
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
onSearchChange(searchTerm: string): void {
|
|
498
|
+
this.searchSubject.next(searchTerm);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Memory Management
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
// Proper cleanup
|
|
507
|
+
ngOnDestroy(): void {
|
|
508
|
+
this.searchSubject.complete();
|
|
509
|
+
this.destroy$.next();
|
|
510
|
+
this.destroy$.complete();
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Lazy load icon packs
|
|
514
|
+
loadIconPack(packName: string): void {
|
|
515
|
+
if (!this.loadedPacks.has(packName)) {
|
|
516
|
+
this.loadIconPackAsync(packName).subscribe(icons => {
|
|
517
|
+
this.loadedPacks.set(packName, icons);
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
## 📝 Examples
|
|
524
|
+
|
|
525
|
+
### Basic Icon Selector
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
@Component({
|
|
529
|
+
selector: "app-basic-icon-selector",
|
|
530
|
+
template: `
|
|
531
|
+
<div class="icon-selector">
|
|
532
|
+
<label>Choose an icon:</label>
|
|
533
|
+
<icon-picker [(icon)]="selectedIcon" [ipIconPack]="['fa']" [ipPlaceHolder]="'Select an icon'" (iconSelected)="onIconSelected($event)"> </icon-picker>
|
|
534
|
+
</div>
|
|
535
|
+
`,
|
|
536
|
+
})
|
|
537
|
+
export class BasicIconSelectorComponent {
|
|
538
|
+
selectedIcon: string = "fa fa-star";
|
|
539
|
+
|
|
540
|
+
onIconSelected(icon: Icon): void {
|
|
541
|
+
console.log("Selected icon:", icon.name);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Advanced Icon Selector with Custom Styling
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
@Component({
|
|
550
|
+
selector: "app-advanced-icon-selector",
|
|
551
|
+
template: `
|
|
552
|
+
<div class="advanced-icon-selector">
|
|
553
|
+
<icon-picker [(icon)]="selectedIcon" [ipIconPack]="['fa', 'fa5', 'fa6', 'mat', 'pi']" [ipPosition]="'bottom'" [ipHeight]="400" [ipWidth]="350" [ipIconSize]="24" [ipIconVerticalPadding]="8" [ipIconHorizontalPadding]="8" [ipPlaceHolder]="'Choose an icon for your project'" [ipFallbackIcon]="'fa fa-question-circle'" [ipKeepSearchFilter]="true" [ipButtonStyleClass]="'custom-icon-button'" [ipInputSearchStyleClass]="'custom-search-input'" [ipDivSearchStyleClass]="'custom-search-container'" (iconSelected)="onIconSelected($event)"> </icon-picker>
|
|
554
|
+
</div>
|
|
555
|
+
`,
|
|
556
|
+
styles: [
|
|
557
|
+
`
|
|
558
|
+
.advanced-icon-selector {
|
|
559
|
+
.custom-icon-button {
|
|
560
|
+
display: flex;
|
|
561
|
+
align-items: center;
|
|
562
|
+
gap: 12px;
|
|
563
|
+
padding: 12px 16px;
|
|
564
|
+
border: 2px solid #e0e0e0;
|
|
565
|
+
border-radius: 8px;
|
|
566
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
567
|
+
color: white;
|
|
568
|
+
font-weight: 500;
|
|
569
|
+
cursor: pointer;
|
|
570
|
+
transition: all 0.3s ease;
|
|
571
|
+
|
|
572
|
+
&:hover {
|
|
573
|
+
border-color: #667eea;
|
|
574
|
+
transform: translateY(-2px);
|
|
575
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.custom-search-input {
|
|
580
|
+
width: 100%;
|
|
581
|
+
padding: 12px 16px;
|
|
582
|
+
border: 2px solid #e0e0e0;
|
|
583
|
+
border-radius: 8px;
|
|
584
|
+
font-size: 16px;
|
|
585
|
+
background-color: #f8f9fa;
|
|
586
|
+
|
|
587
|
+
&:focus {
|
|
588
|
+
outline: none;
|
|
589
|
+
border-color: #667eea;
|
|
590
|
+
background-color: white;
|
|
591
|
+
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.custom-search-container {
|
|
596
|
+
background-color: #f8f9fa;
|
|
597
|
+
border-bottom: 2px solid #e0e0e0;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
`,
|
|
601
|
+
],
|
|
602
|
+
})
|
|
603
|
+
export class AdvancedIconSelectorComponent {
|
|
604
|
+
selectedIcon: string = "fa fa-rocket";
|
|
605
|
+
|
|
606
|
+
onIconSelected(icon: Icon): void {
|
|
607
|
+
console.log("Advanced icon selected:", icon);
|
|
608
|
+
// Handle icon selection with additional logic
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Icon Selector with Validation
|
|
614
|
+
|
|
615
|
+
```typescript
|
|
616
|
+
@Component({
|
|
617
|
+
selector: "app-validated-icon-selector",
|
|
618
|
+
template: `
|
|
619
|
+
<div class="validated-icon-selector">
|
|
620
|
+
<icon-picker [(icon)]="selectedIcon" [ipIconPack]="['fa', 'fa5']" [ipPlaceHolder]="'Select a valid icon'" [ipFallbackIcon]="'fa fa-exclamation-triangle'" (iconSelected)="validateAndSelectIcon($event)"> </icon-picker>
|
|
621
|
+
|
|
622
|
+
<div *ngIf="validationError" class="validation-error">
|
|
623
|
+
{{ validationError }}
|
|
624
|
+
</div>
|
|
625
|
+
</div>
|
|
626
|
+
`,
|
|
627
|
+
})
|
|
628
|
+
export class ValidatedIconSelectorComponent {
|
|
629
|
+
selectedIcon: string = "";
|
|
630
|
+
validationError: string = "";
|
|
631
|
+
|
|
632
|
+
validateAndSelectIcon(icon: Icon): void {
|
|
633
|
+
// Custom validation logic
|
|
634
|
+
if (this.isIconAllowed(icon)) {
|
|
635
|
+
this.selectedIcon = icon.name;
|
|
636
|
+
this.validationError = "";
|
|
637
|
+
} else {
|
|
638
|
+
this.validationError = "This icon is not allowed for your account type.";
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
private isIconAllowed(icon: Icon): boolean {
|
|
643
|
+
// Implement your validation logic
|
|
644
|
+
const allowedIcons = ["fa fa-home", "fa fa-user", "fa fa-cog"];
|
|
645
|
+
return allowedIcons.includes(icon.name);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
## 🔄 Version History
|
|
651
|
+
|
|
652
|
+
### v20.25.3
|
|
653
|
+
|
|
654
|
+
- Initial release with core functionality
|
|
655
|
+
- Multi-icon library support
|
|
656
|
+
- Search and filtering capabilities
|
|
657
|
+
- Customizable interface
|
|
658
|
+
- FontAwesome v4, v5, v6 integration
|
|
659
|
+
- Material Icons support
|
|
660
|
+
- PrimeIcons integration
|
|
661
|
+
|
|
662
|
+
### v20.25.2
|
|
663
|
+
|
|
664
|
+
- Bug fixes and performance improvements
|
|
665
|
+
- Enhanced search functionality
|
|
666
|
+
- Improved accessibility features
|
|
667
|
+
- Better mobile responsiveness
|
|
668
|
+
|
|
669
|
+
## 🤝 Contributing
|
|
670
|
+
|
|
671
|
+
We welcome contributions! Please see our contributing guidelines:
|
|
672
|
+
|
|
673
|
+
1. Fork the repository
|
|
674
|
+
2. Create a feature branch
|
|
675
|
+
3. Make your changes
|
|
676
|
+
4. Add tests for new functionality
|
|
677
|
+
5. Submit a pull request
|
|
678
|
+
|
|
679
|
+
## 📄 License
|
|
680
|
+
|
|
681
|
+
This project is licensed under the ISC License.
|
|
682
|
+
|
|
683
|
+
## 🆘 Support
|
|
684
|
+
|
|
685
|
+
For support and questions:
|
|
686
|
+
|
|
687
|
+
- Create an issue on GitHub
|
|
688
|
+
- Contact: [ntk.ir](https://ntk.ir)
|
|
689
|
+
|
|
690
|
+
## 👨💻 Author
|
|
691
|
+
|
|
692
|
+
**Alireza Karavi**
|
|
693
|
+
|
|
694
|
+
- GitHub: [@akaravi](https://github.com/akaravi)
|
|
695
|
+
- Website: [ntk.ir](https://ntk.ir)
|
|
60
696
|
|
|
61
|
-
|
|
697
|
+
---
|
|
62
698
|
|
|
63
|
-
|
|
699
|
+
**Note**: This library is part of the NTK CMS Angular Libraries collection. For more information, see the main project README.
|
|
@@ -44626,10 +44626,10 @@ class IconPickerService {
|
|
|
44626
44626
|
return false;
|
|
44627
44627
|
}
|
|
44628
44628
|
}
|
|
44629
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.
|
|
44630
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.
|
|
44629
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerService, deps: [{ token: i1.FaIconLibrary }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
44630
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerService }); }
|
|
44631
44631
|
}
|
|
44632
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
44632
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerService, decorators: [{
|
|
44633
44633
|
type: Injectable
|
|
44634
44634
|
}], ctorParameters: () => [{ type: i1.FaIconLibrary }] });
|
|
44635
44635
|
|
|
@@ -44640,10 +44640,10 @@ class TextDirective {
|
|
|
44640
44640
|
changeInput(value) {
|
|
44641
44641
|
this.newValue.emit(value);
|
|
44642
44642
|
}
|
|
44643
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.
|
|
44644
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.
|
|
44643
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: TextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
44644
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.7", type: TextDirective, isStandalone: true, selector: "[text]", inputs: { text: "text" }, outputs: { newValue: "newValue" }, host: { listeners: { "input": "changeInput($event.target.value)" } }, ngImport: i0 }); }
|
|
44645
44645
|
}
|
|
44646
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
44646
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: TextDirective, decorators: [{
|
|
44647
44647
|
type: Directive,
|
|
44648
44648
|
args: [{
|
|
44649
44649
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -44684,10 +44684,10 @@ class SearchIconPipe {
|
|
|
44684
44684
|
clean(value) {
|
|
44685
44685
|
return value.trim().toLowerCase();
|
|
44686
44686
|
}
|
|
44687
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.
|
|
44688
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.
|
|
44687
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: SearchIconPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
44688
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.7", ngImport: i0, type: SearchIconPipe, isStandalone: true, name: "searchIcon" }); }
|
|
44689
44689
|
}
|
|
44690
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
44690
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: SearchIconPipe, decorators: [{
|
|
44691
44691
|
type: Pipe,
|
|
44692
44692
|
args: [{
|
|
44693
44693
|
name: 'searchIcon'
|
|
@@ -44900,10 +44900,10 @@ class IconPickerComponent {
|
|
|
44900
44900
|
// This can be enhanced later with a proper icon existence check
|
|
44901
44901
|
return true;
|
|
44902
44902
|
}
|
|
44903
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.
|
|
44904
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.
|
|
44903
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: IconPickerService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
44904
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.7", type: IconPickerComponent, isStandalone: false, selector: "icon-picker", providers: [IconPickerService], viewQueries: [{ propertyName: "dialogElement", first: true, predicate: ["dialogPopup"], descendants: true }], ngImport: i0, template: "<div class=\"icon-picker\" #dialogPopup [hidden]=\"!show\" [style.visibility]=\"this.hidden ? 'hidden' : 'visible'\"\r\n [style.height.px]=\"ipHeight\" [style.width.px]=\"ipWidth\" [style.top.px]=\"top\" [style.left.px]=\"left\"\r\n [style.position]=\"position\">\r\n\r\n <div class=\"arrow arrow-{{ipPosition}}\" [style.top.px]=\"arrowTop\"></div>\r\n\r\n <div class=\"icon-search {{ipDivSearchStyleClass}}\">\r\n <input type=\"text\" class=\"{{ipInputSearchStyleClass}}\" [text] [value]=\"search\" (newValue)=\"setSearch($event)\"\r\n [placeholder]=\"ipPlaceHolder\">\r\n </div>\r\n <div class=\"icon-grid\" [ngStyle]=\"{'max-height.px': ipMaxHeight}\">\r\n <div *ngFor=\"let icon of icons | searchIcon:search\">\r\n <button *ngIf=\"icon\" class=\"ip-button-icon {{ipButtonStyleClass}}\" type=\"button\" title=\"{{ icon.name }}\"\r\n [ngClass]=\"{active : icon === selectedIcon}\" [style.width.px]=\"buttonWidth\" [style.height.px]=\"buttonHeight\"\r\n [style.padding-top.px]=\"ipIconVerticalPadding\" [style.padding-bottom.px]=\"ipIconVerticalPadding\"\r\n [style.padding-left.px]=\"ipIconHorizontalPadding\" [style.padding-right.px]=\"ipIconHorizontalPadding\"\r\n (click)=\"selectIcon(icon)\">\r\n <span *ngIf=\"icon.type === iconType.FontAwesome\" class=\"fa fa-{{icon.id}}\"\r\n [style.font-size.px]=\"ipIconSize\"></span>\r\n <span *ngIf=\"icon.type === iconType.FontAwesome5\" class=\"{{icon.id}}\" [style.font-size.px]=\"ipIconSize\"></span>\r\n <span *ngIf=\"icon.type === iconType.FontAwesome6\" [style.font-size.px]=\"ipIconSize\">\r\n <fa-icon [icon]=\"['fas', icon.iconName]\" (error)=\"onIconError($event)\"></fa-icon>\r\n </span>\r\n <span *ngIf=\"icon.type === iconType.Material\" class=\"material-icons\"\r\n [style.font-size.px]=\"ipIconSize\">{{icon.id}}</span>\r\n <span *ngIf=\"icon.type === iconType.PrimeIcons\" class=\"pi pi-{{icon.id}}\"\r\n [style.font-size.px]=\"ipIconSize\"></span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n</div>\r\n", styles: [".icon-picker{box-sizing:border-box;margin:0;position:absolute;z-index:100000;top:250px;left:30px;width:230px;height:auto;border:#777 solid 1px;cursor:default;background-color:#fff;-webkit-user-select:none;user-select:none}.icon-picker i{position:relative;cursor:default}.icon-picker .arrow{position:absolute;z-index:999999;width:0;height:0;border-style:solid}.icon-picker .arrow-right{top:10px;left:-20px;border-width:5px 10px;border-color:rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0)}.icon-picker .arrow-left{top:10px;left:100%;border-width:5px 10px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777}.icon-picker .arrow-bottom{top:-20px;left:10px;border-width:10px 5px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) #777 rgba(0,0,0,0)}.icon-picker .arrow-top{left:10px;border-width:10px 5px;border-color:#777 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0)}.icon-picker div.icon-search{padding:5px}.icon-picker div.icon-grid{display:flex;overflow-y:auto;flex-direction:row;flex-wrap:wrap;padding:5px}.icon-picker div.icon-grid div{margin:2px}.icon-picker div.cursor-sv{position:relative;width:15px;height:15px;border-radius:50%;border:#ddd solid 1px;cursor:default}.icon-picker div.cursor{position:relative;width:16px;height:16px;border-radius:50%;border:#222 solid 2px;cursor:default}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "spin", "pulse", "mask", "styles", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "classes", "transform", "a11yRole"] }, { kind: "directive", type: TextDirective, selector: "[text]", inputs: ["text"], outputs: ["newValue"] }, { kind: "pipe", type: SearchIconPipe, name: "searchIcon" }] }); }
|
|
44905
44905
|
}
|
|
44906
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
44906
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerComponent, decorators: [{
|
|
44907
44907
|
type: Component,
|
|
44908
44908
|
args: [{ selector: 'icon-picker', standalone: false, providers: [IconPickerService], template: "<div class=\"icon-picker\" #dialogPopup [hidden]=\"!show\" [style.visibility]=\"this.hidden ? 'hidden' : 'visible'\"\r\n [style.height.px]=\"ipHeight\" [style.width.px]=\"ipWidth\" [style.top.px]=\"top\" [style.left.px]=\"left\"\r\n [style.position]=\"position\">\r\n\r\n <div class=\"arrow arrow-{{ipPosition}}\" [style.top.px]=\"arrowTop\"></div>\r\n\r\n <div class=\"icon-search {{ipDivSearchStyleClass}}\">\r\n <input type=\"text\" class=\"{{ipInputSearchStyleClass}}\" [text] [value]=\"search\" (newValue)=\"setSearch($event)\"\r\n [placeholder]=\"ipPlaceHolder\">\r\n </div>\r\n <div class=\"icon-grid\" [ngStyle]=\"{'max-height.px': ipMaxHeight}\">\r\n <div *ngFor=\"let icon of icons | searchIcon:search\">\r\n <button *ngIf=\"icon\" class=\"ip-button-icon {{ipButtonStyleClass}}\" type=\"button\" title=\"{{ icon.name }}\"\r\n [ngClass]=\"{active : icon === selectedIcon}\" [style.width.px]=\"buttonWidth\" [style.height.px]=\"buttonHeight\"\r\n [style.padding-top.px]=\"ipIconVerticalPadding\" [style.padding-bottom.px]=\"ipIconVerticalPadding\"\r\n [style.padding-left.px]=\"ipIconHorizontalPadding\" [style.padding-right.px]=\"ipIconHorizontalPadding\"\r\n (click)=\"selectIcon(icon)\">\r\n <span *ngIf=\"icon.type === iconType.FontAwesome\" class=\"fa fa-{{icon.id}}\"\r\n [style.font-size.px]=\"ipIconSize\"></span>\r\n <span *ngIf=\"icon.type === iconType.FontAwesome5\" class=\"{{icon.id}}\" [style.font-size.px]=\"ipIconSize\"></span>\r\n <span *ngIf=\"icon.type === iconType.FontAwesome6\" [style.font-size.px]=\"ipIconSize\">\r\n <fa-icon [icon]=\"['fas', icon.iconName]\" (error)=\"onIconError($event)\"></fa-icon>\r\n </span>\r\n <span *ngIf=\"icon.type === iconType.Material\" class=\"material-icons\"\r\n [style.font-size.px]=\"ipIconSize\">{{icon.id}}</span>\r\n <span *ngIf=\"icon.type === iconType.PrimeIcons\" class=\"pi pi-{{icon.id}}\"\r\n [style.font-size.px]=\"ipIconSize\"></span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n</div>\r\n", styles: [".icon-picker{box-sizing:border-box;margin:0;position:absolute;z-index:100000;top:250px;left:30px;width:230px;height:auto;border:#777 solid 1px;cursor:default;background-color:#fff;-webkit-user-select:none;user-select:none}.icon-picker i{position:relative;cursor:default}.icon-picker .arrow{position:absolute;z-index:999999;width:0;height:0;border-style:solid}.icon-picker .arrow-right{top:10px;left:-20px;border-width:5px 10px;border-color:rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0)}.icon-picker .arrow-left{top:10px;left:100%;border-width:5px 10px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777}.icon-picker .arrow-bottom{top:-20px;left:10px;border-width:10px 5px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) #777 rgba(0,0,0,0)}.icon-picker .arrow-top{left:10px;border-width:10px 5px;border-color:#777 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0)}.icon-picker div.icon-search{padding:5px}.icon-picker div.icon-grid{display:flex;overflow-y:auto;flex-direction:row;flex-wrap:wrap;padding:5px}.icon-picker div.icon-grid div{margin:2px}.icon-picker div.cursor-sv{position:relative;width:15px;height:15px;border-radius:50%;border:#ddd solid 1px;cursor:default}.icon-picker div.cursor{position:relative;width:16px;height:16px;border-radius:50%;border:#222 solid 2px;cursor:default}\n"] }]
|
|
44909
44909
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: IconPickerService }], propDecorators: { dialogElement: [{
|
|
@@ -44982,10 +44982,10 @@ class IconPickerDirective {
|
|
|
44982
44982
|
elementFocus() {
|
|
44983
44983
|
this.iconPickerFocus.emit();
|
|
44984
44984
|
}
|
|
44985
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.
|
|
44986
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.
|
|
44985
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerDirective, deps: [{ token: i0.ViewContainerRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
44986
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.7", type: IconPickerDirective, isStandalone: true, selector: "[iconPicker]", inputs: { iconPicker: "iconPicker", ipPlaceHolder: "ipPlaceHolder", ipPosition: "ipPosition", ipFallbackIcon: "ipFallbackIcon", ipHeight: "ipHeight", ipMaxHeight: "ipMaxHeight", ipWidth: "ipWidth", ipIconSize: "ipIconSize", ipIconVerticalPadding: "ipIconVerticalPadding", ipIconHorizontalPadding: "ipIconHorizontalPadding", ipIconPack: "ipIconPack", ipKeepSearchFilter: "ipKeepSearchFilter", ipUseRootViewContainer: "ipUseRootViewContainer", ipButtonStyleClass: "ipButtonStyleClass", ipDivSearchStyleClass: "ipDivSearchStyleClass", ipInputSearchStyleClass: "ipInputSearchStyleClass" }, outputs: { iconPickerSelect: "iconPickerSelect", iconPickerOpen: "iconPickerOpen", iconPickerClose: "iconPickerClose", iconPickerFocus: "iconPickerFocus" }, host: { listeners: { "focus": "handleFocus()", "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
44987
44987
|
}
|
|
44988
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
44988
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerDirective, decorators: [{
|
|
44989
44989
|
type: Directive,
|
|
44990
44990
|
args: [{
|
|
44991
44991
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -45040,8 +45040,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
|
|
|
45040
45040
|
}] } });
|
|
45041
45041
|
|
|
45042
45042
|
class IconPickerModule {
|
|
45043
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.
|
|
45044
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.
|
|
45043
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
45044
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.7", ngImport: i0, type: IconPickerModule, declarations: [IconPickerComponent], imports: [CommonModule,
|
|
45045
45045
|
FontAwesomeModule,
|
|
45046
45046
|
IconPickerDirective,
|
|
45047
45047
|
TextDirective,
|
|
@@ -45049,12 +45049,12 @@ class IconPickerModule {
|
|
|
45049
45049
|
IconPickerDirective,
|
|
45050
45050
|
TextDirective,
|
|
45051
45051
|
SearchIconPipe] }); }
|
|
45052
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.
|
|
45052
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerModule, providers: [
|
|
45053
45053
|
IconPickerService
|
|
45054
45054
|
], imports: [CommonModule,
|
|
45055
45055
|
FontAwesomeModule] }); }
|
|
45056
45056
|
}
|
|
45057
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.
|
|
45057
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.7", ngImport: i0, type: IconPickerModule, decorators: [{
|
|
45058
45058
|
type: NgModule,
|
|
45059
45059
|
args: [{
|
|
45060
45060
|
imports: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-ntk-icon-picker",
|
|
3
|
-
"version": "20.25.
|
|
3
|
+
"version": "20.25.4",
|
|
4
4
|
"description": "Ntk Cms Api And Model For Typscript",
|
|
5
5
|
"author": "Alireza-Karavi",
|
|
6
6
|
"license": "ISC",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"@angular/common": "^20.1.0",
|
|
16
16
|
"@angular/core": "^20.1.0",
|
|
17
|
-
"@fortawesome/angular-fontawesome": "
|
|
17
|
+
"@fortawesome/angular-fontawesome": "^0.10.2",
|
|
18
18
|
"@fortawesome/fontawesome-svg-core": ">=6.1.1",
|
|
19
19
|
"@fortawesome/free-solid-svg-icons": ">=6.1.1",
|
|
20
20
|
"primeicons": ">=5.0.0"
|