Skip to content

Commit

Permalink
feat(business/button): expose button component for business (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
efux authored and kyubisation committed Jun 21, 2019
1 parent 47b2da8 commit ed990a2
Show file tree
Hide file tree
Showing 18 changed files with 461 additions and 112 deletions.
4 changes: 2 additions & 2 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@
"karmaConfig": "projects/sbb-esta/angular-business/karma.conf.js",
"stylePreprocessorOptions": {
"includePaths": [
"projects/sbb-esta/angular-public/src/styles/common"
"projects/sbb-esta/angular-business/src/styles/common"
]
}
},
Expand Down Expand Up @@ -310,4 +310,4 @@
}
},
"defaultProject": "angular-showcase"
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"lint:angular-public:report": "ng lint @sbb-esta/angular-icons --format=json > lintReport.json",
"lint:angular-showcase": "ng lint angular-showcase",
"build": "run-s build:libs build:angular-showcase",
"build:libs": "run-s build:angular-icons build:angular-public",
"build:libs": "run-s build:angular-icons build:angular-public build:angular-business",
"build:angular-icons": "run-s build:angular-icons:*",
"build:angular-icons:ng": "ng build @sbb-esta/angular-icons",
"build:angular-icons:license": "copyfiles LICENSE ./dist/sbb-esta/angular-icons/",
Expand Down
13 changes: 13 additions & 0 deletions projects/sbb-esta/angular-business/src/lib/button/button.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';

import { ButtonIconDirective } from '../../../../angular-public/src/lib/button/button/button-icon.directive';
import { ButtonComponent } from './button/button.component';

@NgModule({
imports: [CommonModule],
declarations: [ButtonComponent, ButtonIconDirective],
exports: [ButtonComponent, ButtonIconDirective],
entryComponents: []
})
export class ButtonModule {}
3 changes: 3 additions & 0 deletions projects/sbb-esta/angular-business/src/lib/button/button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './button.module';

export * from './button/button.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@import '../styles/button';

@mixin businessButtonTypes {
&.sbb-button {
// button types for both themes: primary, secondary, ghost
@include buttonTypes;

// Alternative primary button with icon
&-alternative.sbb-button-has-icon {
@include alternativePrimaryIconButton;
}

// Alternative primary button NO icon
&-alternative:not(.sbb-button-has-icon) {
@include alternativePrimaryButton;
}

&-icon {
@include iconButton;
}
}
}

.sbb-button {
// Kickstart basic button styles
@include buttons();
@include businessButtonTypes;

&:disabled {
opacity: 0.4;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { Component, DebugElement, Type, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {
IconArrowRightComponent as TestIconComponent,
IconCollectionModule
} from '@sbb-esta/angular-icons';
import { configureTestSuite } from 'ng-bullet';

import { ButtonIconDirective } from '../../../../../angular-public/src/lib/button/button/button-icon.directive';
import { ButtonComponent } from './button.component';

// tslint:disable:i18n
@Component({
selector: 'sbb-button-test',
template: `
<button sbbButton [icon]="icon" [mode]="mode" [disabled]="disabled" (click)="testClick()">
Bezeichnung
</button>
<ng-template #icon><sbb-icon-arrow-right></sbb-icon-arrow-right></ng-template>
`,
entryComponents: [TestIconComponent]
})
export class ButtonTemplateTestComponent {
mode: string;
disabled: boolean;

testClick() {}
}

describe('ButtonComponent', () => {
let component: ButtonTemplateTestComponent;
let fixture: ComponentFixture<ButtonTemplateTestComponent>;

configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [IconCollectionModule],
declarations: [ButtonComponent, ButtonTemplateTestComponent, ButtonIconDirective]
});
});

beforeEach(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
fixture = TestBed.createComponent(ButtonTemplateTestComponent);
component = fixture.componentInstance;
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should have two icons instantiated if the icon is being passed', () => {
fixture.detectChanges();

const icons = fixture.debugElement.queryAll(By.css('sbb-icon-arrow-right'));

expect(icons).toBeTruthy();
expect(icons.length).toBe(2);
});

describe('Alternative Primary Button', () => {
let sbbButton: DebugElement;
let sbbButtonStyle: CSSStyleDeclaration;
let sbbButtonIcon: DebugElement;
let sbbButtonIconStyle: CSSStyleDeclaration;

beforeEach(() => {
component.mode = 'alternative';

fixture.detectChanges();

sbbButton = fixture.debugElement.query(By.css('button.sbb-button'));
sbbButtonStyle = getComputedStyle(sbbButton.nativeElement);
sbbButtonIcon = fixture.debugElement.query(By.css('sbb-icon-arrow-right svg'));
sbbButtonIconStyle = getComputedStyle(sbbButtonIcon.nativeElement);
});

it('should have a grey background color of rgb(104, 104, 104)/#686868', () => {
expect(sbbButtonStyle.getPropertyValue('background-color')).toBe('rgb(104, 104, 104)');
});

it('should have a white text color', () => {
expect(sbbButtonStyle.getPropertyValue('color')).toBe('rgb(255, 255, 255)');
});

it('should the icons be white', () => {
expect(sbbButtonIconStyle.getPropertyValue('fill')).toBe('rgb(255, 255, 255)');
});
});

describe('Icon Button', () => {
let sbbButton: DebugElement;
let sbbButtonStyle: CSSStyleDeclaration;
let sbbButtonIcon: DebugElement;
let sbbButtonIconStyle: CSSStyleDeclaration;

beforeEach(() => {
component.mode = 'icon';

fixture.detectChanges();

sbbButton = fixture.debugElement.query(By.css('button[sbbButton]'));
sbbButtonStyle = getComputedStyle(sbbButton.nativeElement);
sbbButtonIcon = fixture.debugElement.query(By.css('sbb-icon-arrow-right svg'));
sbbButtonIconStyle = getComputedStyle(sbbButtonIcon.nativeElement);
});

it('should have a grey background color of rgb(220, 220, 220)/#DCDCDC', () => {
expect(sbbButtonStyle.getPropertyValue('background-color')).toBe('rgb(220, 220, 220)');
});

it('should the icons be grey of rgb(68, 68, 68)/#444444', () => {
expect(sbbButtonIconStyle.getPropertyValue('fill')).toBe('rgb(68, 68, 68)');
});
});

describe('Disabled Primary Button', () => {
let sbbButton: DebugElement;
let sbbButtonStyle: CSSStyleDeclaration;
let sbbButtonIcon: DebugElement;
let sbbButtonIconStyle: CSSStyleDeclaration;

beforeEach(() => {
component.mode = 'primary';
component.disabled = true;

fixture.detectChanges();

sbbButton = fixture.debugElement.query(By.css('button.sbb-button'));
sbbButtonStyle = getComputedStyle(sbbButton.nativeElement);
sbbButtonIcon = fixture.debugElement.query(By.css('sbb-icon-arrow-right svg'));
sbbButtonIconStyle = getComputedStyle(sbbButtonIcon.nativeElement);
});

it('should have a red background color of rgb(235, 0, 0)/#EB0000', () => {
expect(sbbButtonStyle.getPropertyValue('background-color')).toBe('rgb(235, 0, 0)');
});

it('should have a white text color', () => {
expect(sbbButtonStyle.getPropertyValue('color')).toBe('rgb(255, 255, 255)');
});

it('should the icons be white', () => {
expect(sbbButtonIconStyle.getPropertyValue('fill')).toBe('rgb(255, 255, 255)');
});

it('should have opacity 0.4', () => {
expect(sbbButtonStyle.getPropertyValue('opacity')).toBe('0.4');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
ChangeDetectionStrategy,
Component,
HostBinding,
Input,
ViewEncapsulation
} from '@angular/core';
import { BaseButton } from '../../../../../angular-public/src/lib/button/button/base-button';

@Component({
// tslint:disable-next-line:component-selector
selector: 'button[sbbButton], input[type=submit][sbbButton]',
templateUrl: '../../../../../angular-public/src/lib/button/button/button.component.html',
styleUrls: ['./button.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class ButtonComponent extends BaseButton {
/**
* Button modes available for different purposes.
*/
@Input() mode: 'primary' | 'secondary' | 'ghost' | 'alternative' | 'icon' = 'primary';

/** @docs-private */
@HostBinding('class.sbb-button-alternative')
get _alternativeClass() {
return this.mode === 'alternative';
}

/** @docs-private */
@HostBinding('class.sbb-button-icon')
get _iconClass() {
return this.mode === 'icon';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@import 'common';

/*** ALTERNATIVE PRIMARY BUTTON ***/
@mixin alternativePrimaryButton {
color: $buttonDefaultColor;
border: none;
background-color: $buttonAlternativeBgColor;

&:not(:disabled) {
&:hover,
&:focus {
background-color: $buttonAlternativeBgColorHover;
border: none;
color: $buttonAlternativeColor;

.sbb-svgsprite-icon {
@include svgIconColor($buttonAlternativeColor);
}
}
}
}

/***
* ALTERNATIVE PRIMARY BUTTON PLACEHOLDER
* - Include primary mixin in order to allow extension
* in order to get a more compact compiled css
***/
%alternativePrimaryButton {
@include alternativePrimaryButton();
}

/*** ALTERNATIVE PRIMARY BUTTON WITH ICON ***/
@mixin alternativePrimaryIconButton {
@extend %alternativePrimaryButton;
@extend %arrowbuttons;
}

/*** ICON BUTTON ***/
@mixin iconButton {
@extend %secondaryIconButton;
min-width: 36px;
width: 36px;

padding-left: pxToEm(36, $buttonSizeFontDefault);
padding-right: 0;

.sbb-svgsprite-icon:first-of-type {
opacity: 1;
margin-left: pxToEm(-4, $buttonSizeFontDefault);
}

.sbb-svgsprite-icon:last-of-type {
opacity: 0;
}
}

%iconButton {
@include iconButton;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import '../../../../../angular-public/src/lib/button/styles/button';
@import './button-themes';
1 change: 1 addition & 0 deletions projects/sbb-esta/angular-business/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './lib/field/field';
export * from './lib/radio-button/radio-button';
export * from './lib/time-input/time-input';
export * from './lib/textarea/textarea';
export * from './lib/button/button';
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
ContentChild,
HostBinding,
Input,
TemplateRef
} from '@angular/core';
import { ButtonIconDirective } from './button-icon.directive';

export abstract class BaseButton {
/**
* Button modes available for different purposes.
*/
abstract mode: string;

/**
* Template that will contain icons.
* Use the *sbbButtonIcon structural directive to provide the desired icon.
*/
@Input()
get icon(): TemplateRef<any> {
return this._contentIcon || this._icon;
}
set icon(icon: TemplateRef<any>) {
this._icon = icon;
}
private _icon: TemplateRef<any>;

/** @docs-private */
@HostBinding('class.sbb-button') buttonClass = true;

/** @docs-private */
@HostBinding('class.sbb-button-has-icon') get buttonHasIconClass() {
return !!this.icon;
}

/** @docs-private */
@ContentChild(ButtonIconDirective, { read: TemplateRef, static: false })
_contentIcon: TemplateRef<any>;

/** @docs-private */
@HostBinding('class.sbb-button-primary')
get _primaryClass() {
return this.mode === 'primary';
}

/** @docs-private */
@HostBinding('class.sbb-button-secondary')
get _secondaryClass() {
return this.mode === 'secondary';
}

/** @docs-private */
@HostBinding('class.sbb-button-ghost')
get _ghostClass() {
return this.mode === 'ghost';
}
}
Loading

0 comments on commit ed990a2

Please sign in to comment.