Skip to content

Commit

Permalink
feat(icon): new component and example usage in menu
Browse files Browse the repository at this point in the history
  • Loading branch information
alexciesielski committed May 21, 2024
1 parent c42b73b commit f504079
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 3 deletions.
Empty file.
46 changes: 46 additions & 0 deletions src/app/components/icon/icon.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Component, Input } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Icon, PIconComponent, P_ICON_COMPONENT } from './icon';

describe('Icon', () => {
let fixture: ComponentFixture<Icon>;

beforeEach(() => TestBed.configureTestingModule({ imports: [Icon] }));

it('should display default template if no override has been defined', () => {
fixture = TestBed.createComponent(Icon);
fixture.componentInstance.icon = 'pi pi-check';
fixture.componentInstance.iconStyle = { color: 'red' };

fixture.detectChanges();
const iconEl = fixture.debugElement.query(By.css('i'));
expect(iconEl).toBeTruthy();
});

it('should display custom component if override has been defined', () => {
@Component({
standalone: true,
selector: 'custom-icon',
template: ` Hello world! `
})
class CustomIconComponent implements PIconComponent {
@Input() icon: string;
@Input() iconStyle?: any;
@Input() iconClass?: any;
}

TestBed.overrideProvider(P_ICON_COMPONENT, { useValue: CustomIconComponent });
fixture = TestBed.createComponent(Icon);
fixture.componentInstance.icon = 'pi pi-check';
fixture.componentInstance.iconStyle = { color: 'red' };

fixture.detectChanges();
const customIconEl = fixture.debugElement.query(By.css('custom-icon'));
expect(customIconEl).toBeTruthy();

const customIconComponent = customIconEl.componentInstance as CustomIconComponent;
expect(customIconComponent.icon).toBe('pi pi-check');
expect(customIconComponent.iconStyle).toEqual({ color: 'red' });
});
});
38 changes: 38 additions & 0 deletions src/app/components/icon/icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NgClass, NgComponentOutlet, NgStyle } from '@angular/common';
import { ChangeDetectionStrategy, Component, InjectionToken, Input, Type, inject } from '@angular/core';

export interface PIconComponent {
icon: string;
iconStyle?: NgStyle['ngStyle'];
}

export const P_ICON_COMPONENT = new InjectionToken<Type<PIconComponent>>('P_ICON_COMPONENT');

/**
* Icon is a simple component to render an icon.
* @group Components
*/
@Component({
standalone: true,
imports: [NgClass, NgStyle, NgComponentOutlet],
selector: 'p-icon',
template: `
@if(!iconComponentClass) {
<i [ngClass]="icon" [ngStyle]="iconStyle"></i>
} @else {
<ng-container *ngComponentOutlet="iconComponentClass; inputs: { icon: icon, iconStyle: iconStyle }" />
}
`,
styleUrls: ['./icon.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
class: 'p-element'
// style: 'display: contents'
}
})
export class Icon implements PIconComponent {
@Input({ required: true }) icon: string;
@Input() iconStyle?: NgStyle['ngStyle'];

protected readonly iconComponentClass = inject(P_ICON_COMPONENT, { optional: true });
}
6 changes: 6 additions & 0 deletions src/app/components/icon/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "ng-packagr/ng-package.schema.json",
"lib": {
"entryFile": "public_api.ts"
}
}
1 change: 1 addition & 0 deletions src/app/components/icon/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './icon';
9 changes: 6 additions & 3 deletions src/app/components/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
ViewRef,
booleanAttribute,
computed,
effect,
forwardRef,
numberAttribute,
signal
Expand All @@ -36,6 +35,7 @@ import { RippleModule } from 'primeng/ripple';
import { TooltipModule } from 'primeng/tooltip';
import { Nullable, VoidListener } from 'primeng/ts-helpers';
import { UniqueComponentId, ZIndexUtils } from 'primeng/utils';
import { Icon } from '../icon/icon';

@Pipe({
name: 'safeHtml'
Expand Down Expand Up @@ -103,7 +103,10 @@ export class SafeHtmlPipe implements PipeTransform {
</ng-container>
<ng-template #itemContent>
<span class="p-menuitem-icon" *ngIf="item.icon" [ngClass]="item.icon" [class]="item.iconClass" [ngStyle]="item.iconStyle"></span>
@if(item.icon) {
<p-icon class="p-menuitem-icon" [icon]="item.icon" [iconStyle]="item.iconStyle" />
}
<span class="p-menuitem-text" *ngIf="item.escape !== false; else htmlLabel">{{ item.label }}</span>
<ng-template #htmlLabel><span class="p-menuitem-text" [innerHTML]="item.label | safeHtml"></span></ng-template>
<span class="p-menuitem-badge" *ngIf="item.badge" [ngClass]="item.badgeStyleClass">{{ item.badge }}</span>
Expand Down Expand Up @@ -821,7 +824,7 @@ export class Menu implements OnDestroy {
}

@NgModule({
imports: [CommonModule, RouterModule, RippleModule, TooltipModule],
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, Icon],
exports: [Menu, RouterModule, TooltipModule],
declarations: [Menu, MenuItemContent, SafeHtmlPipe]
})
Expand Down

0 comments on commit f504079

Please sign in to comment.