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 CHANGED
@@ -1,25 +1,768 @@
1
- # Action Compact Buttons
1
+ # Action Compact Button Component
2
2
 
3
- This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.0.
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
- <div style="margin: 2rem;">
7
- <div style="display: flex; gap: 2rem">
8
- <!-- Display Card - Compact Buttons -->
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]="expand.checked"
12
- ></app-compact-button-actions>
13
- <mat-checkbox #expand>Expanded Buttons</mat-checkbox>
14
- </div>
15
- </div>
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
- ```ts
20
- buttonActions: ButtonAction[] = [
21
- { icon: 'dialpad', label: 'Phone', disabled: true},
22
- { icon: 'voicemail', label: 'Messages', badge: 6, color: 'orange' },
23
- { icon: 'notifications_off', label: 'Alerts', badge: 0 },
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
+ ```