action-buttons 15.0.6 → 15.0.7
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 +534 -12
- package/action-buttons-15.0.7.tgz +0 -0
- package/fesm2022/action-buttons.mjs +133 -0
- package/fesm2022/action-buttons.mjs.map +1 -0
- package/package.json +12 -1
- package/types/action-buttons.d.ts +61 -0
- package/ng-package.json +0 -7
- package/src/lib/action-buttons-demo/action-buttons-demo.component.css +0 -0
- package/src/lib/action-buttons-demo/action-buttons-demo.component.html +0 -8
- package/src/lib/action-buttons-demo/action-buttons-demo.component.ts +0 -22
- package/src/lib/action-buttons.component.html +0 -40
- package/src/lib/action-buttons.component.scss +0 -3
- package/src/lib/action-buttons.component.spec.ts +0 -91
- package/src/lib/action-buttons.component.ts +0 -60
- package/src/lib/action-buttons.module.ts +0 -29
- package/src/lib/models/button-action.model.spec.ts +0 -66
- package/src/lib/models/button-action.model.ts +0 -30
- package/src/lib/models/index.ts +0 -6
- package/src/public-api.ts +0 -8
- package/tsconfig.lib.json +0 -32
- package/tsconfig.lib.prod.json +0 -10
- package/tsconfig.spec.json +0 -14
package/README.md
CHANGED
|
@@ -1,21 +1,543 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Action Buttons Component
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `action-buttons` library provides a Material Design-based component for displaying action buttons with various configurations including icons, labels, badges, colors, and disabled states. It implements Angular's `ControlValueAccessor` interface for seamless form integration.
|
|
6
|
+
|
|
7
|
+
### Core Capabilities
|
|
8
|
+
|
|
9
|
+
#### 🎯 Material Design Button Actions
|
|
10
|
+
|
|
11
|
+
- **Multiple Display Modes**: Icon-only, labeled buttons, or combination
|
|
12
|
+
- **Badge Support**: Display notification counts with badge overlays
|
|
13
|
+
- **Color Customization**: Apply custom colors to individual buttons
|
|
14
|
+
- **State Management**: Built-in support for disabled states
|
|
15
|
+
- **SVG Icons**: Support for both Material Icons and custom SVG icons
|
|
16
|
+
- **Form Integration**: Implements ControlValueAccessor for reactive forms
|
|
17
|
+
|
|
18
|
+
#### 🔧 Features
|
|
19
|
+
|
|
20
|
+
✅ **ControlValueAccessor Implementation** - Works with Angular forms
|
|
21
|
+
✅ **Material Design Integration** - Uses Angular Material components
|
|
22
|
+
✅ **Badge Notifications** - Visual notification indicators
|
|
23
|
+
✅ **Color Customization** - Theme-aware button colors
|
|
24
|
+
✅ **SVG Icon Support** - Works with Material Icons and custom SVGs
|
|
25
|
+
✅ **Responsive Design** - Adapts to different screen sizes
|
|
26
|
+
✅ **Accessibility Ready** - ARIA labels and keyboard navigation
|
|
27
|
+
|
|
28
|
+
### Key Benefits
|
|
29
|
+
|
|
30
|
+
| Feature | Description |
|
|
31
|
+
|---------|-------------|
|
|
32
|
+
| **Form Integration** | Native Angular form control support |
|
|
33
|
+
| **Visual Feedback** | Badge system for notifications/counts |
|
|
34
|
+
| **Flexible Styling** | Color customization and Material Design theming |
|
|
35
|
+
| **Icon Support** | Works with Material Icons and SVG icons |
|
|
36
|
+
| **State Management** | Disabled states and conditional rendering |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Demo Component (`ActionButtonsDemoComponent`)
|
|
41
|
+
|
|
42
|
+
The demo component showcases various button configurations and states, providing interactive examples of the action buttons functionality.
|
|
43
|
+
|
|
44
|
+
### Usage
|
|
45
|
+
|
|
46
|
+
To use the demo component in your application:
|
|
4
47
|
|
|
5
48
|
```html
|
|
6
|
-
<
|
|
7
|
-
<!-- Display Card - Action Buttons -->
|
|
8
|
-
<app-action-buttons
|
|
9
|
-
[data]="buttonActions"
|
|
10
|
-
></app-action-buttons>
|
|
11
|
-
</div>
|
|
49
|
+
<app-action-buttons-demo></app-action-buttons-demo>
|
|
12
50
|
```
|
|
13
51
|
|
|
52
|
+
The demo includes:
|
|
53
|
+
- Phone button (disabled state)
|
|
54
|
+
- Messages button (with badge showing 6 notifications)
|
|
55
|
+
- Alerts button (zero badge state)
|
|
56
|
+
- Different color configurations
|
|
57
|
+
- Disabled and enabled states
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Summary
|
|
62
|
+
|
|
63
|
+
The `action-buttons` library provides a flexible, Material Design-compliant button component for Angular applications with badge support, color customization, and form integration.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Quick Start Guide
|
|
68
|
+
|
|
69
|
+
### Installation & Setup (2 minutes)
|
|
70
|
+
|
|
71
|
+
#### 1. Import Module
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// app.module.ts
|
|
75
|
+
import { ActionButtonsModule } from 'action-buttons';
|
|
76
|
+
|
|
77
|
+
@NgModule({
|
|
78
|
+
imports: [
|
|
79
|
+
ActionButtonsModule
|
|
80
|
+
]
|
|
81
|
+
})
|
|
82
|
+
export class AppModule { }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### 2. No Module Configuration Required
|
|
86
|
+
|
|
87
|
+
The `ActionButtonsModule` does not require global configuration. Components can be used immediately after module import.
|
|
88
|
+
|
|
89
|
+
### Quick Examples
|
|
90
|
+
|
|
91
|
+
#### Example 1: Basic Button Actions
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Component } from '@angular/core';
|
|
95
|
+
import { ButtonAction } from 'action-buttons';
|
|
14
96
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
97
|
+
@Component({
|
|
98
|
+
selector: 'app-buttons',
|
|
99
|
+
template: `
|
|
100
|
+
<app-action-buttons
|
|
101
|
+
[data]="buttonActions"
|
|
102
|
+
[disabled]="isDisabled">
|
|
103
|
+
</app-action-buttons>
|
|
104
|
+
`
|
|
105
|
+
})
|
|
106
|
+
export class ButtonsComponent {
|
|
107
|
+
isDisabled = false;
|
|
108
|
+
|
|
109
|
+
buttonActions: ButtonAction[] = [
|
|
110
|
+
{ icon: 'dialpad', label: 'Phone', disabled: true },
|
|
18
111
|
{ icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },
|
|
19
|
-
{ icon: 'notifications_off', label: 'Alerts', badge: 0 }
|
|
112
|
+
{ icon: 'notifications_off', label: 'Alerts', badge: 0 }
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Example 2: Form Control Integration
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { Component } from '@angular/core';
|
|
121
|
+
import { FormControl } from '@angular/forms';
|
|
122
|
+
import { ButtonAction } from 'action-buttons';
|
|
123
|
+
|
|
124
|
+
@Component({
|
|
125
|
+
selector: 'app-form-buttons',
|
|
126
|
+
template: `
|
|
127
|
+
<app-action-buttons
|
|
128
|
+
[formControl]="buttonControl"
|
|
129
|
+
[data]="buttonActions">
|
|
130
|
+
</app-action-buttons>
|
|
131
|
+
|
|
132
|
+
<div>Selected: {{ buttonControl.value | json }}</div>
|
|
133
|
+
`
|
|
134
|
+
})
|
|
135
|
+
export class FormButtonsComponent {
|
|
136
|
+
buttonControl = new FormControl();
|
|
137
|
+
|
|
138
|
+
buttonActions: ButtonAction[] = [
|
|
139
|
+
{ icon: 'edit', label: 'Edit', color: 'primary' },
|
|
140
|
+
{ icon: 'delete', label: 'Delete', color: 'warn' },
|
|
141
|
+
{ icon: 'share', label: 'Share', color: 'accent' }
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### Example 3: Dynamic Button States
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { Component } from '@angular/core';
|
|
150
|
+
import { ButtonAction } from 'action-buttons';
|
|
151
|
+
|
|
152
|
+
@Component({
|
|
153
|
+
selector: 'app-dynamic-buttons',
|
|
154
|
+
template: `
|
|
155
|
+
<div class="button-controls">
|
|
156
|
+
<button (click)="toggleDisabled()">
|
|
157
|
+
{{ isDisabled ? 'Enable' : 'Disable' }} Buttons
|
|
158
|
+
</button>
|
|
159
|
+
<button (click)="addNotification()">Add Notification</button>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<app-action-buttons
|
|
163
|
+
[data]="buttonActions"
|
|
164
|
+
[disabled]="isDisabled">
|
|
165
|
+
</app-action-buttons>
|
|
166
|
+
|
|
167
|
+
<div *ngFor="let action of buttonActions; let i = index">
|
|
168
|
+
{{ action.label }}: Badge = {{ action.badge || 0 }}
|
|
169
|
+
</div>
|
|
170
|
+
`
|
|
171
|
+
})
|
|
172
|
+
export class DynamicButtonsComponent {
|
|
173
|
+
isDisabled = false;
|
|
174
|
+
notificationCount = 3;
|
|
175
|
+
|
|
176
|
+
buttonActions: ButtonAction[] = [
|
|
177
|
+
{ icon: 'home', label: 'Home' },
|
|
178
|
+
{ icon: 'search', label: 'Search' },
|
|
179
|
+
{ icon: 'notifications', label: 'Notifications', badge: this.notificationCount }
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
toggleDisabled() {
|
|
183
|
+
this.isDisabled = !this.isDisabled;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
addNotification() {
|
|
187
|
+
this.notificationCount++;
|
|
188
|
+
this.buttonActions[2].badge = this.notificationCount;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
#### Example 4: Custom Styled Buttons
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { Component } from '@angular/core';
|
|
197
|
+
import { ButtonAction } from 'action-buttons';
|
|
198
|
+
|
|
199
|
+
@Component({
|
|
200
|
+
selector: 'app-styled-buttons',
|
|
201
|
+
template: `
|
|
202
|
+
<div class="button-groups">
|
|
203
|
+
<!-- Primary Actions -->
|
|
204
|
+
<h3>Primary Actions</h3>
|
|
205
|
+
<app-action-buttons [data]="primaryActions"></app-action-buttons>
|
|
206
|
+
|
|
207
|
+
<!-- Status Actions -->
|
|
208
|
+
<h3>Status Actions</h3>
|
|
209
|
+
<app-action-buttons [data]="statusActions"></app-action-buttons>
|
|
210
|
+
|
|
211
|
+
<!-- Icon Only -->
|
|
212
|
+
<h3>Icon Only</h3>
|
|
213
|
+
<app-action-buttons [data]="iconOnlyActions"></app-action-buttons>
|
|
214
|
+
</div>
|
|
215
|
+
`,
|
|
216
|
+
styles: [`
|
|
217
|
+
.button-groups { margin: 2rem; }
|
|
218
|
+
h3 { margin: 1rem 0 0.5rem; color: #666; }
|
|
219
|
+
`]
|
|
220
|
+
})
|
|
221
|
+
export class StyledButtonsComponent {
|
|
222
|
+
primaryActions: ButtonAction[] = [
|
|
223
|
+
{ icon: 'add', label: 'Add', color: 'primary' },
|
|
224
|
+
{ icon: 'edit', label: 'Edit', color: 'primary' },
|
|
225
|
+
{ icon: 'save', label: 'Save', color: 'primary' }
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
statusActions: ButtonAction[] = [
|
|
229
|
+
{ icon: 'check_circle', label: 'Approved', color: 'green' },
|
|
230
|
+
{ icon: 'warning', label: 'Warning', color: 'orange' },
|
|
231
|
+
{ icon: 'error', label: 'Error', color: 'red' }
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
iconOnlyActions: ButtonAction[] = [
|
|
235
|
+
{ icon: 'star', label: 'Favorite' },
|
|
236
|
+
{ icon: 'bookmark', label: 'Bookmark' },
|
|
237
|
+
{ icon: 'share', label: 'Share' }
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Component API
|
|
245
|
+
|
|
246
|
+
### Inputs
|
|
247
|
+
|
|
248
|
+
| Input | Type | Description | Default |
|
|
249
|
+
| :--- | :--- | :--- | :--- |
|
|
250
|
+
| `data` | `ButtonAction[]` | Array of button action configurations | `[]` |
|
|
251
|
+
| `disabled` | `boolean` | Whether the entire component is disabled | `false` |
|
|
252
|
+
|
|
253
|
+
### Outputs
|
|
254
|
+
|
|
255
|
+
| Output | Type | Description |
|
|
256
|
+
| :--- | :--- | :--- |
|
|
257
|
+
| `selectionChange` | `EventEmitter<any>` | Emits when a button is selected/clicked |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Model Structures
|
|
262
|
+
|
|
263
|
+
### ButtonAction Interface
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
export interface ButtonActionInterface {
|
|
267
|
+
label?: string; // Button text label
|
|
268
|
+
icon?: string; // Material icon name or custom icon
|
|
269
|
+
disabled?: boolean; // Individual button disabled state
|
|
270
|
+
badge?: number; // Notification badge count (0 or positive number)
|
|
271
|
+
color?: string; // Custom color (CSS color value)
|
|
272
|
+
svg?: boolean; // Whether icon is SVG format
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### ButtonAction Class
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
export class ButtonAction implements ButtonActionInterface {
|
|
280
|
+
constructor(
|
|
281
|
+
public label?: string,
|
|
282
|
+
public icon?: string,
|
|
283
|
+
public disabled?: boolean = false,
|
|
284
|
+
public badge?: number = 0,
|
|
285
|
+
public color?: string,
|
|
286
|
+
public svg?: boolean = false
|
|
287
|
+
) {}
|
|
288
|
+
|
|
289
|
+
static adapt(data?: any): ButtonAction {
|
|
290
|
+
return new ButtonAction(
|
|
291
|
+
data?.label,
|
|
292
|
+
data?.icon,
|
|
293
|
+
(data?.disabled) ? data.disabled : false,
|
|
294
|
+
(data?.badge) ? data.badge : 0,
|
|
295
|
+
data?.color,
|
|
296
|
+
(data?.svg) ? true : false
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Usage Examples
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
// Basic button configuration
|
|
306
|
+
const basicButton: ButtonAction = new ButtonAction(
|
|
307
|
+
'Click Me', // label
|
|
308
|
+
'touch_app', // icon
|
|
309
|
+
false, // disabled
|
|
310
|
+
0, // badge
|
|
311
|
+
undefined, // color
|
|
312
|
+
false // svg
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// Using the adapt method
|
|
316
|
+
const adaptedButton = ButtonAction.adapt({
|
|
317
|
+
label: 'Save',
|
|
318
|
+
icon: 'save',
|
|
319
|
+
badge: 5,
|
|
320
|
+
color: 'accent'
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Configuration with all options
|
|
324
|
+
const fullConfig: ButtonAction[] = [
|
|
325
|
+
{ label: 'Home', icon: 'home', disabled: false, badge: 0 },
|
|
326
|
+
{ label: 'Profile', icon: 'person', color: 'primary' },
|
|
327
|
+
{ label: 'Settings', icon: 'settings', badge: 3, color: 'warn' },
|
|
328
|
+
{ label: 'Custom SVG', icon: 'custom-icon', svg: true }
|
|
329
|
+
];
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Module Configuration
|
|
335
|
+
|
|
336
|
+
### ActionButtonsModule
|
|
337
|
+
|
|
338
|
+
**No Global Configuration Required**
|
|
339
|
+
|
|
340
|
+
The `ActionButtonsModule` does not provide a `forRoot()` method or global configuration options. All configuration is done at the component level through input properties.
|
|
341
|
+
|
|
342
|
+
#### Module Structure
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
@NgModule({
|
|
346
|
+
imports: [
|
|
347
|
+
CommonModule,
|
|
348
|
+
FormsModule,
|
|
349
|
+
ReactiveFormsModule,
|
|
350
|
+
MatIconModule,
|
|
351
|
+
MatButtonModule,
|
|
352
|
+
MatBadgeModule,
|
|
353
|
+
],
|
|
354
|
+
declarations: [
|
|
355
|
+
ActionButtonsComponent,
|
|
356
|
+
ActionButtonsDemoComponent,
|
|
357
|
+
],
|
|
358
|
+
exports:[
|
|
359
|
+
ActionButtonsComponent,
|
|
360
|
+
ActionButtonsDemoComponent,
|
|
20
361
|
]
|
|
362
|
+
})
|
|
363
|
+
export class ActionButtonsModule { }
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### Dependencies
|
|
367
|
+
|
|
368
|
+
- **@angular/common**: Core Angular functionality
|
|
369
|
+
- **@angular/forms**: Form control integration
|
|
370
|
+
- **@angular/material**: Material Design components
|
|
371
|
+
- MatIconModule: Icon display
|
|
372
|
+
- MatButtonModule: Button base component
|
|
373
|
+
- MatBadgeModule: Badge notifications
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Styling and Customization
|
|
378
|
+
|
|
379
|
+
### CSS Classes and Styling
|
|
380
|
+
|
|
381
|
+
The component uses Material Design styling and can be customized using:
|
|
382
|
+
|
|
383
|
+
1. **Global Material Theme**: Configure colors in your Angular Material theme
|
|
384
|
+
2. **Component-specific Styles**: Add custom CSS classes
|
|
385
|
+
3. **Color Input**: Use the `color` property for individual button styling
|
|
386
|
+
|
|
387
|
+
### Example Customization
|
|
388
|
+
|
|
389
|
+
```scss
|
|
390
|
+
// Custom styles for action buttons
|
|
391
|
+
:host ::ng-deep .action-buttons {
|
|
392
|
+
.mat-button-wrapper {
|
|
393
|
+
display: flex;
|
|
394
|
+
flex-direction: column;
|
|
395
|
+
align-items: center;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.button-label {
|
|
399
|
+
font-size: 0.75rem;
|
|
400
|
+
margin-top: 4px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.mat-badge-content {
|
|
404
|
+
font-size: 0.6rem;
|
|
405
|
+
font-weight: bold;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Accessibility
|
|
413
|
+
|
|
414
|
+
### ARIA Support
|
|
415
|
+
|
|
416
|
+
- Buttons include proper ARIA labels
|
|
417
|
+
- Keyboard navigation is supported
|
|
418
|
+
- Screen reader friendly with label and icon descriptions
|
|
419
|
+
- Badge notifications include appropriate ARIA live regions
|
|
420
|
+
|
|
421
|
+
### Best Practices
|
|
422
|
+
|
|
423
|
+
1. **Provide meaningful labels** for all buttons
|
|
424
|
+
2. **Use appropriate icons** that match the button purpose
|
|
425
|
+
3. **Set badge counts appropriately** for notification indicators
|
|
426
|
+
4. **Consider color contrast** when using custom colors
|
|
427
|
+
5. **Test with screen readers** to ensure accessibility
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Integration Examples
|
|
432
|
+
|
|
433
|
+
### With Other UI Components
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
// Integration with display-card
|
|
437
|
+
@Component({
|
|
438
|
+
template: `
|
|
439
|
+
<app-display-card [title]="'User Actions'">
|
|
440
|
+
<app-action-buttons [data]="userActions"></app-action-buttons>
|
|
441
|
+
</app-display-card>
|
|
442
|
+
`
|
|
443
|
+
})
|
|
444
|
+
export class CardWithActionsComponent {
|
|
445
|
+
userActions: ButtonAction[] = [
|
|
446
|
+
{ icon: 'edit', label: 'Edit Profile', color: 'primary' },
|
|
447
|
+
{ icon: 'security', label: 'Security', color: 'accent' },
|
|
448
|
+
{ icon: 'notifications', label: 'Notifications', badge: 2 }
|
|
449
|
+
];
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### With State Management
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
// Integration with HTTP Request Manager
|
|
457
|
+
@Component({
|
|
458
|
+
template: `
|
|
459
|
+
<app-action-buttons
|
|
460
|
+
[data]="actionButtons$ | async"
|
|
461
|
+
(selectionChange)="handleAction($event)">
|
|
462
|
+
</app-action-buttons>
|
|
463
|
+
`
|
|
464
|
+
})
|
|
465
|
+
export class StateManagedButtonsComponent {
|
|
466
|
+
actionButtons$ = this.actionStore.buttons$;
|
|
467
|
+
|
|
468
|
+
constructor(private actionStore: ActionStore) {}
|
|
469
|
+
|
|
470
|
+
handleAction(action: ButtonAction) {
|
|
471
|
+
this.actionStore.executeAction(action);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
21
474
|
```
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
## Testing
|
|
479
|
+
|
|
480
|
+
### Unit Testing Example
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
484
|
+
import { ActionButtonsComponent } from './action-buttons.component';
|
|
485
|
+
import { ButtonAction } from './models/button-action.model';
|
|
486
|
+
|
|
487
|
+
describe('ActionButtonsComponent', () => {
|
|
488
|
+
let component: ActionButtonsComponent;
|
|
489
|
+
let fixture: ComponentFixture<ActionButtonsComponent>;
|
|
490
|
+
|
|
491
|
+
beforeEach(async () => {
|
|
492
|
+
await TestBed.configureTestingModule({
|
|
493
|
+
declarations: [ ActionButtonsComponent ]
|
|
494
|
+
}).compileComponents();
|
|
495
|
+
|
|
496
|
+
fixture = TestBed.createComponent(ActionButtonsComponent);
|
|
497
|
+
component = fixture.componentInstance;
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('should create', () => {
|
|
501
|
+
expect(component).toBeTruthy();
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should display buttons from data input', () => {
|
|
505
|
+
component.data = [
|
|
506
|
+
{ label: 'Test', icon: 'home' }
|
|
507
|
+
];
|
|
508
|
+
fixture.detectChanges();
|
|
509
|
+
|
|
510
|
+
const compiled = fixture.nativeElement;
|
|
511
|
+
expect(compiled.textContent).toContain('Test');
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('should emit selection change when button is clicked', () => {
|
|
515
|
+
spyOn(component.selectionChange, 'emit');
|
|
516
|
+
component.data = [{ label: 'Test', icon: 'home' }];
|
|
517
|
+
fixture.detectChanges();
|
|
518
|
+
|
|
519
|
+
const button = fixture.nativeElement.querySelector('button');
|
|
520
|
+
button.click();
|
|
521
|
+
|
|
522
|
+
expect(component.selectionChange.emit).toHaveBeenCalled();
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## Troubleshooting
|
|
530
|
+
|
|
531
|
+
### Common Issues
|
|
532
|
+
|
|
533
|
+
1. **Icons not displaying**: Ensure Material Icons are loaded in your index.html
|
|
534
|
+
2. **Badge not showing**: Make sure MatBadgeModule is imported in your module
|
|
535
|
+
3. **Form control not working**: Verify ReactiveFormsModule is imported
|
|
536
|
+
4. **Colors not applying**: Check that custom colors are valid CSS color values
|
|
537
|
+
|
|
538
|
+
### Performance Tips
|
|
539
|
+
|
|
540
|
+
1. **Use OnPush change detection** for better performance with large button arrays
|
|
541
|
+
2. **Implement trackBy** for dynamic button lists
|
|
542
|
+
3. **Avoid frequent data object recreation** to prevent unnecessary re-renders
|
|
543
|
+
4. **Use immutable data patterns** for button action updates
|
|
Binary file
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { forwardRef, Input, Component, NgModule } from '@angular/core';
|
|
3
|
+
import { NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import * as i1 from '@angular/common';
|
|
5
|
+
import { CommonModule } from '@angular/common';
|
|
6
|
+
import * as i2 from '@angular/material/icon';
|
|
7
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
8
|
+
import * as i3 from '@angular/material/button';
|
|
9
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
10
|
+
import * as i4 from '@angular/material/badge';
|
|
11
|
+
import { MatBadgeModule } from '@angular/material/badge';
|
|
12
|
+
|
|
13
|
+
class ActionButtonsComponent {
|
|
14
|
+
constructor() {
|
|
15
|
+
this._data = [];
|
|
16
|
+
this.disabled = false;
|
|
17
|
+
this.onChange = () => { };
|
|
18
|
+
this.onTouch = () => { };
|
|
19
|
+
this.icon = (item) => (item?.icon) ? item?.icon : '';
|
|
20
|
+
}
|
|
21
|
+
set data(value) {
|
|
22
|
+
this._data = value || [];
|
|
23
|
+
}
|
|
24
|
+
get data() {
|
|
25
|
+
return this._data;
|
|
26
|
+
}
|
|
27
|
+
ngOnInit() {
|
|
28
|
+
}
|
|
29
|
+
writeValue(value) {
|
|
30
|
+
console.log('writeValue', value);
|
|
31
|
+
}
|
|
32
|
+
registerOnChange(fn) {
|
|
33
|
+
this.onChange = fn;
|
|
34
|
+
}
|
|
35
|
+
registerOnTouched(fn) {
|
|
36
|
+
this.onTouch = fn;
|
|
37
|
+
}
|
|
38
|
+
setDisabledState(isDisabled) {
|
|
39
|
+
this.disabled = isDisabled;
|
|
40
|
+
}
|
|
41
|
+
onSelected(event) {
|
|
42
|
+
this.onChange(event);
|
|
43
|
+
}
|
|
44
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
45
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ActionButtonsComponent, selector: "app-action-buttons", inputs: { data: "data", disabled: "disabled" }, providers: [
|
|
46
|
+
{
|
|
47
|
+
provide: NG_VALUE_ACCESSOR,
|
|
48
|
+
useExisting: forwardRef(() => ActionButtonsComponent),
|
|
49
|
+
multi: true,
|
|
50
|
+
},
|
|
51
|
+
], ngImport: i0, template: "<div style=\"display: flex; gap: .5rem; padding-top: .4rem;\">\n <ng-container *ngFor=\"let item of data\">\n <div style=\"align-content: space-evenly;\">\n <button\n class=\"btn\"\n *ngIf=\"item?.label; else ICON\"\n mat-stroked-button\n [disabled]=\"item.disabled || disabled\"\n [matBadge]=\"(item.badge && item.badge > 0) ? item.badge : ''\"\n [color]=\"item.color\"\n (click)=\"onSelected(item)\"\n >\n <mat-icon *ngIf=\"!item.svg; else SVG\">\n {{ item.icon }}\n </mat-icon>\n <ng-template #SVG>\n <mat-icon [svgIcon]=\"icon(item)\"></mat-icon>\n </ng-template>\n {{ item.label }}\n </button>\n </div>\n <ng-template #ICON>\n <button\n mat-icon-button\n [disabled]=\"item.disabled || disabled\"\n [matBadge]=\"(item.badge && item.badge > 0) ? item.badge : ''\"\n [color]=\"item.color\"\n (click)=\"onSelected(item)\"\n >\n <mat-icon *ngIf=\"!item.svg; else SVG\">\n {{ item.icon }}\n </mat-icon>\n <ng-template #SVG>\n <mat-icon [svgIcon]=\"icon(item)\"></mat-icon>\n </ng-template>\n\n </button>\n </ng-template>\n </ng-container>\n</div>\n", styles: [".btn{min-width:120px}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: i4.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }] }); }
|
|
52
|
+
}
|
|
53
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsComponent, decorators: [{
|
|
54
|
+
type: Component,
|
|
55
|
+
args: [{ selector: 'app-action-buttons', providers: [
|
|
56
|
+
{
|
|
57
|
+
provide: NG_VALUE_ACCESSOR,
|
|
58
|
+
useExisting: forwardRef(() => ActionButtonsComponent),
|
|
59
|
+
multi: true,
|
|
60
|
+
},
|
|
61
|
+
], standalone: false, template: "<div style=\"display: flex; gap: .5rem; padding-top: .4rem;\">\n <ng-container *ngFor=\"let item of data\">\n <div style=\"align-content: space-evenly;\">\n <button\n class=\"btn\"\n *ngIf=\"item?.label; else ICON\"\n mat-stroked-button\n [disabled]=\"item.disabled || disabled\"\n [matBadge]=\"(item.badge && item.badge > 0) ? item.badge : ''\"\n [color]=\"item.color\"\n (click)=\"onSelected(item)\"\n >\n <mat-icon *ngIf=\"!item.svg; else SVG\">\n {{ item.icon }}\n </mat-icon>\n <ng-template #SVG>\n <mat-icon [svgIcon]=\"icon(item)\"></mat-icon>\n </ng-template>\n {{ item.label }}\n </button>\n </div>\n <ng-template #ICON>\n <button\n mat-icon-button\n [disabled]=\"item.disabled || disabled\"\n [matBadge]=\"(item.badge && item.badge > 0) ? item.badge : ''\"\n [color]=\"item.color\"\n (click)=\"onSelected(item)\"\n >\n <mat-icon *ngIf=\"!item.svg; else SVG\">\n {{ item.icon }}\n </mat-icon>\n <ng-template #SVG>\n <mat-icon [svgIcon]=\"icon(item)\"></mat-icon>\n </ng-template>\n\n </button>\n </ng-template>\n </ng-container>\n</div>\n", styles: [".btn{min-width:120px}\n"] }]
|
|
62
|
+
}], propDecorators: { data: [{
|
|
63
|
+
type: Input
|
|
64
|
+
}], disabled: [{
|
|
65
|
+
type: Input
|
|
66
|
+
}] } });
|
|
67
|
+
|
|
68
|
+
class ActionButtonsDemoComponent {
|
|
69
|
+
constructor() {
|
|
70
|
+
this.buttonActions = [
|
|
71
|
+
{ icon: 'dialpad', label: 'Phone', disabled: true },
|
|
72
|
+
{ icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },
|
|
73
|
+
{ icon: 'notifications_off', label: 'Alerts', badge: 0 },
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
ngOnInit() {
|
|
77
|
+
}
|
|
78
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
79
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ActionButtonsDemoComponent, selector: "app-action-buttons-demo", ngImport: i0, template: "<h1>\n Action Buttons\n</h1>\n\n <!-- Display Card - Action Buttons -->\n <app-action-buttons\n [data]=\"buttonActions\"\n ></app-action-buttons>\n", styles: [""], dependencies: [{ kind: "component", type: ActionButtonsComponent, selector: "app-action-buttons", inputs: ["data", "disabled"] }] }); }
|
|
80
|
+
}
|
|
81
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsDemoComponent, decorators: [{
|
|
82
|
+
type: Component,
|
|
83
|
+
args: [{ selector: 'app-action-buttons-demo', standalone: false, template: "<h1>\n Action Buttons\n</h1>\n\n <!-- Display Card - Action Buttons -->\n <app-action-buttons\n [data]=\"buttonActions\"\n ></app-action-buttons>\n" }]
|
|
84
|
+
}], ctorParameters: () => [] });
|
|
85
|
+
|
|
86
|
+
class ActionButtonsModule {
|
|
87
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
88
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsModule, declarations: [ActionButtonsComponent,
|
|
89
|
+
ActionButtonsDemoComponent], imports: [CommonModule,
|
|
90
|
+
FormsModule,
|
|
91
|
+
ReactiveFormsModule,
|
|
92
|
+
MatIconModule,
|
|
93
|
+
MatButtonModule,
|
|
94
|
+
MatBadgeModule], exports: [ActionButtonsComponent,
|
|
95
|
+
ActionButtonsDemoComponent] }); }
|
|
96
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsModule, imports: [CommonModule,
|
|
97
|
+
FormsModule,
|
|
98
|
+
ReactiveFormsModule,
|
|
99
|
+
MatIconModule,
|
|
100
|
+
MatButtonModule,
|
|
101
|
+
MatBadgeModule] }); }
|
|
102
|
+
}
|
|
103
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionButtonsModule, decorators: [{
|
|
104
|
+
type: NgModule,
|
|
105
|
+
args: [{
|
|
106
|
+
imports: [
|
|
107
|
+
CommonModule,
|
|
108
|
+
FormsModule,
|
|
109
|
+
ReactiveFormsModule,
|
|
110
|
+
MatIconModule,
|
|
111
|
+
MatButtonModule,
|
|
112
|
+
MatBadgeModule,
|
|
113
|
+
],
|
|
114
|
+
declarations: [
|
|
115
|
+
ActionButtonsComponent,
|
|
116
|
+
ActionButtonsDemoComponent,
|
|
117
|
+
], exports: [
|
|
118
|
+
ActionButtonsComponent,
|
|
119
|
+
ActionButtonsDemoComponent,
|
|
120
|
+
]
|
|
121
|
+
}]
|
|
122
|
+
}] });
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
* Public API Surface of action-buttons
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Generated bundle index. Do not edit.
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
export { ActionButtonsComponent, ActionButtonsDemoComponent, ActionButtonsModule };
|
|
133
|
+
//# sourceMappingURL=action-buttons.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-buttons.mjs","sources":["../../../projects/action-buttons/src/lib/action-buttons.component.ts","../../../projects/action-buttons/src/lib/action-buttons.component.html","../../../projects/action-buttons/src/lib/action-buttons-demo/action-buttons-demo.component.ts","../../../projects/action-buttons/src/lib/action-buttons-demo/action-buttons-demo.component.html","../../../projects/action-buttons/src/lib/action-buttons.module.ts","../../../projects/action-buttons/src/public-api.ts","../../../projects/action-buttons/src/action-buttons.ts"],"sourcesContent":["import { Component, Input, OnInit, forwardRef } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { ButtonAction } from './models';\n\n@Component({\n selector: 'app-action-buttons',\n templateUrl: './action-buttons.component.html',\n styleUrls: ['./action-buttons.component.scss'],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => ActionButtonsComponent),\n multi: true,\n },\n ],\n standalone: false\n})\nexport class ActionButtonsComponent implements OnInit, ControlValueAccessor {\n\n _data: ButtonAction[] = []\n @Input() set data(value: ButtonAction[]) {\n this._data = value || []\n }\n\n get data() {\n return this._data\n }\n\n @Input() disabled = false\n\n onChange: any = () => {};\n onTouch: any = () => {};\n\n icon = (item: ButtonAction) => (item?.icon) ? item?.icon : ''\n\n ngOnInit() {\n }\n\n writeValue(value: string) {\n console.log('writeValue', value)\n }\n\n registerOnChange(fn: any) {\n this.onChange = fn\n }\n\n registerOnTouched(fn: any) {\n this.onTouch = fn\n }\n\n setDisabledState?(isDisabled: boolean) {\n this.disabled = isDisabled\n }\n\n onSelected(event: any) {\n this.onChange(event)\n }\n\n}\n","<div style=\"display: flex; gap: .5rem; padding-top: .4rem;\">\n <ng-container *ngFor=\"let item of data\">\n <div style=\"align-content: space-evenly;\">\n <button\n class=\"btn\"\n *ngIf=\"item?.label; else ICON\"\n mat-stroked-button\n [disabled]=\"item.disabled || disabled\"\n [matBadge]=\"(item.badge && item.badge > 0) ? item.badge : ''\"\n [color]=\"item.color\"\n (click)=\"onSelected(item)\"\n >\n <mat-icon *ngIf=\"!item.svg; else SVG\">\n {{ item.icon }}\n </mat-icon>\n <ng-template #SVG>\n <mat-icon [svgIcon]=\"icon(item)\"></mat-icon>\n </ng-template>\n {{ item.label }}\n </button>\n </div>\n <ng-template #ICON>\n <button\n mat-icon-button\n [disabled]=\"item.disabled || disabled\"\n [matBadge]=\"(item.badge && item.badge > 0) ? item.badge : ''\"\n [color]=\"item.color\"\n (click)=\"onSelected(item)\"\n >\n <mat-icon *ngIf=\"!item.svg; else SVG\">\n {{ item.icon }}\n </mat-icon>\n <ng-template #SVG>\n <mat-icon [svgIcon]=\"icon(item)\"></mat-icon>\n </ng-template>\n\n </button>\n </ng-template>\n </ng-container>\n</div>\n","import { Component, OnInit } from '@angular/core';\nimport { ButtonAction } from '../models';\n\n@Component({\n selector: 'app-action-buttons-demo',\n templateUrl: './action-buttons-demo.component.html',\n styleUrls: ['./action-buttons-demo.component.css'],\n standalone: false\n})\nexport class ActionButtonsDemoComponent implements OnInit {\n\n buttonActions: ButtonAction[] = [\n { icon: 'dialpad', label: 'Phone', disabled: true},\n { icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },\n { icon: 'notifications_off', label: 'Alerts', badge: 0 },\n ]\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n","<h1>\n Action Buttons\n</h1>\n\n <!-- Display Card - Action Buttons -->\n <app-action-buttons\n [data]=\"buttonActions\"\n ></app-action-buttons>\n","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\nimport { ActionButtonsComponent } from './action-buttons.component';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatBadgeModule } from '@angular/material/badge';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\n\nimport { ActionButtonsDemoComponent } from './action-buttons-demo/action-buttons-demo.component';\n\n@NgModule({\n imports: [\n CommonModule,\n FormsModule,\n ReactiveFormsModule,\n MatIconModule,\n MatButtonModule,\n MatBadgeModule,\n ],\n declarations: [\n ActionButtonsComponent,\n ActionButtonsDemoComponent,\n ], exports:[\n ActionButtonsComponent,\n ActionButtonsDemoComponent,\n ]\n})\nexport class ActionButtonsModule { }\n","/*\n * Public API Surface of action-buttons\n */\n\nexport * from './lib/action-buttons.component';\nexport * from './lib/action-buttons.module';\n\nexport * from './lib/action-buttons-demo/action-buttons-demo.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.ActionButtonsComponent"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "action-buttons",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.7",
|
|
4
4
|
"homepage": "https://wavecoders.ca",
|
|
5
5
|
"author": "Mike Bonifacio <wavecoders@gmail.com> (http://wavecoders@gmail.com/)",
|
|
6
6
|
"description": "This is an Angular Module containing Components/Services using Material",
|
|
@@ -22,5 +22,16 @@
|
|
|
22
22
|
"dest": "../../dist/action-buttons",
|
|
23
23
|
"lib": {
|
|
24
24
|
"entryFile": "src/public-api.ts"
|
|
25
|
+
},
|
|
26
|
+
"module": "fesm2022/action-buttons.mjs",
|
|
27
|
+
"typings": "types/action-buttons.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
"./package.json": {
|
|
30
|
+
"default": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./types/action-buttons.d.ts",
|
|
34
|
+
"default": "./fesm2022/action-buttons.mjs"
|
|
35
|
+
}
|
|
25
36
|
}
|
|
26
37
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { OnInit } from '@angular/core';
|
|
3
|
+
import * as i4 from '@angular/forms';
|
|
4
|
+
import { ControlValueAccessor } from '@angular/forms';
|
|
5
|
+
import * as i3 from '@angular/common';
|
|
6
|
+
import * as i5 from '@angular/material/icon';
|
|
7
|
+
import * as i6 from '@angular/material/button';
|
|
8
|
+
import * as i7 from '@angular/material/badge';
|
|
9
|
+
|
|
10
|
+
interface ButtonActionInterface {
|
|
11
|
+
label?: string;
|
|
12
|
+
icon?: string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
badge?: number;
|
|
15
|
+
color?: string;
|
|
16
|
+
svg?: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare class ButtonAction implements ButtonActionInterface {
|
|
19
|
+
label?: string | undefined;
|
|
20
|
+
icon?: string | undefined;
|
|
21
|
+
disabled?: boolean | undefined;
|
|
22
|
+
badge?: number | undefined;
|
|
23
|
+
color?: string | undefined;
|
|
24
|
+
svg?: boolean | undefined;
|
|
25
|
+
constructor(label?: string | undefined, icon?: string | undefined, disabled?: boolean | undefined, badge?: number | undefined, color?: string | undefined, svg?: boolean | undefined);
|
|
26
|
+
static adapt(data?: any): ButtonAction;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class ActionButtonsComponent implements OnInit, ControlValueAccessor {
|
|
30
|
+
_data: ButtonAction[];
|
|
31
|
+
set data(value: ButtonAction[]);
|
|
32
|
+
get data(): ButtonAction[];
|
|
33
|
+
disabled: boolean;
|
|
34
|
+
onChange: any;
|
|
35
|
+
onTouch: any;
|
|
36
|
+
icon: (item: ButtonAction) => string;
|
|
37
|
+
ngOnInit(): void;
|
|
38
|
+
writeValue(value: string): void;
|
|
39
|
+
registerOnChange(fn: any): void;
|
|
40
|
+
registerOnTouched(fn: any): void;
|
|
41
|
+
setDisabledState?(isDisabled: boolean): void;
|
|
42
|
+
onSelected(event: any): void;
|
|
43
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ActionButtonsComponent, never>;
|
|
44
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ActionButtonsComponent, "app-action-buttons", never, { "data": { "alias": "data"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, {}, never, never, false, never>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
declare class ActionButtonsDemoComponent implements OnInit {
|
|
48
|
+
buttonActions: ButtonAction[];
|
|
49
|
+
constructor();
|
|
50
|
+
ngOnInit(): void;
|
|
51
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ActionButtonsDemoComponent, never>;
|
|
52
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ActionButtonsDemoComponent, "app-action-buttons-demo", never, {}, {}, never, never, false, never>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare class ActionButtonsModule {
|
|
56
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ActionButtonsModule, never>;
|
|
57
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<ActionButtonsModule, [typeof ActionButtonsComponent, typeof ActionButtonsDemoComponent], [typeof i3.CommonModule, typeof i4.FormsModule, typeof i4.ReactiveFormsModule, typeof i5.MatIconModule, typeof i6.MatButtonModule, typeof i7.MatBadgeModule], [typeof ActionButtonsComponent, typeof ActionButtonsDemoComponent]>;
|
|
58
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<ActionButtonsModule>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { ActionButtonsComponent, ActionButtonsDemoComponent, ActionButtonsModule };
|
package/ng-package.json
DELETED
|
File without changes
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Component, OnInit } from '@angular/core';
|
|
2
|
-
import { ButtonAction } from '../models';
|
|
3
|
-
|
|
4
|
-
@Component({
|
|
5
|
-
selector: 'app-action-buttons-demo',
|
|
6
|
-
templateUrl: './action-buttons-demo.component.html',
|
|
7
|
-
styleUrls: ['./action-buttons-demo.component.css']
|
|
8
|
-
})
|
|
9
|
-
export class ActionButtonsDemoComponent implements OnInit {
|
|
10
|
-
|
|
11
|
-
buttonActions: ButtonAction[] = [
|
|
12
|
-
{ icon: 'dialpad', label: 'Phone', disabled: true},
|
|
13
|
-
{ icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },
|
|
14
|
-
{ icon: 'notifications_off', label: 'Alerts', badge: 0 },
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
constructor() { }
|
|
18
|
-
|
|
19
|
-
ngOnInit() {
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<div style="display: flex; gap: .5rem; padding-top: .4rem;">
|
|
2
|
-
<ng-container *ngFor="let item of data">
|
|
3
|
-
<div style="align-content: space-evenly;">
|
|
4
|
-
<button
|
|
5
|
-
class="btn"
|
|
6
|
-
*ngIf="item?.label; else ICON"
|
|
7
|
-
mat-stroked-button
|
|
8
|
-
[disabled]="item.disabled || disabled"
|
|
9
|
-
[matBadge]="(item.badge && item.badge > 0) ? item.badge : ''"
|
|
10
|
-
[color]="item.color"
|
|
11
|
-
(click)="onSelected(item)"
|
|
12
|
-
>
|
|
13
|
-
<mat-icon *ngIf="!item.svg; else SVG">
|
|
14
|
-
{{ item.icon }}
|
|
15
|
-
</mat-icon>
|
|
16
|
-
<ng-template #SVG>
|
|
17
|
-
<mat-icon [svgIcon]="icon(item)"></mat-icon>
|
|
18
|
-
</ng-template>
|
|
19
|
-
{{ item.label }}
|
|
20
|
-
</button>
|
|
21
|
-
</div>
|
|
22
|
-
<ng-template #ICON>
|
|
23
|
-
<button
|
|
24
|
-
mat-icon-button
|
|
25
|
-
[disabled]="item.disabled || disabled"
|
|
26
|
-
[matBadge]="(item.badge && item.badge > 0) ? item.badge : ''"
|
|
27
|
-
[color]="item.color"
|
|
28
|
-
(click)="onSelected(item)"
|
|
29
|
-
>
|
|
30
|
-
<mat-icon *ngIf="!item.svg; else SVG">
|
|
31
|
-
{{ item.icon }}
|
|
32
|
-
</mat-icon>
|
|
33
|
-
<ng-template #SVG>
|
|
34
|
-
<mat-icon [svgIcon]="icon(item)"></mat-icon>
|
|
35
|
-
</ng-template>
|
|
36
|
-
|
|
37
|
-
</button>
|
|
38
|
-
</ng-template>
|
|
39
|
-
</ng-container>
|
|
40
|
-
</div>
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
-
import { ActionButtonsComponent } from './action-buttons.component';
|
|
3
|
-
import { ButtonAction } from './models';
|
|
4
|
-
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
5
|
-
import { Component, Input, NgModule } from '@angular/core';
|
|
6
|
-
import { MatBadgeModule } from '@angular/material/badge';
|
|
7
|
-
import { MatButtonModule } from '@angular/material/button';
|
|
8
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
9
|
-
import { CommonModule } from '@angular/common';
|
|
10
|
-
|
|
11
|
-
// Create a dummy component to simulate the icon
|
|
12
|
-
@Component({
|
|
13
|
-
selector: 'mat-icon',
|
|
14
|
-
template: '<span>{{ icon }}</span>'
|
|
15
|
-
})
|
|
16
|
-
class MockMatIconComponent {
|
|
17
|
-
@Input() icon: string | undefined;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Create a dummy demo component
|
|
21
|
-
@Component({
|
|
22
|
-
selector: 'app-action-buttons-demo',
|
|
23
|
-
template: '<app-action-buttons></app-action-buttons>'
|
|
24
|
-
})
|
|
25
|
-
class ActionButtonsDemoComponent {}
|
|
26
|
-
|
|
27
|
-
@NgModule({
|
|
28
|
-
declarations: [ActionButtonsComponent, MockMatIconComponent, ActionButtonsDemoComponent],
|
|
29
|
-
exports: [ActionButtonsComponent, ActionButtonsDemoComponent],
|
|
30
|
-
imports: [
|
|
31
|
-
CommonModule,
|
|
32
|
-
FormsModule,
|
|
33
|
-
ReactiveFormsModule,
|
|
34
|
-
MatIconModule,
|
|
35
|
-
MatButtonModule,
|
|
36
|
-
MatBadgeModule,
|
|
37
|
-
]
|
|
38
|
-
})
|
|
39
|
-
class TestModule {}
|
|
40
|
-
|
|
41
|
-
describe('ActionButtonsComponent', () => {
|
|
42
|
-
let component: ActionButtonsComponent;
|
|
43
|
-
let fixture: ComponentFixture<ActionButtonsComponent>;
|
|
44
|
-
|
|
45
|
-
beforeEach(async () => {
|
|
46
|
-
await TestBed.configureTestingModule({
|
|
47
|
-
imports: [TestModule]
|
|
48
|
-
})
|
|
49
|
-
.compileComponents();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
beforeEach(() => {
|
|
53
|
-
fixture = TestBed.createComponent(ActionButtonsComponent);
|
|
54
|
-
component = fixture.componentInstance;
|
|
55
|
-
fixture.detectChanges();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should create', () => {
|
|
59
|
-
expect(component).toBeTruthy();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should initialize with an empty data array', () => {
|
|
63
|
-
expect(component.data).toEqual([]);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should update the data array when the data input changes', () => {
|
|
67
|
-
const mockData: ButtonAction[] = [
|
|
68
|
-
{ label: 'Action 1'},
|
|
69
|
-
{ label: 'Action 2'}
|
|
70
|
-
];
|
|
71
|
-
component.data = mockData;
|
|
72
|
-
expect(component.data).toEqual(mockData);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should emit the selected value when onSelected is called', () => {
|
|
76
|
-
const selectedValue = 'action1';
|
|
77
|
-
spyOn(component, 'onChange');
|
|
78
|
-
component.onSelected(selectedValue);
|
|
79
|
-
expect(component.onChange).toHaveBeenCalledWith(selectedValue);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should return an empty string when icon is not defined', () => {
|
|
83
|
-
const item: ButtonAction = { label: 'Action 1'};
|
|
84
|
-
expect(component.icon(item)).toBe('');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should return the icon string when icon is defined', () => {
|
|
88
|
-
const item: ButtonAction = { label: 'Action 1', icon: 'some-icon' };
|
|
89
|
-
expect(component.icon(item)).toBe('some-icon');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Component, Input, OnInit, forwardRef } from '@angular/core';
|
|
2
|
-
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
3
|
-
import { ButtonAction } from './models';
|
|
4
|
-
|
|
5
|
-
@Component({
|
|
6
|
-
selector: 'app-action-buttons',
|
|
7
|
-
templateUrl: './action-buttons.component.html',
|
|
8
|
-
styleUrls: ['./action-buttons.component.scss'],
|
|
9
|
-
providers: [
|
|
10
|
-
{
|
|
11
|
-
provide: NG_VALUE_ACCESSOR,
|
|
12
|
-
useExisting: forwardRef(() => ActionButtonsComponent),
|
|
13
|
-
multi: true,
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
})
|
|
17
|
-
export class ActionButtonsComponent implements OnInit, ControlValueAccessor {
|
|
18
|
-
|
|
19
|
-
_data: ButtonAction[] = []
|
|
20
|
-
@Input() set data(value: ButtonAction[]) {
|
|
21
|
-
this._data = value || []
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get data() {
|
|
25
|
-
return this._data
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@Input() disabled = false
|
|
29
|
-
|
|
30
|
-
onChange: any = () => {};
|
|
31
|
-
onTouch: any = () => {};
|
|
32
|
-
|
|
33
|
-
icon = (item: ButtonAction) => (item?.icon) ? item?.icon : ''
|
|
34
|
-
|
|
35
|
-
constructor() { }
|
|
36
|
-
|
|
37
|
-
ngOnInit() {
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
writeValue(value: string) {
|
|
41
|
-
// call patchValue on the form
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
registerOnChange(fn: any) {
|
|
45
|
-
this.onChange = fn
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
registerOnTouched(fn: any) {
|
|
49
|
-
this.onTouch = fn
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
setDisabledState?(isDisabled: boolean) {
|
|
53
|
-
this.disabled = isDisabled
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
onSelected(event: any) {
|
|
57
|
-
this.onChange(event)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { NgModule } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
|
|
4
|
-
import { ActionButtonsComponent } from './action-buttons.component';
|
|
5
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
6
|
-
import { MatButtonModule } from '@angular/material/button';
|
|
7
|
-
import { MatBadgeModule } from '@angular/material/badge';
|
|
8
|
-
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
9
|
-
|
|
10
|
-
import { ActionButtonsDemoComponent } from './action-buttons-demo/action-buttons-demo.component';
|
|
11
|
-
|
|
12
|
-
@NgModule({
|
|
13
|
-
imports: [
|
|
14
|
-
CommonModule,
|
|
15
|
-
FormsModule,
|
|
16
|
-
ReactiveFormsModule,
|
|
17
|
-
MatIconModule,
|
|
18
|
-
MatButtonModule,
|
|
19
|
-
MatBadgeModule,
|
|
20
|
-
],
|
|
21
|
-
declarations: [
|
|
22
|
-
ActionButtonsComponent,
|
|
23
|
-
ActionButtonsDemoComponent,
|
|
24
|
-
], exports:[
|
|
25
|
-
ActionButtonsComponent,
|
|
26
|
-
ActionButtonsDemoComponent,
|
|
27
|
-
]
|
|
28
|
-
})
|
|
29
|
-
export class ActionButtonsModule { }
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { ButtonAction } from './button-action.model';
|
|
2
|
-
|
|
3
|
-
describe('ButtonAction', () => {
|
|
4
|
-
it('should create an instance', () => {
|
|
5
|
-
const buttonAction = new ButtonAction();
|
|
6
|
-
expect(buttonAction).toBeTruthy();
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
it('should set properties correctly', () => {
|
|
10
|
-
const label = 'Submit';
|
|
11
|
-
const icon = 'check';
|
|
12
|
-
const disabled = true;
|
|
13
|
-
const badge = 5;
|
|
14
|
-
const color = 'primary';
|
|
15
|
-
const svg = true;
|
|
16
|
-
|
|
17
|
-
const buttonAction = new ButtonAction(label, icon, disabled, badge, color, svg);
|
|
18
|
-
|
|
19
|
-
expect(buttonAction.label).toEqual(label);
|
|
20
|
-
expect(buttonAction.icon).toEqual(icon);
|
|
21
|
-
expect(buttonAction.disabled).toEqual(disabled);
|
|
22
|
-
expect(buttonAction.badge).toEqual(badge);
|
|
23
|
-
expect(buttonAction.color).toEqual(color);
|
|
24
|
-
expect(buttonAction.svg).toEqual(svg);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should adapt data correctly with truthy values', () => {
|
|
28
|
-
const data = {
|
|
29
|
-
label: 'Cancel',
|
|
30
|
-
icon: 'close',
|
|
31
|
-
disabled: true,
|
|
32
|
-
badge: 1,
|
|
33
|
-
color: 'secondary',
|
|
34
|
-
svg: true
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const buttonAction = ButtonAction.adapt(data);
|
|
38
|
-
|
|
39
|
-
expect(buttonAction.label).toEqual(data.label);
|
|
40
|
-
expect(buttonAction.icon).toEqual(data.icon);
|
|
41
|
-
expect(buttonAction.disabled).toEqual(data.disabled);
|
|
42
|
-
expect(buttonAction.badge).toEqual(data.badge);
|
|
43
|
-
expect(buttonAction.color).toEqual(data.color);
|
|
44
|
-
expect(buttonAction.svg).toEqual(data.svg);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should adapt data correctly with falsey values', () => {
|
|
48
|
-
const data = {
|
|
49
|
-
label: 'Cancel',
|
|
50
|
-
icon: 'close',
|
|
51
|
-
disabled: false,
|
|
52
|
-
badge: 0,
|
|
53
|
-
color: 'secondary',
|
|
54
|
-
svg: false
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const buttonAction = ButtonAction.adapt(data);
|
|
58
|
-
|
|
59
|
-
expect(buttonAction.label).toEqual(data.label);
|
|
60
|
-
expect(buttonAction.icon).toEqual(data.icon);
|
|
61
|
-
expect(buttonAction.disabled).toEqual(data.disabled);
|
|
62
|
-
expect(buttonAction.badge).toEqual(data.badge);
|
|
63
|
-
expect(buttonAction.color).toEqual(data.color);
|
|
64
|
-
expect(buttonAction.svg).toEqual(data.svg);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export interface ButtonActionInterface {
|
|
2
|
-
label?: string;
|
|
3
|
-
icon?: string;
|
|
4
|
-
disabled?: boolean;
|
|
5
|
-
badge?: number;
|
|
6
|
-
color?: string;
|
|
7
|
-
svg?: boolean
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class ButtonAction implements ButtonActionInterface {
|
|
11
|
-
constructor(
|
|
12
|
-
public label?: string,
|
|
13
|
-
public icon?: string,
|
|
14
|
-
public disabled?: boolean,
|
|
15
|
-
public badge?: number,
|
|
16
|
-
public color?: string,
|
|
17
|
-
public svg?: boolean
|
|
18
|
-
) {}
|
|
19
|
-
|
|
20
|
-
static adapt(data?: any): ButtonAction {
|
|
21
|
-
return new ButtonAction(
|
|
22
|
-
data?.label,
|
|
23
|
-
data?.icon,
|
|
24
|
-
(data?.disabled) ? data.disabled : false,
|
|
25
|
-
(data?.badge) ? data.badge : 0,
|
|
26
|
-
data?.color,
|
|
27
|
-
(data?.svg) ? true : false
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
}
|
package/src/lib/models/index.ts
DELETED
package/src/public-api.ts
DELETED
package/tsconfig.lib.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
-
{
|
|
3
|
-
"extends": "../../tsconfig.json",
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"outDir": "../../dist/action-buttons",
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"declarationMap": true,
|
|
8
|
-
"inlineSources": true,
|
|
9
|
-
"types": [],
|
|
10
|
-
"baseUrl": "./",
|
|
11
|
-
"paths": {
|
|
12
|
-
"@angular/*": ["node_modules/@angular/*"],
|
|
13
|
-
"action-buttons": ["node_modules/action-buttons"]
|
|
14
|
-
},
|
|
15
|
-
"target": "es2019",
|
|
16
|
-
"lib": [
|
|
17
|
-
"dom",
|
|
18
|
-
"es2019"
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
"angularCompilerOptions": {
|
|
22
|
-
"skipTemplateCodegen": true,
|
|
23
|
-
"strictMetadataEmit": true,
|
|
24
|
-
"enableResourceInlining": true,
|
|
25
|
-
"strictInjectionParameters": true,
|
|
26
|
-
"strictTemplates": true
|
|
27
|
-
},
|
|
28
|
-
"exclude": [
|
|
29
|
-
"src/test.ts",
|
|
30
|
-
"**/*.spec.ts"
|
|
31
|
-
]
|
|
32
|
-
}
|
package/tsconfig.lib.prod.json
DELETED
package/tsconfig.spec.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
-
{
|
|
3
|
-
"extends": "../../tsconfig.json",
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"outDir": "../../out-tsc/spec",
|
|
6
|
-
"types": [
|
|
7
|
-
"jasmine"
|
|
8
|
-
]
|
|
9
|
-
},
|
|
10
|
-
"include": [
|
|
11
|
-
"**/*.spec.ts",
|
|
12
|
-
"**/*.d.ts"
|
|
13
|
-
]
|
|
14
|
-
}
|