Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/framework/theme/components/tag/tag.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{{ text }}
<nb-icon *ngIf="removable"
(click)="_remove()"
class="nb-tag-remove size-{{size}}"
icon="close-outline"
pack="nebular-essentials"
aria-hidden="true">
<nb-icon
*ngIf="removable"
(click)="_remove()"
class="nb-tag-remove size-{{ size }}"
[icon]="removeIcon"
[pack]="removeIconPack"
aria-hidden="true"
>
</nb-icon>
31 changes: 22 additions & 9 deletions src/framework/theme/components/tag/tag.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,13 @@ let tagUniqueId = 0;
* tag-outline-control-selected-text-color:
*/
@Component({
selector: 'nb-tag',
templateUrl: './tag.component.html',
exportAs: 'nbTag',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false
selector: 'nb-tag',
templateUrl: './tag.component.html',
exportAs: 'nbTag',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false,
})
export class NbTagComponent implements AfterViewInit, OnDestroy, NbHighlightableOption {

private _destroy$: Subject<NbTagComponent> = new Subject<NbTagComponent>();

get destroy$(): Observable<NbTagComponent> {
Expand Down Expand Up @@ -275,6 +274,18 @@ export class NbTagComponent implements AfterViewInit, OnDestroy, NbHighlightable
protected _removable: boolean = false;
static ngAcceptInputType_removable: NbBooleanInput;

/**
* Remove icon name
* @param {string} status
*/
@Input() removeIcon: string = 'close-outline';

/**
* Remove icon pack name
* @param {string} status
*/
@Input() removeIconPack: string = 'nebular-essentials';

/**
* Tag appearance: `filled`, `outline`.
*/
Expand Down Expand Up @@ -414,9 +425,11 @@ export class NbTagComponent implements AfterViewInit, OnDestroy, NbHighlightable

ngAfterViewInit() {
// TODO: #2254
this.zone.runOutsideAngular(() => setTimeout(() => {
this.renderer.addClass(this._hostElement.nativeElement, 'nb-transition');
}));
this.zone.runOutsideAngular(() =>
setTimeout(() => {
this.renderer.addClass(this._hostElement.nativeElement, 'nb-transition');
}),
);
}

ngOnDestroy() {
Expand Down
230 changes: 124 additions & 106 deletions src/framework/theme/components/tag/tag.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,123 +4,141 @@ import { NbTagComponent, NbTagModule, NbThemeModule } from '@nebular/theme';
import createSpy = jasmine.createSpy;

@Component({
selector: 'nb-tag-test',
template: `<nb-tag [text]="'test-tag'" [removable]="isRemovable" [selected]="selected"></nb-tag>`,
standalone: false
selector: 'nb-tag-test',
template: `<nb-tag
[text]="'test-tag'"
[removable]="isRemovable"
[selected]="selected"
[removeIcon]="removeIcon"
[removeIconPack]="removeIconPack"
></nb-tag>`,
standalone: false,
})

export class NbTagTestComponent {
@ViewChild(NbTagComponent) nbTag: NbTagComponent;
isRemovable: boolean = true;
selected: boolean = false;
@ViewChild(NbTagComponent) nbTag: NbTagComponent;
isRemovable: boolean = true;
selected: boolean = false;
removeIcon: string = 'close-outline';
removeIconPack: string = 'nebular-essentials';
}

describe('Component: NbTagComponent', () => {
let tag: NbTagComponent;
let fixture: ComponentFixture<NbTagComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [NbThemeModule.forRoot(), NbTagModule],
declarations: [NbTagTestComponent],
});

fixture = TestBed.createComponent(NbTagComponent);
tag = fixture.componentInstance;
fixture.detectChanges();
});

it('should be created', () => {
expect(tag).toBeTruthy();
})

it('should return default selected property', () => {
expect(fixture.nativeElement.classList).not.toContain('selected');
});

it('should return toggled selection value', () => {
tag._toggleSelection();
fixture.detectChanges();
expect(fixture.nativeElement.classList).toContain('selected');
});

it('should be inactive by default', () => {
expect(fixture.nativeElement.classList).not.toContain('active');
});
let tag: NbTagComponent;
let fixture: ComponentFixture<NbTagComponent>;

it('should be active', () => {
tag.setActiveStyles();
fixture.detectChanges();
expect(fixture.nativeElement.classList).toContain('active');
});

it('should return applied inactive state', () => {
tag.setInactiveStyles();
fixture.detectChanges();
expect(fixture.nativeElement.classList).not.toContain('active');
beforeEach(() => {
TestBed.configureTestingModule({
imports: [NbThemeModule.forRoot(), NbTagModule],
declarations: [NbTagTestComponent],
});

fixture = TestBed.createComponent(NbTagComponent);
tag = fixture.componentInstance;
fixture.detectChanges();
});

it('should be created', () => {
expect(tag).toBeTruthy();
});

it('should return default selected property', () => {
expect(fixture.nativeElement.classList).not.toContain('selected');
});

it('should return toggled selection value', () => {
tag._toggleSelection();
fixture.detectChanges();
expect(fixture.nativeElement.classList).toContain('selected');
});

it('should be inactive by default', () => {
expect(fixture.nativeElement.classList).not.toContain('active');
});

it('should be active', () => {
tag.setActiveStyles();
fixture.detectChanges();
expect(fixture.nativeElement.classList).toContain('active');
});

it('should return applied inactive state', () => {
tag.setInactiveStyles();
fixture.detectChanges();
expect(fixture.nativeElement.classList).not.toContain('active');
});
});

describe('Component: NbTagComponent bindings', () => {
let fixture: ComponentFixture<NbTagTestComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [NbThemeModule.forRoot(), NbTagModule],
declarations: [NbTagTestComponent],
});
fixture = TestBed.createComponent(NbTagTestComponent);
fixture.detectChanges();
});
let fixture: ComponentFixture<NbTagTestComponent>;

it('should be created', () => {
const tagEl = fixture.nativeElement.querySelector('nb-tag');
expect(tagEl).toBeTruthy();
beforeEach(() => {
TestBed.configureTestingModule({
imports: [NbThemeModule.forRoot(), NbTagModule],
declarations: [NbTagTestComponent],
});

it('should emit remove event on delete keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
tagEl.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'delete' }));
expect(removeSpy).toHaveBeenCalled();
});

it('should not emit remove event on delete keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
fixture.componentInstance.isRemovable = false;
fixture.detectChanges();
tagEl.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'delete' }));
expect(removeSpy).not.toHaveBeenCalled();
});

it('should emit remove event on backspace keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
tagEl.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'backspace' }));
expect(removeSpy).toHaveBeenCalled();
});

it('should not emit remove event on backspace keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
fixture.componentInstance.isRemovable = false;
fixture.detectChanges();
tagEl.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'backspace' }));
expect(removeSpy).not.toHaveBeenCalled();
});

it('should emit selected change event', () => {
const selectedSpy = createSpy('selected');
fixture.componentInstance.nbTag.selectedChange.subscribe(selectedSpy);
fixture.componentInstance.selected = true;
fixture.detectChanges();
expect(selectedSpy).toHaveBeenCalled();
});

fixture = TestBed.createComponent(NbTagTestComponent);
fixture.detectChanges();
});

it('should be created', () => {
const tagEl = fixture.nativeElement.querySelector('nb-tag');
expect(tagEl).toBeTruthy();
});

it('should emit remove event on delete keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
tagEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'delete' }));
expect(removeSpy).toHaveBeenCalled();
});

it('should not emit remove event on delete keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
fixture.componentInstance.isRemovable = false;
fixture.detectChanges();
tagEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'delete' }));
expect(removeSpy).not.toHaveBeenCalled();
});

it('should emit remove event on backspace keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
tagEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'backspace' }));
expect(removeSpy).toHaveBeenCalled();
});

it('should not emit remove event on backspace keydown', () => {
const removeSpy = createSpy('removeSpy');
const tagEl = fixture.nativeElement.querySelector('nb-tag');
fixture.componentInstance.nbTag.remove.subscribe(removeSpy);
fixture.componentInstance.isRemovable = false;
fixture.detectChanges();
tagEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'backspace' }));
expect(removeSpy).not.toHaveBeenCalled();
});

it('should emit selected change event', () => {
const selectedSpy = createSpy('selected');
fixture.componentInstance.nbTag.selectedChange.subscribe(selectedSpy);
fixture.componentInstance.selected = true;
fixture.detectChanges();
expect(selectedSpy).toHaveBeenCalled();
});

it('should render custom remove icon pack', () => {
fixture.componentInstance.removeIcon = 'plus-outline';
fixture.componentInstance.removeIconPack = 'eva';
fixture.detectChanges();

const tagEl: HTMLElement = fixture.nativeElement.querySelector('nb-tag');
const iconEl: HTMLElement | null = tagEl.querySelector('nb-icon');

expect(iconEl).toBeTruthy();
expect(iconEl.getAttribute('ng-reflect-icon')).toBe('plus-outline');
expect(iconEl.getAttribute('ng-reflect-pack')).toBe('eva');
});
});