Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(business/checkbox): expose checkbox component for business #51

Merged
merged 6 commits into from
Jun 28, 2019
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ describe('ButtonComponent', () => {
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 have a white text color with opacity', () => {
expect(sbbButtonStyle.getPropertyValue('color')).toBe('rgba(255, 255, 255, 0.5)');
});

it('should the icons be white', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { IconTickModule } from '@sbb-esta/angular-icons';

import { CheckboxComponent } from './checkbox/checkbox.component';

@NgModule({
imports: [CommonModule, IconTickModule],
declarations: [CheckboxComponent],
exports: [CheckboxComponent]
})
export class CheckboxModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './checkbox.module';

export * from './checkbox/checkbox.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<label [attr.for]="inputId">
<input
type="checkbox"
class="cdk-visually-hidden"
[id]="inputId"
[value]="value"
[required]="required"
[checked]="checked"
[indeterminate]="indeterminate"
[attr.aria-checked]="ariaChecked"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledby]="ariaLabelledby"
[attr.aria-describedby]="ariaDescribedby"
[disabled]="disabled"
(click)="click()"
/>

<div class="sbb-checkbox-container">
<sbb-icon-tick class="sbb-checkbox-checked"></sbb-icon-tick>
</div>

<div class="sbb-checkbox-label-content">
<!-- Add an invisible span so JAWS can read the label -->
<span style="display:none">&nbsp;</span>
<ng-content></ng-content>
</div>
</label>
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { IconCollectionModule } from '@sbb-esta/angular-icons';
import { configureTestSuite } from 'ng-bullet';

import { CheckboxComponent } from './checkbox.component';

// tslint:disable:i18n
@Component({
selector: 'sbb-model-checkbox-test',
template: `
<sbb-checkbox [(ngModel)]="checkValue1" inputId="test-check-1" value="1" #check1
>Test check 1</sbb-checkbox
>
`
})
class ModelCheckboxTestComponent {
checkValue1 = false;

@ViewChild('check1', { static: false })
checkboxComponent: CheckboxComponent;
}

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

configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [CommonModule, IconCollectionModule],
declarations: [CheckboxComponent]
}).overrideComponent(CheckboxComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
});
});

beforeEach(() => {
fixture = TestBed.createComponent(CheckboxComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

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

it('should have a generated id if not provided', () => {
expect(component.inputId).toContain('sbb-checkbox-');
});
});

describe('CheckboxComponent using mock component', () => {
let modelComponent: ModelCheckboxTestComponent;
let modelComponentFixture: ComponentFixture<ModelCheckboxTestComponent>;

configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [CommonModule, FormsModule, IconCollectionModule],
declarations: [CheckboxComponent, ModelCheckboxTestComponent]
}).overrideComponent(CheckboxComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
});
});

beforeEach(() => {
modelComponentFixture = TestBed.createComponent(ModelCheckboxTestComponent);
modelComponent = modelComponentFixture.componentInstance;

modelComponentFixture.detectChanges();
});

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

it('should not have class for indeterminate', () => {
const checkboxComponentIndeterminate = modelComponentFixture.debugElement.query(
By.css('.sbb-checkbox-indeterminate')
);
expect(checkboxComponentIndeterminate).not.toBeTruthy();
});

it('should have class for indeterminate if indeterminate', async () => {
modelComponent.checkboxComponent.indeterminate = true;

modelComponentFixture.detectChanges();
await modelComponentFixture.whenStable();

const checkboxComponentIndeterminate = modelComponentFixture.debugElement.query(
By.css('.sbb-checkbox-indeterminate')
);
expect(checkboxComponentIndeterminate).toBeTruthy();
});

it('should have class for indeterminate if indeterminate and checked', async () => {
modelComponent.checkboxComponent.checked = true;
modelComponent.checkboxComponent.indeterminate = true;

modelComponentFixture.detectChanges();
await modelComponentFixture.whenStable();

const checkboxComponentIndeterminate = modelComponentFixture.debugElement.query(
By.css('.sbb-checkbox-indeterminate')
);
expect(checkboxComponentIndeterminate).toBeTruthy();
});

it('should not show tick if indeterminate and checked', async () => {
modelComponent.checkboxComponent.checked = true;
modelComponent.checkboxComponent.indeterminate = true;

modelComponentFixture.detectChanges();
await modelComponentFixture.whenStable();

const checkboxChecked = modelComponentFixture.debugElement.query(
By.css('.sbb-checkbox-checked')
);
expect(getComputedStyle(checkboxChecked.nativeElement).getPropertyValue('display')).toBe(
'none'
);
});

it('should change from checked and indeterminate to checked on click', async () => {
modelComponent.checkboxComponent.checked = true;
modelComponent.checkboxComponent.indeterminate = true;

modelComponent.checkboxComponent.click();

modelComponentFixture.detectChanges();
await modelComponentFixture.whenStable();

const inputElement = modelComponentFixture.debugElement.query(By.css('input'))
.nativeElement as HTMLInputElement;
expect(modelComponent.checkboxComponent.indeterminate).toBe(false);
expect(inputElement.checked).toBe(true);
});

it('should change from unchecked and indeterminate to checked on click', async () => {
modelComponent.checkboxComponent.checked = false;
modelComponent.checkboxComponent.indeterminate = true;

modelComponent.checkboxComponent.click();

modelComponentFixture.detectChanges();
await modelComponentFixture.whenStable();

const inputElement = modelComponentFixture.debugElement.query(By.css('input'))
.nativeElement as HTMLInputElement;
expect(modelComponent.checkboxComponent.indeterminate).toBe(false);
expect(inputElement.checked).toBe(true);
});

it('should change checked to unchecked on click', async () => {
modelComponent.checkboxComponent.checked = true;

modelComponent.checkboxComponent.click();

modelComponentFixture.detectChanges();
await modelComponentFixture.whenStable();

const inputElement = modelComponentFixture.debugElement.query(By.css('input'))
.nativeElement as HTMLInputElement;
expect(inputElement.checked).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
forwardRef,
HostBinding,
Input,
ViewEncapsulation
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

import { BaseCheckbox } from '../../../../../angular-public/src/lib/checkbox/checkbox/base-checkbox';

@Component({
selector: 'sbb-checkbox',
templateUrl: './checkbox.component.html',
styleUrls: ['../../../../../angular-public/src/lib/checkbox/checkbox/checkbox.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxComponent),
multi: true
}
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CheckboxComponent extends BaseCheckbox {
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector);
}

/**
* The indeterminate state of the checkbox
*/
@Input()
@HostBinding('class.sbb-checkbox-indeterminate')
get indeterminate(): any {
return this._indeterminate;
}
set indeterminate(value: any) {
this._indeterminate = value;
this._changeDetector.markForCheck();
}
private _indeterminate = false;

/** @inheritDoc */
click() {
if (this.indeterminate && this.checked) {
this.indeterminate = false;
return false; // prevent default
} else {
this.indeterminate = false;
super.click();
}
}

/** @docs-private */
get ariaChecked(): String {
return this.checked ? 'true' : this.indeterminate ? 'mixed' : 'false';
}
}
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 @@ -3,6 +3,7 @@
*/
export * from './lib/autocomplete/autocomplete';
export * from './lib/button/button';
export * from './lib/checkbox/checkbox';
export * from './lib/datepicker/datepicker';
export * from './lib/field/field';
export * from './lib/radio-button/radio-button';
Expand Down
49 changes: 45 additions & 4 deletions projects/sbb-esta/angular-public/src/lib/checkbox/_checkbox.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
@import 'common';

$checkBoxGreyColor: $sbbColorGrey;
$checkBoxContainerBorder: 2;

@if $sbbBusiness {
$checkBoxGreyColor: $sbbColorGranite;
$checkBoxContainerBorder: 1;
}


@mixin checkbox() {
& > label {
@include checkboxBase();
}

@include businessOnly() {
&.sbb-checkbox-indeterminate > label > input[type='checkbox'] {
& + .sbb-checkbox-container {
&::before {
content: '';
position: relative;
height: 1px;
width: 10px;
left: 4px;
top: 8.5px;
border: 1px solid $sbbColorGranite;
display: block;
}

& + .sbb-checkbox-label-content {
color: $sbbColorBlack;
}
}

&:checked + .sbb-checkbox-container,
&[checked] + .sbb-checkbox-container {
& > .sbb-checkbox-checked {
display: none;
}
}
}
}
}

@mixin checkboxBase {
Expand All @@ -19,13 +56,17 @@
}

& + .sbb-checkbox-label-content {
color: $sbbColorGrey;
@include businessOnly() {
line-height: toEm(21 / $sizeFontDefault);
}

color: $checkBoxGreyColor;
transition: color 0.3s cubic-bezier(0.785, 0.135, 0.15, 0.86);
}
}

&:focus + .sbb-checkbox-container {
border-color: $sbbColorGrey;
border-color: $checkBoxGreyColor;
}

&:checked + .sbb-checkbox-container,
Expand All @@ -49,7 +90,7 @@
}

& + .sbb-checkbox-label-content {
color: $sbbColorGrey;
color: $checkBoxGreyColor;
}
}
}
Expand All @@ -59,7 +100,7 @@
width: toPx(20);
height: toPx(20);
background-color: $sbbColorWhite;
border: toPx(2) solid $sbbColorGraphite;
border: toPx($checkBoxContainerBorder) solid $sbbColorGraphite;
border-radius: toPx(2);
margin-right: toPx(8);
margin-top: toPx(1);
Expand Down
Loading