/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
import {
ChangeDetectionStrategy,
Component,
ElementRef,
HostBinding,
Input,
OnChanges,
OnInit,
Renderer2,
} from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { NbStatusService } from '../../services/status.service';
import { NbComponentOrCustomStatus } from '../component-status';
import { NbIconLibraries } from './icon-libraries';
export interface NbIconConfig {
icon: string;
pack?: string;
status?: NbComponentOrCustomStatus;
options?: { [name: string]: any };
}
/**
* Icon component. Allows to render both `svg` and `font` icons.
* Starting from Nebular 4.0 uses [Eva Icons](https://akveo.github.io/eva-icons/) pack by default.
*
* Basic icon example:
* @stacked-example(Showcase, icon/icon-showcase.component)
*
* Icon configuration:
*
* ```html
*
* ```
* ### Installation
*
* By default Nebular comes without any pre-installed icon pack.
* Starting with Nebular 4.0.0 we ship separate package called `@nebular/eva-icons`
* which integrates SVG [Eva Icons](https://akveo.github.io/eva-icons/) pack to Nebular. To add it to your
* project run:
* ```sh
* npm i eva-icons @nebular/eva-icons
* ```
* This command will install Eva Icons pack. Then register `NbEvaIconsModule` into your app module:
* ```ts
* import { NbEvaIconsModule } from '@nebular/eva-icons';
*
* @NgModule({
* imports: [
* // ...
* NbEvaIconsModule,
* ],
* })
* export class AppModule { }
* ```
* Last thing, import `NbIconModule` to your feature module where you need to show an icon:
* ```ts
* import { NbIconModule } from '@nebular/theme';
*
* @NgModule({
* imports: [
* // ...
* NbIconModule,
* ],
* })
* export class PageModule { }
* ```
* ### Usage
*
* Icon can be colored using `status` input:
* ```html
*
* ```
*
* Colored icons:
* @stacked-example(Colored Icons, icon/icon-colors.component)
*
* In case you need to specify an icon from a specific icon pack, this could be done using `pack` input property:
* ```html
*
* ```
* Additional icon settings (if available by the icon pack) could be passed using `options` input:
*
* ```html
*
* ```
*
* @styles
*
* icon-font-size:
* icon-line-height:
* icon-width:
* icon-height:
* icon-svg-vertical-align:
* icon-basic-color:
* icon-primary-color:
* icon-info-color:
* icon-success-color:
* icon-warning-color:
* icon-danger-color:
* icon-control-color:
*/
@Component({
selector: 'nb-icon',
styleUrls: [`./icon.component.scss`],
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NbIconComponent implements NbIconConfig, OnChanges, OnInit {
protected iconDef;
protected prevClasses = [];
@HostBinding('innerHtml')
html: SafeHtml = '';
@HostBinding('class.status-primary')
get primary() {
return this.status === 'primary';
}
@HostBinding('class.status-info')
get info() {
return this.status === 'info';
}
@HostBinding('class.status-success')
get success() {
return this.status === 'success';
}
@HostBinding('class.status-warning')
get warning() {
return this.status === 'warning';
}
@HostBinding('class.status-danger')
get danger() {
return this.status === 'danger';
}
@HostBinding('class.status-basic')
get basic() {
return this.status === 'basic';
}
@HostBinding('class.status-control')
get control() {
return this.status === 'control';
}
@HostBinding('class')
get additionalClasses(): string[] {
if (this.statusService.isCustomStatus(this.status)) {
return [this.statusService.getStatusClass(this.status)];
}
return [];
}
/**
* Icon name
* @param {string} status
*/
@Input() icon: string;
/**
* Icon pack name
* @param {string} status
*/
@Input() pack: string;
/**
* Additional icon settings
* @param {[name: string]: any}
*/
@Input() options: { [name: string]: any };
/**
* Icon status (adds specific styles):
* `basic`, `primary`, `info`, `success`, `warning`, `danger`, `control`
*/
@Input() status?: NbComponentOrCustomStatus;
/**
* Sets all icon configurable properties via config object.
* If passed value is a string set icon name.
* @docs-private
*/
@Input()
get config(): string | NbIconConfig {
return this._config;
}
set config(value: string | NbIconConfig) {
if (!value) {
return;
}
this._config = value;
if (typeof value === 'string') {
this.icon = value;
} else {
this.icon = value.icon;
this.pack = value.pack;
this.status = value.status;
this.options = value.options;
}
}
protected _config: string | NbIconConfig;
constructor(
protected sanitizer: DomSanitizer,
protected iconLibrary: NbIconLibraries,
protected el: ElementRef,
protected renderer: Renderer2,
protected statusService: NbStatusService,
) {}
ngOnInit() {
this.iconDef = this.renderIcon(this.icon, this.pack, this.options);
}
ngOnChanges() {
const iconDef = this.iconLibrary.getIcon(this.icon, this.pack);
if (iconDef) {
this.renderIcon(this.icon, this.pack, this.options);
} else {
this.clearIcon();
}
}
renderIcon(name: string, pack?: string, options?: { [name: string]: any }) {
const iconDefinition = this.iconLibrary.getIcon(name, pack);
if (!iconDefinition) {
return;
}
const content = iconDefinition.icon.getContent(options);
if (content) {
this.html = this.sanitizer.bypassSecurityTrustHtml(content);
}
this.assignClasses(iconDefinition.icon.getClasses(options));
return iconDefinition;
}
protected clearIcon(): void {
this.html = '';
this.assignClasses([]);
}
protected assignClasses(classes: string[]) {
this.prevClasses.forEach((className: string) => {
this.renderer.removeClass(this.el.nativeElement, className);
});
classes.forEach((className: string) => {
this.renderer.addClass(this.el.nativeElement, className);
});
this.prevClasses = classes;
}
}