action-compact-button 15.0.4 → 15.0.5
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 +758 -15
- package/action-compact-button-15.0.5.tgz +0 -0
- package/fesm2022/action-compact-button.mjs +21 -22
- package/fesm2022/action-compact-button.mjs.map +1 -1
- package/package.json +3 -5
- package/types/action-compact-button.d.ts +68 -0
- package/action-compact-button-15.0.4.tgz +0 -0
- package/esm2022/action-compact-button.mjs +0 -5
- package/esm2022/lib/action-compact-button-demo/action-compact-button-demo.component.mjs +0 -22
- package/esm2022/lib/action-compact-button.component.mjs +0 -74
- package/esm2022/lib/action-compact-button.module.mjs +0 -54
- package/esm2022/lib/models/button-action.model.mjs +0 -14
- package/esm2022/lib/models/index.mjs +0 -5
- package/esm2022/public-api.mjs +0 -8
- package/index.d.ts +0 -5
- package/lib/action-compact-button-demo/action-compact-button-demo.component.d.ts +0 -10
- package/lib/action-compact-button.component.d.ts +0 -25
- package/lib/action-compact-button.module.d.ts +0 -15
- package/lib/models/button-action.model.d.ts +0 -18
- package/lib/models/index.d.ts +0 -1
- package/public-api.d.ts +0 -4
package/README.md
CHANGED
|
@@ -1,25 +1,768 @@
|
|
|
1
|
-
# Action Compact
|
|
1
|
+
# Action Compact Button Component
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `action-compact-button` library provides a compact version of action buttons with expand/collapse functionality. It displays buttons in a space-efficient manner, showing only icons in compact mode and expanding to show full labels when needed. The component implements Angular's `ControlValueAccessor` interface for seamless form integration.
|
|
6
|
+
|
|
7
|
+
### Core Capabilities
|
|
8
|
+
|
|
9
|
+
#### 🎯 Compact Action Button Interface
|
|
10
|
+
|
|
11
|
+
- **Space-Efficient Design**: Displays buttons in compact mode (icons only) or expanded mode (with labels)
|
|
12
|
+
- **Expandable Interface**: Toggle between compact and expanded views dynamically
|
|
13
|
+
- **Material Design Integration**: Uses Angular Material components for consistent styling
|
|
14
|
+
- **Form Control Support**: Implements ControlValueAccessor for reactive forms
|
|
15
|
+
- **Badge Support**: Maintains notification badge functionality in both modes
|
|
16
|
+
- **Responsive Behavior**: Adapts to available screen space
|
|
17
|
+
|
|
18
|
+
#### 🔧 Features
|
|
19
|
+
|
|
20
|
+
✅ **Expand/Collapse Toggle** - Dynamic view switching between compact and expanded
|
|
21
|
+
✅ **ControlValueAccessor Implementation** - Works with Angular forms
|
|
22
|
+
✅ **Material Design Integration** - Uses Angular Material components
|
|
23
|
+
✅ **Badge Notifications** - Visual notification indicators in both modes
|
|
24
|
+
✅ **Icon-Only Display** - Compact mode shows only icons to save space
|
|
25
|
+
✅ **Label Display** - Expanded mode shows both icons and labels
|
|
26
|
+
✅ **State Management** - Disabled states and conditional rendering
|
|
27
|
+
✅ **Responsive Design** - Adapts to different screen sizes
|
|
28
|
+
|
|
29
|
+
### Key Benefits
|
|
30
|
+
|
|
31
|
+
| Feature | Description |
|
|
32
|
+
|---------|-------------|
|
|
33
|
+
| **Space Optimization** | Compact mode saves horizontal space |
|
|
34
|
+
| **Flexible Display** | Toggle between icon-only and labeled views |
|
|
35
|
+
| **Form Integration** | Native Angular form control support |
|
|
36
|
+
| **Badge Support** | Notification indicators work in both modes |
|
|
37
|
+
| **Consistent Styling** | Material Design theming throughout |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Demo Component (`ActionCompactButtonDemoComponent`)
|
|
42
|
+
|
|
43
|
+
The demo component showcases the expand/collapse functionality and various button configurations.
|
|
44
|
+
|
|
45
|
+
### Usage
|
|
46
|
+
|
|
47
|
+
To use the demo component in your application:
|
|
4
48
|
|
|
5
49
|
```html
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
50
|
+
<app-compact-button-actions-demo></app-compact-button-actions-demo>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The demo includes:
|
|
54
|
+
- Expandable/collapsible button interface
|
|
55
|
+
- Phone button (disabled state)
|
|
56
|
+
- Messages button (with badge showing 6 notifications)
|
|
57
|
+
- Alerts button (zero badge state)
|
|
58
|
+
- Material checkbox to control expansion state
|
|
59
|
+
- Different color configurations
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Summary
|
|
64
|
+
|
|
65
|
+
The `action-compact-button` library provides a space-efficient, expandable action button component that dynamically switches between compact (icon-only) and expanded (icon+label) display modes.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Quick Start Guide
|
|
70
|
+
|
|
71
|
+
### Installation & Setup (2 minutes)
|
|
72
|
+
|
|
73
|
+
#### 1. Import Module
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// app.module.ts
|
|
77
|
+
import { ActionCompactButtonModule } from 'action-compact-button';
|
|
78
|
+
|
|
79
|
+
@NgModule({
|
|
80
|
+
imports: [
|
|
81
|
+
ActionCompactButtonModule
|
|
82
|
+
]
|
|
83
|
+
})
|
|
84
|
+
export class AppModule { }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### 2. No Module Configuration Required
|
|
88
|
+
|
|
89
|
+
The `ActionCompactButtonModule` does not require global configuration. Components can be used immediately after module import.
|
|
90
|
+
|
|
91
|
+
### Quick Examples
|
|
92
|
+
|
|
93
|
+
#### Example 1: Basic Compact/Expand Buttons
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { Component } from '@angular/core';
|
|
97
|
+
import { ButtonAction } from 'action-compact-button';
|
|
98
|
+
|
|
99
|
+
@Component({
|
|
100
|
+
selector: 'app-compact-buttons',
|
|
101
|
+
template: `
|
|
102
|
+
<div class="button-container">
|
|
103
|
+
<app-compact-button-actions
|
|
104
|
+
[data]="buttonActions"
|
|
105
|
+
[expand]="isExpanded">
|
|
106
|
+
</app-compact-button-actions>
|
|
107
|
+
|
|
108
|
+
<button (click)="toggleExpansion()">
|
|
109
|
+
{{ isExpanded ? 'Compact' : 'Expand' }} View
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
`
|
|
113
|
+
})
|
|
114
|
+
export class CompactButtonsComponent {
|
|
115
|
+
isExpanded = false;
|
|
116
|
+
|
|
117
|
+
buttonActions: ButtonAction[] = [
|
|
118
|
+
{ icon: 'dialpad', label: 'Phone', disabled: true },
|
|
119
|
+
{ icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },
|
|
120
|
+
{ icon: 'notifications_off', label: 'Alerts', badge: 0 }
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
toggleExpansion() {
|
|
124
|
+
this.isExpanded = !this.isExpanded;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Example 2: Form Control Integration
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { Component } from '@angular/core';
|
|
133
|
+
import { FormControl } from '@angular/forms';
|
|
134
|
+
import { ButtonAction } from 'action-compact-button';
|
|
135
|
+
|
|
136
|
+
@Component({
|
|
137
|
+
selector: 'app-form-compact-buttons',
|
|
138
|
+
template: `
|
|
9
139
|
<app-compact-button-actions
|
|
140
|
+
[formControl]="compactControl"
|
|
10
141
|
[data]="buttonActions"
|
|
11
|
-
[expand]="
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
142
|
+
[expand]="isExpanded">
|
|
143
|
+
</app-compact-button-actions>
|
|
144
|
+
|
|
145
|
+
<div class="controls">
|
|
146
|
+
<label>
|
|
147
|
+
<input type="checkbox" [(ngModel)]="isExpanded">
|
|
148
|
+
Expand Buttons
|
|
149
|
+
</label>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div>Selected: {{ compactControl.value | json }}</div>
|
|
153
|
+
`
|
|
154
|
+
})
|
|
155
|
+
export class FormCompactButtonsComponent {
|
|
156
|
+
isExpanded = true;
|
|
157
|
+
compactControl = new FormControl();
|
|
158
|
+
|
|
159
|
+
buttonActions: ButtonAction[] = [
|
|
160
|
+
{ icon: 'edit', label: 'Edit', color: 'primary' },
|
|
161
|
+
{ icon: 'delete', label: 'Delete', color: 'warn' },
|
|
162
|
+
{ icon: 'share', label: 'Share', color: 'accent' }
|
|
163
|
+
];
|
|
164
|
+
}
|
|
16
165
|
```
|
|
17
166
|
|
|
167
|
+
#### Example 3: Responsive Button Panel
|
|
18
168
|
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
169
|
+
```typescript
|
|
170
|
+
import { Component } from '@angular/core';
|
|
171
|
+
import { ButtonAction } from 'action-compact-button';
|
|
172
|
+
|
|
173
|
+
@Component({
|
|
174
|
+
selector: 'app-responsive-buttons',
|
|
175
|
+
template: `
|
|
176
|
+
<div class="responsive-container">
|
|
177
|
+
<h3>Action Panel</h3>
|
|
178
|
+
|
|
179
|
+
<app-compact-button-actions
|
|
180
|
+
[data]="actionButtons"
|
|
181
|
+
[expand]="isExpanded"
|
|
182
|
+
[disabled]="isDisabled">
|
|
183
|
+
</app-compact-button-actions>
|
|
184
|
+
|
|
185
|
+
<div class="controls">
|
|
186
|
+
<button (click)="toggleExpanded()">
|
|
187
|
+
{{ isExpanded ? 'Show Compact' : 'Show Labels' }}
|
|
188
|
+
</button>
|
|
189
|
+
|
|
190
|
+
<button (click)="toggleDisabled()">
|
|
191
|
+
{{ isDisabled ? 'Enable' : 'Disable' }}
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div class="status">
|
|
196
|
+
Mode: {{ isExpanded ? 'Expanded' : 'Compact' }} |
|
|
197
|
+
State: {{ isDisabled ? 'Disabled' : 'Enabled' }}
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
`,
|
|
201
|
+
styles: [`
|
|
202
|
+
.responsive-container {
|
|
203
|
+
padding: 1rem;
|
|
204
|
+
border: 1px solid #ddd;
|
|
205
|
+
border-radius: 4px;
|
|
206
|
+
}
|
|
207
|
+
.controls {
|
|
208
|
+
margin-top: 1rem;
|
|
209
|
+
display: flex;
|
|
210
|
+
gap: 0.5rem;
|
|
211
|
+
}
|
|
212
|
+
.status {
|
|
213
|
+
margin-top: 0.5rem;
|
|
214
|
+
font-size: 0.9rem;
|
|
215
|
+
color: #666;
|
|
216
|
+
}
|
|
217
|
+
`]
|
|
218
|
+
})
|
|
219
|
+
export class ResponsiveButtonsComponent {
|
|
220
|
+
isExpanded = false;
|
|
221
|
+
isDisabled = false;
|
|
222
|
+
|
|
223
|
+
actionButtons: ButtonAction[] = [
|
|
224
|
+
{ icon: 'save', label: 'Save', color: 'primary' },
|
|
225
|
+
{ icon: 'cancel', label: 'Cancel', color: 'warn' },
|
|
226
|
+
{ icon: 'help', label: 'Help', badge: 3 }
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
toggleExpanded() {
|
|
230
|
+
this.isExpanded = !this.isExpanded;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
toggleDisabled() {
|
|
234
|
+
this.isDisabled = !this.isDisabled;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### Example 4: Dashboard Action Buttons
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import { Component } from '@angular/core';
|
|
243
|
+
import { ButtonAction } from 'action-compact-button';
|
|
244
|
+
|
|
245
|
+
@Component({
|
|
246
|
+
selector: 'app-dashboard-actions',
|
|
247
|
+
template: `
|
|
248
|
+
<div class="dashboard">
|
|
249
|
+
<div class="header">
|
|
250
|
+
<h2>Dashboard</h2>
|
|
251
|
+
<app-compact-button-actions
|
|
252
|
+
[data]="dashboardActions"
|
|
253
|
+
[expand]="showLabels"
|
|
254
|
+
(selectionChange)="handleAction($event)">
|
|
255
|
+
</app-compact-button-actions>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<div class="content">
|
|
259
|
+
<p>Dashboard content goes here...</p>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
`,
|
|
263
|
+
styles: [`
|
|
264
|
+
.dashboard { padding: 1rem; }
|
|
265
|
+
.header {
|
|
266
|
+
display: flex;
|
|
267
|
+
justify-content: space-between;
|
|
268
|
+
align-items: center;
|
|
269
|
+
margin-bottom: 2rem;
|
|
270
|
+
}
|
|
271
|
+
.header h2 { margin: 0; }
|
|
272
|
+
`]
|
|
273
|
+
})
|
|
274
|
+
export class DashboardActionsComponent {
|
|
275
|
+
showLabels = false;
|
|
276
|
+
|
|
277
|
+
dashboardActions: ButtonAction[] = [
|
|
278
|
+
{ icon: 'refresh', label: 'Refresh', color: 'primary' },
|
|
279
|
+
{ icon: 'settings', label: 'Settings', color: 'accent' },
|
|
280
|
+
{ icon: 'notifications', label: 'Notifications', badge: this.getNotificationCount() },
|
|
281
|
+
{ icon: 'help', label: 'Help', color: 'warn' }
|
|
282
|
+
];
|
|
283
|
+
|
|
284
|
+
getNotificationCount(): number {
|
|
285
|
+
// Logic to get notification count
|
|
286
|
+
return 7;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
handleAction(action: ButtonAction) {
|
|
290
|
+
console.log('Action triggered:', action);
|
|
291
|
+
// Handle different actions based on icon/label
|
|
292
|
+
switch (action.icon) {
|
|
293
|
+
case 'refresh':
|
|
294
|
+
this.refreshDashboard();
|
|
295
|
+
break;
|
|
296
|
+
case 'settings':
|
|
297
|
+
this.openSettings();
|
|
298
|
+
break;
|
|
299
|
+
case 'notifications':
|
|
300
|
+
this.showNotifications();
|
|
301
|
+
break;
|
|
302
|
+
case 'help':
|
|
303
|
+
this.showHelp();
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private refreshDashboard() {
|
|
309
|
+
console.log('Refreshing dashboard...');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private openSettings() {
|
|
313
|
+
console.log('Opening settings...');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private showNotifications() {
|
|
317
|
+
console.log('Showing notifications...');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private showHelp() {
|
|
321
|
+
console.log('Showing help...');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Component API
|
|
329
|
+
|
|
330
|
+
### Inputs
|
|
331
|
+
|
|
332
|
+
| Input | Type | Description | Default |
|
|
333
|
+
| :--- | :--- | :--- | :--- |
|
|
334
|
+
| `data` | `ButtonAction[]` | Array of button action configurations | `[]` |
|
|
335
|
+
| `expand` | `boolean \| string` | Controls expansion state (true/expanded, false/compact) | `false` |
|
|
336
|
+
| `disabled` | `boolean` | Whether the entire component is disabled | `false` |
|
|
337
|
+
|
|
338
|
+
### Outputs
|
|
339
|
+
|
|
340
|
+
| Output | Type | Description |
|
|
341
|
+
| :--- | :--- | :--- |
|
|
342
|
+
| `selectionChange` | `EventEmitter<any>` | Emits when a button is selected/clicked |
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Model Structures
|
|
347
|
+
|
|
348
|
+
### ButtonAction Interface (Shared)
|
|
349
|
+
|
|
350
|
+
The `action-compact-button` package uses the same `ButtonAction` model as `action-buttons`:
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
export interface ButtonActionInterface {
|
|
354
|
+
label?: string; // Button text label
|
|
355
|
+
icon?: string; // Material icon name or custom icon
|
|
356
|
+
disabled?: boolean; // Individual button disabled state
|
|
357
|
+
badge?: number; // Notification badge count (0 or positive number)
|
|
358
|
+
color?: string; // Custom color (CSS color value)
|
|
359
|
+
svg?: boolean; // Whether icon is SVG format
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### ButtonAction Class (Shared)
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
export class ButtonAction implements ButtonActionInterface {
|
|
367
|
+
constructor(
|
|
368
|
+
public label?: string,
|
|
369
|
+
public icon?: string,
|
|
370
|
+
public disabled?: boolean = false,
|
|
371
|
+
public badge?: number = 0,
|
|
372
|
+
public color?: string,
|
|
373
|
+
public svg?: boolean = false
|
|
374
|
+
) {}
|
|
375
|
+
|
|
376
|
+
static adapt(data?: any): ButtonAction {
|
|
377
|
+
return new ButtonAction(
|
|
378
|
+
data?.label,
|
|
379
|
+
data?.icon,
|
|
380
|
+
(data?.disabled) ? data.disabled : false,
|
|
381
|
+
(data?.badge) ? data.badge : 0,
|
|
382
|
+
data?.color,
|
|
383
|
+
(data?.svg) ? true : false
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Usage Examples
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
// Compact mode buttons (icons more important)
|
|
393
|
+
const compactButtons: ButtonAction[] = [
|
|
394
|
+
{ icon: 'home', label: 'Home', color: 'primary' },
|
|
395
|
+
{ icon: 'search', label: 'Search', color: 'accent' },
|
|
396
|
+
{ icon: 'notifications', label: 'Alerts', badge: 5 },
|
|
397
|
+
{ icon: 'settings', label: 'Settings', color: 'warn' }
|
|
398
|
+
];
|
|
399
|
+
|
|
400
|
+
// Expanded mode buttons (labels more important)
|
|
401
|
+
const expandedButtons: ButtonAction[] = [
|
|
402
|
+
{ icon: 'save', label: 'Save Document', color: 'primary' },
|
|
403
|
+
{ icon: 'print', label: 'Print Report', color: 'accent' },
|
|
404
|
+
{ icon: 'email', label: 'Email Results', badge: 2 },
|
|
405
|
+
{ icon: 'download', label: 'Download Data', color: 'warn' }
|
|
406
|
+
];
|
|
407
|
+
|
|
408
|
+
// Mixed usage - some buttons work better compact, others expanded
|
|
409
|
+
const mixedButtons: ButtonAction[] = [
|
|
410
|
+
{ icon: 'home', label: 'Dashboard' }, // Good for both modes
|
|
411
|
+
{ icon: 'notifications', label: 'Alerts', badge: 3 }, // Badge visible in both modes
|
|
412
|
+
{ icon: 'settings', label: 'Settings' }, // Settings icon is descriptive
|
|
413
|
+
{ icon: 'book', label: 'Documentation' } // Book icon needs label in compact mode
|
|
414
|
+
];
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Module Configuration
|
|
420
|
+
|
|
421
|
+
### ActionCompactButtonModule
|
|
422
|
+
|
|
423
|
+
**No Global Configuration Required**
|
|
424
|
+
|
|
425
|
+
The `ActionCompactButtonModule` does not provide a `forRoot()` method or global configuration options. All configuration is done at the component level through input properties.
|
|
426
|
+
|
|
427
|
+
#### Module Structure
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
@NgModule({
|
|
431
|
+
imports: [
|
|
432
|
+
CommonModule,
|
|
433
|
+
FormsModule,
|
|
434
|
+
ReactiveFormsModule,
|
|
435
|
+
MatIconModule,
|
|
436
|
+
MatButtonModule,
|
|
437
|
+
MatBadgeModule,
|
|
438
|
+
],
|
|
439
|
+
declarations: [
|
|
440
|
+
ActionCompactButtonComponent,
|
|
441
|
+
ActionCompactButtonDemoComponent,
|
|
442
|
+
],
|
|
443
|
+
exports:[
|
|
444
|
+
ActionCompactButtonComponent,
|
|
445
|
+
ActionCompactButtonDemoComponent,
|
|
24
446
|
]
|
|
447
|
+
})
|
|
448
|
+
export class ActionCompactButtonModule { }
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
#### Dependencies
|
|
452
|
+
|
|
453
|
+
- **@angular/common**: Core Angular functionality
|
|
454
|
+
- **@angular/forms**: Form control integration
|
|
455
|
+
- **@angular/material**: Material Design components
|
|
456
|
+
- MatIconModule: Icon display
|
|
457
|
+
- MatButtonModule: Button base component
|
|
458
|
+
- MatBadgeModule: Badge notifications
|
|
459
|
+
- **Shared Models**: Uses `ButtonAction` model from `action-buttons` package
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Styling and Customization
|
|
464
|
+
|
|
465
|
+
### CSS Classes and Styling
|
|
466
|
+
|
|
467
|
+
The component uses Material Design styling and can be customized using:
|
|
468
|
+
|
|
469
|
+
1. **Global Material Theme**: Configure colors in your Angular Material theme
|
|
470
|
+
2. **Component-specific Styles**: Add custom CSS classes for different display modes
|
|
471
|
+
3. **Responsive Breakpoints**: Customize when to show compact vs expanded mode
|
|
472
|
+
4. **Color Input**: Use the `color` property for individual button styling
|
|
473
|
+
|
|
474
|
+
### Example Customization
|
|
475
|
+
|
|
476
|
+
```scss
|
|
477
|
+
// Custom styles for compact button actions
|
|
478
|
+
:host ::ng-deep .compact-button-actions {
|
|
479
|
+
&.compact-mode {
|
|
480
|
+
.mat-button-wrapper {
|
|
481
|
+
padding: 8px; // Smaller padding in compact mode
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.button-label {
|
|
485
|
+
display: none; // Hide labels in compact mode
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
&.expanded-mode {
|
|
490
|
+
.mat-button-wrapper {
|
|
491
|
+
padding: 12px 16px; // Larger padding in expanded mode
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.button-label {
|
|
495
|
+
display: inline-block;
|
|
496
|
+
margin-left: 8px;
|
|
497
|
+
font-size: 0.875rem;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Animation for expand/collapse transition
|
|
502
|
+
.mat-button {
|
|
503
|
+
transition: all 0.3s ease;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Responsive Behavior
|
|
509
|
+
|
|
510
|
+
```scss
|
|
511
|
+
// Auto-expand on desktop, compact on mobile
|
|
512
|
+
:host ::ng-deep .compact-button-actions {
|
|
513
|
+
@media (min-width: 768px) {
|
|
514
|
+
&[expand="false"] {
|
|
515
|
+
// Force expanded mode on larger screens
|
|
516
|
+
.button-label {
|
|
517
|
+
display: inline-block !important;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
@media (max-width: 767px) {
|
|
523
|
+
// Compact mode on mobile
|
|
524
|
+
&[expand="false"] {
|
|
525
|
+
.button-label {
|
|
526
|
+
display: none;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Accessibility
|
|
536
|
+
|
|
537
|
+
### ARIA Support
|
|
538
|
+
|
|
539
|
+
- Buttons include proper ARIA labels in both compact and expanded modes
|
|
540
|
+
- Keyboard navigation is supported across all button states
|
|
541
|
+
- Screen reader friendly with appropriate labels and descriptions
|
|
542
|
+
- Badge notifications include appropriate ARIA live regions
|
|
543
|
+
- Expand/collapse state is communicated to assistive technologies
|
|
544
|
+
|
|
545
|
+
### Best Practices
|
|
546
|
+
|
|
547
|
+
1. **Provide meaningful labels** for all buttons (used in expanded mode)
|
|
548
|
+
2. **Use descriptive icons** that work well in compact mode
|
|
549
|
+
3. **Set badge counts appropriately** for notification indicators
|
|
550
|
+
4. **Consider screen size** when implementing expand/collapse logic
|
|
551
|
+
5. **Test with screen readers** in both compact and expanded modes
|
|
552
|
+
6. **Maintain consistent spacing** between compact and expanded layouts
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
## Integration Examples
|
|
557
|
+
|
|
558
|
+
### With Screen Observer
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
import { Component } from '@angular/core';
|
|
562
|
+
import { ScreenObserverService } from 'screen-observer';
|
|
563
|
+
|
|
564
|
+
@Component({
|
|
565
|
+
template: `
|
|
566
|
+
<app-compact-button-actions
|
|
567
|
+
[data]="actionButtons"
|
|
568
|
+
[expand]="shouldExpand">
|
|
569
|
+
</app-compact-button-actions>
|
|
570
|
+
`
|
|
571
|
+
})
|
|
572
|
+
export class ResponsiveActionsComponent {
|
|
573
|
+
shouldExpand = false;
|
|
574
|
+
|
|
575
|
+
constructor(private screenObserver: ScreenObserverService) {
|
|
576
|
+
this.screenObserver.screenSize$.subscribe(screenType => {
|
|
577
|
+
// Expand on tablets and desktop, compact on mobile
|
|
578
|
+
this.shouldExpand = ['TC52', 'Mobile'].indexOf(screenType) === -1;
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
actionButtons: ButtonAction[] = [
|
|
583
|
+
{ icon: 'home', label: 'Home' },
|
|
584
|
+
{ icon: 'search', label: 'Search' },
|
|
585
|
+
{ icon: 'notifications', label: 'Alerts', badge: 3 }
|
|
586
|
+
];
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### With State Management
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
// Integration with HTTP Request Manager
|
|
594
|
+
@Component({
|
|
595
|
+
template: `
|
|
596
|
+
<app-compact-button-actions
|
|
597
|
+
[data]="actionButtons$ | async"
|
|
598
|
+
[expand]="uiState.expanded"
|
|
599
|
+
(selectionChange)="handleAction($event)">
|
|
600
|
+
</app-compact-button-actions>
|
|
601
|
+
`
|
|
602
|
+
})
|
|
603
|
+
export class StateManagedCompactButtonsComponent {
|
|
604
|
+
actionButtons$ = this.actionStore.buttons$;
|
|
605
|
+
uiState = { expanded: false };
|
|
606
|
+
|
|
607
|
+
constructor(private actionStore: ActionStore) {}
|
|
608
|
+
|
|
609
|
+
handleAction(action: ButtonAction) {
|
|
610
|
+
this.actionStore.executeAction(action);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### With Column Fitter
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
import { Component } from '@angular/core';
|
|
619
|
+
import { ColumnFitterService } from 'column-fitter';
|
|
620
|
+
|
|
621
|
+
@Component({
|
|
622
|
+
template: `
|
|
623
|
+
<div [style.gridTemplateColumns]="columnTemplate">
|
|
624
|
+
<app-compact-button-actions
|
|
625
|
+
[data]="actionButtons"
|
|
626
|
+
[expand]="columnsFit > 2">
|
|
627
|
+
</app-compact-button-actions>
|
|
628
|
+
</div>
|
|
629
|
+
`
|
|
630
|
+
})
|
|
631
|
+
export class AdaptiveActionsComponent {
|
|
632
|
+
columnsFit = 1;
|
|
633
|
+
columnTemplate = '1fr';
|
|
634
|
+
|
|
635
|
+
constructor(private columnFitter: ColumnFitterService) {
|
|
636
|
+
this.columnFitter.columns$.subscribe(columns => {
|
|
637
|
+
this.columnsFit = columns;
|
|
638
|
+
this.columnTemplate = `repeat(${columns}, 1fr)`;
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
actionButtons: ButtonAction[] = [
|
|
643
|
+
{ icon: 'add', label: 'Add Item' },
|
|
644
|
+
{ icon: 'edit', label: 'Edit' },
|
|
645
|
+
{ icon: 'delete', label: 'Delete' },
|
|
646
|
+
{ icon: 'share', label: 'Share' }
|
|
647
|
+
];
|
|
648
|
+
}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Testing
|
|
654
|
+
|
|
655
|
+
### Unit Testing Example
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
659
|
+
import { ActionCompactButtonComponent } from './action-compact-button.component';
|
|
660
|
+
import { ButtonAction } from './models';
|
|
661
|
+
|
|
662
|
+
describe('ActionCompactButtonComponent', () => {
|
|
663
|
+
let component: ActionCompactButtonComponent;
|
|
664
|
+
let fixture: ComponentFixture<ActionCompactButtonComponent>;
|
|
665
|
+
|
|
666
|
+
beforeEach(async () => {
|
|
667
|
+
await TestBed.configureTestingModule({
|
|
668
|
+
declarations: [ ActionCompactButtonComponent ]
|
|
669
|
+
}).compileComponents();
|
|
670
|
+
|
|
671
|
+
fixture = TestBed.createComponent(ActionCompactButtonComponent);
|
|
672
|
+
component = fixture.componentInstance;
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
it('should create', () => {
|
|
676
|
+
expect(component).toBeTruthy();
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it('should display buttons in compact mode when expand is false', () => {
|
|
680
|
+
component.data = [{ label: 'Test', icon: 'home' }];
|
|
681
|
+
component.expand = false;
|
|
682
|
+
fixture.detectChanges();
|
|
683
|
+
|
|
684
|
+
const compiled = fixture.nativeElement;
|
|
685
|
+
const labels = compiled.querySelectorAll('.button-label');
|
|
686
|
+
expect(labels.length).toBe(0); // Labels hidden in compact mode
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
it('should display buttons in expanded mode when expand is true', () => {
|
|
690
|
+
component.data = [{ label: 'Test', icon: 'home' }];
|
|
691
|
+
component.expand = true;
|
|
692
|
+
fixture.detectChanges();
|
|
693
|
+
|
|
694
|
+
const compiled = fixture.nativeElement;
|
|
695
|
+
const labels = compiled.querySelectorAll('.button-label');
|
|
696
|
+
expect(labels.length).toBe(1); // Labels shown in expanded mode
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
it('should toggle expand state correctly', () => {
|
|
700
|
+
component.data = [{ label: 'Test', icon: 'home' }];
|
|
701
|
+
|
|
702
|
+
component.expand = false;
|
|
703
|
+
fixture.detectChanges();
|
|
704
|
+
expect(component.expand).toBe(false);
|
|
705
|
+
|
|
706
|
+
component.expand = true;
|
|
707
|
+
fixture.detectChanges();
|
|
708
|
+
expect(component.expand).toBe(true);
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
it('should emit selection change when button is clicked', () => {
|
|
712
|
+
spyOn(component.selectionChange, 'emit');
|
|
713
|
+
component.data = [{ label: 'Test', icon: 'home' }];
|
|
714
|
+
fixture.detectChanges();
|
|
715
|
+
|
|
716
|
+
const button = fixture.nativeElement.querySelector('button');
|
|
717
|
+
button.click();
|
|
718
|
+
|
|
719
|
+
expect(component.selectionChange.emit).toHaveBeenCalled();
|
|
720
|
+
});
|
|
721
|
+
});
|
|
25
722
|
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## Troubleshooting
|
|
727
|
+
|
|
728
|
+
### Common Issues
|
|
729
|
+
|
|
730
|
+
1. **Icons not displaying**: Ensure Material Icons are loaded in your index.html
|
|
731
|
+
2. **Labels not showing in expanded mode**: Check that expand input is set to true
|
|
732
|
+
3. **Compact mode not working**: Verify expand input is set to false or not provided
|
|
733
|
+
4. **Form control not working**: Verify ReactiveFormsModule is imported
|
|
734
|
+
5. **Badge not showing**: Make sure MatBadgeModule is imported in your module
|
|
735
|
+
|
|
736
|
+
### Performance Tips
|
|
737
|
+
|
|
738
|
+
1. **Use OnPush change detection** for better performance with large button arrays
|
|
739
|
+
2. **Implement trackBy** for dynamic button lists
|
|
740
|
+
3. **Avoid frequent data object recreation** to prevent unnecessary re-renders
|
|
741
|
+
4. **Use immutable data patterns** for button action updates
|
|
742
|
+
5. **Consider debouncing** expand/collapse state changes for smooth animations
|
|
743
|
+
|
|
744
|
+
### Debug Mode
|
|
745
|
+
|
|
746
|
+
```typescript
|
|
747
|
+
// Add debugging to track expand/collapse state
|
|
748
|
+
@Component({
|
|
749
|
+
template: `
|
|
750
|
+
<div class="debug-info">
|
|
751
|
+
Expand State: {{ expand }} |
|
|
752
|
+
Data Length: {{ data?.length || 0 }} |
|
|
753
|
+
Disabled: {{ disabled }}
|
|
754
|
+
</div>
|
|
755
|
+
|
|
756
|
+
<app-compact-button-actions
|
|
757
|
+
[data]="data"
|
|
758
|
+
[expand]="expand"
|
|
759
|
+
[disabled]="disabled">
|
|
760
|
+
</app-compact-button-actions>
|
|
761
|
+
`
|
|
762
|
+
})
|
|
763
|
+
export class DebugCompactButtonsComponent {
|
|
764
|
+
expand = false;
|
|
765
|
+
disabled = false;
|
|
766
|
+
data: ButtonAction[] = [];
|
|
767
|
+
}
|
|
768
|
+
```
|