diff --git a/e2e/actions.e2e-spec.ts b/e2e/actions.e2e-spec.ts index e998f71902..63c420515a 100644 --- a/e2e/actions.e2e-spec.ts +++ b/e2e/actions.e2e-spec.ts @@ -5,7 +5,6 @@ */ import { browser } from 'protractor'; -import { NbBadgeComponent } from '../src/framework/theme/components/badge/badge.component'; import badgeTests from './badge.e2e-spec'; describe('nb-action', () => { @@ -19,7 +18,7 @@ describe('nb-action', () => { const badgesConf = { selector: (i) => `nb-card:nth-child(4) nb-actions nb-action:nth-child(${i + 1}) nb-badge > span`, badges: [ - { position: NbBadgeComponent.BOTTOM_LEFT, status: NbBadgeComponent.STATUS_SUCCESS, text: badgeText }, + { position: 'bottom left', status: 'success', text: badgeText }, ], }; badgeTests(badgesConf); diff --git a/e2e/user.e2e-spec.ts b/e2e/user.e2e-spec.ts index 0d0b361011..5f5853b75f 100644 --- a/e2e/user.e2e-spec.ts +++ b/e2e/user.e2e-spec.ts @@ -5,7 +5,6 @@ */ import { browser, element, by } from 'protractor'; -import { NbBadgeComponent } from '../src/framework/theme/components/badge/badge.component'; import badgeTests from './badge.e2e-spec'; describe('nb-user', () => { @@ -20,7 +19,7 @@ describe('nb-user', () => { const badgesConf = { selector: (i) => `.test-row:nth-child(${elementsOffset + i + 1}) nb-badge > span`, badges: [ - { position: NbBadgeComponent.TOP_RIGHT, status: NbBadgeComponent.STATUS_PRIMARY, text: badgeText }, + { position: 'top right', status: 'primary', text: badgeText }, ], }; badgeTests(badgesConf); diff --git a/src/framework/theme/components/actions/actions.component.ts b/src/framework/theme/components/actions/actions.component.ts index 779f634b1d..fc6d321192 100644 --- a/src/framework/theme/components/actions/actions.component.ts +++ b/src/framework/theme/components/actions/actions.component.ts @@ -8,6 +8,8 @@ import { Component, HostBinding, Input } from '@angular/core'; import { convertToBoolProperty } from '../helpers'; import { NbComponentSize } from '../component-size'; +import { NbComponentStatus } from '../component-status'; +import { NbBadgePosition } from '../badge/badge.component'; /** * Action item, display a link with an icon, or any other content provided instead. @@ -100,7 +102,7 @@ export class NbActionComponent { * 'primary', 'info', 'success', 'warning', 'danger' * @param {string} val */ - @Input() badgeStatus: string; + @Input() badgeStatus: NbComponentStatus; /** * Badge position. @@ -109,7 +111,7 @@ export class NbActionComponent { * 'top start', 'top end', 'bottom start', 'bottom end' * @type string */ - @Input() badgePosition: string; + @Input() badgePosition: NbBadgePosition; } /** diff --git a/src/framework/theme/components/actions/actions.spec.ts b/src/framework/theme/components/actions/actions.spec.ts index 16274726d3..4f05fb3852 100644 --- a/src/framework/theme/components/actions/actions.spec.ts +++ b/src/framework/theme/components/actions/actions.spec.ts @@ -188,14 +188,14 @@ describe('NbActionComponent link with icon', () => { it('should pass set badge position and status to badge component', () => { actionComponent.badgeText = '1'; - actionComponent.badgePosition = NbBadgeComponent.BOTTOM_RIGHT; - actionComponent.badgeStatus = NbBadgeComponent.STATUS_INFO; + actionComponent.badgePosition = 'bottom right'; + actionComponent.badgeStatus = 'info'; fixture.detectChanges(); const badge = fixture.debugElement.query(By.directive(NbBadgeComponent)); const badgeComponent: NbBadgeComponent = badge.componentInstance; - expect(badgeComponent.position).toEqual(NbBadgeComponent.BOTTOM_RIGHT); - expect(badgeComponent.colorClass).toEqual(NbBadgeComponent.STATUS_INFO); + expect(badgeComponent.position).toEqual('bottom right'); + expect(badgeComponent.status).toEqual('info'); }); }); diff --git a/src/framework/theme/components/badge/_badge.component.theme.scss b/src/framework/theme/components/badge/_badge.component.theme.scss index 049ad6a767..390ff7af3a 100644 --- a/src/framework/theme/components/badge/_badge.component.theme.scss +++ b/src/framework/theme/components/badge/_badge.component.theme.scss @@ -5,23 +5,19 @@ */ @mixin nb-badge-theme() { - .nb-badge { - color: nb-theme(badge-fg-text); + nb-badge { + border-radius: nb-theme(badge-border-radius); + font-family: nb-theme(badge-text-font-family); + font-size: nb-theme(badge-text-font-size); + font-weight: nb-theme(badge-text-font-weight); + line-height: nb-theme(badge-text-line-height); + padding: nb-theme(badge-padding); + } - &.nb-badge-primary { - background-color: nb-theme(badge-primary-bg-color); - } - &.nb-badge-info { - background-color: nb-theme(badge-info-bg-color); - } - &.nb-badge-success { - background-color: nb-theme(badge-success-bg-color); - } - &.nb-badge-warning { - background-color: nb-theme(badge-warning-bg-color); - } - &.nb-badge-danger { - background-color: nb-theme(badge-danger-bg-color); + @each $status in nb-get-statuses() { + nb-badge.status-#{$status} { + color: nb-theme(badge-#{$status}-text-color); + background-color: nb-theme(badge-#{$status}-background-color); } } } diff --git a/src/framework/theme/components/badge/badge.component.scss b/src/framework/theme/components/badge/badge.component.scss index 3c87d928ed..eb46dc3910 100644 --- a/src/framework/theme/components/badge/badge.component.scss +++ b/src/framework/theme/components/badge/badge.component.scss @@ -4,19 +4,37 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ -:host .nb-badge { +@import '../../styles/core/mixins'; + +:host { position: absolute; - padding: 0.25em 0.4em; - font-size: 75%; - font-weight: 700; - line-height: 1; text-align: center; white-space: nowrap; vertical-align: baseline; - border-radius: 0.25rem; +} + +:host(.position-top) { + top: 0; +} + +:host(.position-right) { + right: 0; +} + +:host(.position-bottom) { + bottom: 0; +} + +:host(.position-left) { + left: 0; +} + +:host(.position-start) { + @include nb-ltr(left, 0); + @include nb-rtl(right, 0); +} - &.top { top: 0; } - &.right { right: 0; } - &.bottom { bottom: 0; } - &.left { left: 0; } +:host(.position-end) { + @include nb-ltr(right, 0); + @include nb-rtl(left, 0); } diff --git a/src/framework/theme/components/badge/badge.component.spec.ts b/src/framework/theme/components/badge/badge.component.spec.ts new file mode 100644 index 0000000000..02b24f2087 --- /dev/null +++ b/src/framework/theme/components/badge/badge.component.spec.ts @@ -0,0 +1,111 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { NbBadgeComponent, NbBadgeModule, NbBadgePosition, NbComponentStatus } from '@nebular/theme'; + +describe('NbBadgeComponent', () => { + let fixture: ComponentFixture; + let badgeComponent: NbBadgeComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ NbBadgeModule ], + }); + + fixture = TestBed.createComponent(NbBadgeComponent); + badgeComponent = fixture.componentInstance; + }); + + it(`should contain text set to 'text' input`, () => { + const text = 'random badge text'; + badgeComponent.text = text; + fixture.detectChanges(); + + expect(fixture.debugElement.nativeElement.textContent).toEqual(text); + }); + + it('should has primary status by default', () => { + expect(badgeComponent.status).toEqual('primary'); + }); + + it('should set status class', () => { + const statuses: NbComponentStatus[] = [ 'primary', 'success', 'info', 'warning', 'danger' ]; + + for (const status of statuses) { + badgeComponent.status = status; + fixture.detectChanges(); + + expect(fixture.debugElement.classes[`status-${status}`]).toEqual(true); + } + }); + + it(`should has 'top' class if position contains 'top'`, () => { + const topPositions: NbBadgePosition[] = [ 'top end', 'top left', 'top right', 'top start' ]; + + for (const position of topPositions) { + badgeComponent.position = position; + fixture.detectChanges(); + + expect(badgeComponent.top).toEqual(true); + expect(fixture.debugElement.classes['position-top']).toEqual(true); + } + }); + + it(`should has 'right' class if position contains 'right'`, () => { + const rightPositions: NbBadgePosition[] = [ 'top right', 'bottom right' ]; + + for (const position of rightPositions) { + badgeComponent.position = position; + fixture.detectChanges(); + + expect(badgeComponent.right).toEqual(true); + expect(fixture.debugElement.classes['position-right']).toEqual(true); + } + }); + + it(`should has 'bottom' class if position contains 'bottom'`, () => { + const bottomPositions: NbBadgePosition[] = [ 'bottom end', 'bottom left', 'bottom right', 'bottom start' ]; + + for (const position of bottomPositions) { + badgeComponent.position = position; + fixture.detectChanges(); + + expect(badgeComponent.bottom).toEqual(true); + expect(fixture.debugElement.classes['position-bottom']).toEqual(true); + } + }); + + it(`should has 'left' class if position contains 'left'`, () => { + const leftPositions: NbBadgePosition[] = [ 'top left', 'bottom left' ]; + + for (const position of leftPositions) { + badgeComponent.position = position; + fixture.detectChanges(); + + expect(badgeComponent.left).toEqual(true); + expect(fixture.debugElement.classes['position-left']).toEqual(true); + } + }); + + it(`should has 'start' class if position contains 'start'`, () => { + const startPositions: NbBadgePosition[] = [ 'top start', 'bottom start' ]; + + for (const position of startPositions) { + badgeComponent.position = position; + fixture.detectChanges(); + + expect(badgeComponent.start).toEqual(true); + expect(fixture.debugElement.classes['position-start']).toEqual(true); + } + }); + + it(`should has 'end' class if position contains 'end'`, () => { + const endPositions: NbBadgePosition[] = [ 'top end', 'bottom end' ]; + + for (const position of endPositions) { + badgeComponent.position = position; + fixture.detectChanges(); + + expect(badgeComponent.end).toEqual(true); + expect(fixture.debugElement.classes['position-end']).toEqual(true); + } + }); +}); diff --git a/src/framework/theme/components/badge/badge.component.ts b/src/framework/theme/components/badge/badge.component.ts index a527810b96..07781c2915 100644 --- a/src/framework/theme/components/badge/badge.component.ts +++ b/src/framework/theme/components/badge/badge.component.ts @@ -4,8 +4,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ -import { Component, Input } from '@angular/core'; -import { NbLayoutDirectionService } from '../../services/direction.service'; +import { Component, HostBinding, Input } from '@angular/core'; + +import { NbComponentStatus } from '../component-status'; + +export type NbBadgePhysicalPosition = 'top left' | 'top right' | 'bottom left' | 'bottom right'; +export type NbBadgeLogicalPosition = 'top start' | 'top end' | 'bottom start' | 'bottom end'; +export type NbBadgePosition = NbBadgePhysicalPosition | NbBadgeLogicalPosition; + /** * Badge is a simple labeling component. @@ -22,7 +28,7 @@ import { NbLayoutDirectionService } from '../../services/direction.service'; * ```ts * @NgModule({ * imports: [ - * // ... + * // ... * NbBadgeModule, * ], * }) @@ -48,38 +54,29 @@ import { NbLayoutDirectionService } from '../../services/direction.service'; * * @styles * - * badge-fg-text: - * badge-primary-bg-color: - * badge-success-bg-color: - * badge-info-bg-color: - * badge-warning-bg-color: - * badge-danger-bg-color: + * badge-border-radius: + * badge-text-font-family: + * badge-text-font-size: + * badge-text-font-weight: + * badge-text-line-height: + * badge-padding: + * badge-primary-background-color: + * badge-primary-text-color: + * badge-success-background-color: + * badge-success-text-color: + * badge-info-background-color: + * badge-info-text-color: + * badge-warning-background-color: + * badge-warning-text-color: + * badge-danger-background-color: + * badge-danger-text-color: */ @Component({ selector: 'nb-badge', styleUrls: ['./badge.component.scss'], - template: ` - {{text}} - `, + template: `{{text}}`, }) export class NbBadgeComponent { - static readonly TOP_LEFT = 'top left'; - static readonly TOP_RIGHT = 'top right'; - static readonly BOTTOM_LEFT = 'bottom left'; - static readonly BOTTOM_RIGHT = 'bottom right'; - - static readonly TOP_START = 'top start'; - static readonly TOP_END = 'top end'; - static readonly BOTTOM_START = 'bottom start'; - static readonly BOTTOM_END = 'bottom end'; - - static readonly STATUS_PRIMARY = 'primary'; - static readonly STATUS_INFO = 'info'; - static readonly STATUS_SUCCESS = 'success'; - static readonly STATUS_WARNING = 'warning'; - static readonly STATUS_DANGER = 'danger'; - - colorClass: string = NbBadgeComponent.STATUS_PRIMARY; /** * Text to display @@ -95,32 +92,74 @@ export class NbBadgeComponent { * 'top start', 'top end', 'bottom start', 'bottom end' * @type string */ - @Input() position: string; + @Input() + get position(): NbBadgePosition { + return this._position; + } + set position(value: NbBadgePosition) { + this._position = value || this._defaultPosition; + } + protected _defaultPosition: NbBadgePosition = 'top right'; + protected _position: NbBadgePosition = this._defaultPosition; /** * Badge status (adds specific styles): * 'primary', 'info', 'success', 'warning', 'danger' - * @param {string} val - * @type string */ - @Input() set status(value) { - if (value) { - this.colorClass = value; - } + @Input() status: NbComponentStatus = 'primary'; + + @HostBinding('class.status-primary') + get primary(): boolean { + return this.status === 'primary'; + } + + @HostBinding('class.status-success') + get success(): boolean { + return this.status === 'success'; + } + + @HostBinding('class.status-info') + get info(): boolean { + return this.status === 'info'; } - get positionClass() { - if (!this.position) { - return NbBadgeComponent.TOP_RIGHT; - } - - const isLtr = this.layoutDirectionService.isLtr(); - const startValue = isLtr ? 'left' : 'right'; - const endValue = isLtr ? 'right' : 'left'; - return this.position - .replace(/\bstart\b/, startValue) - .replace(/\bend\b/, endValue); + @HostBinding('class.status-warning') + get warning(): boolean { + return this.status === 'warning'; } - constructor(private layoutDirectionService: NbLayoutDirectionService) {} + @HostBinding('class.status-danger') + get danger(): boolean { + return this.status === 'danger'; + } + + @HostBinding('class.position-top') + get top(): boolean { + return this.position.includes('top'); + } + + @HostBinding('class.position-right') + get right(): boolean { + return this.position.includes('right'); + } + + @HostBinding('class.position-bottom') + get bottom(): boolean { + return this.position.includes('bottom'); + } + + @HostBinding('class.position-left') + get left(): boolean { + return this.position.includes('left'); + } + + @HostBinding('class.position-start') + get start(): boolean { + return this.position.includes('start'); + } + + @HostBinding('class.position-end') + get end(): boolean { + return this.position.includes('end'); + } } diff --git a/src/framework/theme/components/progress-bar/progress-bar.component.ts b/src/framework/theme/components/progress-bar/progress-bar.component.ts index b4e121efdc..fd6f077470 100644 --- a/src/framework/theme/components/progress-bar/progress-bar.component.ts +++ b/src/framework/theme/components/progress-bar/progress-bar.component.ts @@ -5,7 +5,9 @@ */ import { Component, HostBinding, Input } from '@angular/core'; -import { NbComponentSize, NbComponentStatus } from '@nebular/theme'; + +import { NbComponentSize } from '../component-size'; +import { NbComponentStatus } from '../component-status'; /** * Progress Bar is a component for indicating progress. diff --git a/src/framework/theme/components/tabset/tabset.component.ts b/src/framework/theme/components/tabset/tabset.component.ts index 8ee02ab812..b911928c79 100644 --- a/src/framework/theme/components/tabset/tabset.component.ts +++ b/src/framework/theme/components/tabset/tabset.component.ts @@ -19,6 +19,8 @@ import { import { ActivatedRoute } from '@angular/router'; import { convertToBoolProperty } from '../helpers'; +import { NbComponentStatus } from '../component-status'; +import { NbBadgePosition } from '../badge/badge.component'; /** * Specific tab container. @@ -123,7 +125,7 @@ export class NbTabComponent { * 'primary', 'info', 'success', 'warning', 'danger' * @param {string} val */ - @Input() badgeStatus: string; + @Input() badgeStatus: NbComponentStatus; /** * Badge position. @@ -132,7 +134,7 @@ export class NbTabComponent { * 'top start', 'top end', 'bottom start', 'bottom end' * @type string */ - @Input() badgePosition: string; + @Input() badgePosition: NbBadgePosition; init: boolean = false; } diff --git a/src/framework/theme/components/user/user.component.ts b/src/framework/theme/components/user/user.component.ts index f3e51cf156..7eb35b3c09 100644 --- a/src/framework/theme/components/user/user.component.ts +++ b/src/framework/theme/components/user/user.component.ts @@ -6,10 +6,12 @@ import { Component, HostBinding, Input } from '@angular/core'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; -import { NbComponentShape } from '@nebular/theme'; import { convertToBoolProperty } from '../helpers'; import { NbComponentSize } from '../component-size'; +import { NbComponentShape } from '../component-shape'; +import { NbComponentStatus } from '../component-status'; +import { NbBadgePosition } from '../badge/badge.component'; /** * Represents a component showing a user avatar (picture) with a user name on the right. @@ -215,7 +217,7 @@ export class NbUserComponent { * `primary`, `info`, `success`, `warning`, `danger` * @param {string} val */ - @Input() badgeStatus: string; + @Input() badgeStatus: NbComponentStatus; /** * Badge position. @@ -224,7 +226,7 @@ export class NbUserComponent { * 'top start', 'top end', 'bottom start', 'bottom end' * @type string */ - @Input() badgePosition: string; + @Input() badgePosition: NbBadgePosition; @HostBinding('class.size-tiny') get tiny(): boolean { diff --git a/src/framework/theme/styles/themes/_default.scss b/src/framework/theme/styles/themes/_default.scss index 972c0a5e9d..b1d95735de 100644 --- a/src/framework/theme/styles/themes/_default.scss +++ b/src/framework/theme/styles/themes/_default.scss @@ -1114,12 +1114,23 @@ $theme: ( modal-body-font-size: font-size, modal-separator: separator, - badge-fg-text: color-white, - badge-primary-bg-color: color-primary, - badge-success-bg-color: color-success, - badge-info-bg-color: color-info, - badge-warning-bg-color: color-warning, - badge-danger-bg-color: color-danger, + badge-border-radius: 0.75rem, + badge-text-font-family: text-button-font-family, + badge-text-font-size: text-button-tiny-font-size, + badge-text-font-weight: text-button-font-weight, + badge-text-line-height: text-button-tiny-line-height, + badge-padding: 0.25rem 0.4rem, + + badge-primary-background-color: color-primary, + badge-primary-text-color: text-light-color, + badge-success-background-color: color-success, + badge-success-text-color: text-light-color, + badge-info-background-color: color-info, + badge-info-text-color: text-light-color, + badge-warning-background-color: color-warning, + badge-warning-text-color: text-light-color, + badge-danger-background-color: color-danger, + badge-danger-text-color: text-light-color, progress-bar-animation-duration: 400ms, progress-bar-border-radius: radius, diff --git a/src/playground/with-layout/action/action-test.component.ts b/src/playground/with-layout/action/action-test.component.ts index 1812d60011..f43e11022b 100644 --- a/src/playground/with-layout/action/action-test.component.ts +++ b/src/playground/with-layout/action/action-test.component.ts @@ -5,7 +5,6 @@ */ import { Component } from '@angular/core'; -import { NbBadgeComponent } from '@nebular/theme'; @Component({ selector: 'nb-action-test', @@ -87,38 +86,38 @@ import { NbBadgeComponent } from '@nebular/theme'; + badgeStatus="success" + badgePosition="bottom left"> @@ -132,8 +131,6 @@ import { NbBadgeComponent } from '@nebular/theme'; }) export class ActionTestComponent { - badge = NbBadgeComponent; - actionOnClick(event: any) { console.info(event); } diff --git a/src/playground/with-layout/tabset/tabset-test.component.ts b/src/playground/with-layout/tabset/tabset-test.component.ts index 874c410ba9..c9fb3518c6 100644 --- a/src/playground/with-layout/tabset/tabset-test.component.ts +++ b/src/playground/with-layout/tabset/tabset-test.component.ts @@ -6,7 +6,6 @@ import { Component } from '@angular/core'; import { Router } from '@angular/router'; -import { NbBadgeComponent } from '@nebular/theme'; @Component({ selector: 'nb-tabset-test', @@ -79,26 +78,26 @@ import { NbBadgeComponent } from '@nebular/theme'; + badgeStatus="info" + badgePosition="top left"> Content #2 + badgeStatus="success" + badgePosition="bottom right"> Content #3 + badgeStatus="danger" + badgePosition="bottom left"> Content #4 + badgeStatus="warning" + badgePosition="bottom right"> Content #5 @@ -108,26 +107,26 @@ import { NbBadgeComponent } from '@nebular/theme'; + badgeStatus="info" + badgePosition="bottom right"> Content #2 + badgeStatus="success" + badgePosition="top left"> Content #3 + badgeStatus="danger" + badgePosition="bottom left"> Content #4 + badgeStatus="warning" + badgePosition="bottom right"> Content #5 @@ -149,8 +148,6 @@ import { NbBadgeComponent } from '@nebular/theme'; }) export class TabsetTestComponent { - badge = NbBadgeComponent; - constructor(private router: Router) { } diff --git a/src/playground/without-layout/user/user-test.component.ts b/src/playground/without-layout/user/user-test.component.ts index c3a611172c..89fa283be9 100644 --- a/src/playground/without-layout/user/user-test.component.ts +++ b/src/playground/without-layout/user/user-test.component.ts @@ -5,7 +5,6 @@ */ import { Component } from '@angular/core'; -import { NbBadgeComponent } from '@nebular/theme'; @Component({ selector: 'nb-user-test', @@ -64,8 +63,8 @@ import { NbBadgeComponent } from '@nebular/theme'; name="Dmitry Nehaychik" title="Worker" badgeText="29" - [badgeStatus]="badge.STATUS_INFO" - [badgePosition]="badge.TOP_LEFT"> + badgeStatus="info" + badgePosition="top left">
@@ -75,8 +74,8 @@ import { NbBadgeComponent } from '@nebular/theme'; title="Worker" showTitle="false" badgeText="29" - [badgeStatus]="badge.STATUS_SUCCESS" - [badgePosition]="badge.BOTTOM_RIGHT"> + badgeStatus="success" + badgePosition="bottom right">
@@ -86,8 +85,8 @@ import { NbBadgeComponent } from '@nebular/theme'; name="Dmitry Nehaychik" title="Worker" badgeText="29" - [badgeStatus]="badge.STATUS_WARNING" - [badgePosition]="badge.BOTTOM_LEFT"> + badgeStatus="warning" + badgePosition="bottom left">
@@ -97,8 +96,8 @@ import { NbBadgeComponent } from '@nebular/theme'; name="Dmitry Nehaychik" title="Worker" badgeText="29" - [badgeStatus]="badge.STATUS_DANGER" - [badgePosition]="badge.TOP_LEFT"> + badgeStatus="danger" + badgePosition="top left">
@@ -106,14 +105,14 @@ import { NbBadgeComponent } from '@nebular/theme'; [picture]="'data:image/png;base64,aaa'">
- + badgeStatus="danger" + badgePosition="top start">
@@ -121,6 +120,4 @@ import { NbBadgeComponent } from '@nebular/theme'; `, }) export class UserTestComponent { - - badge = NbBadgeComponent; }