Skip to content

Commit

Permalink
feat(progress-spinner): added component progress-spinner (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilfant authored and pimenovoleg committed Jul 20, 2018
1 parent c9fcdcf commit ee127e7
Show file tree
Hide file tree
Showing 17 changed files with 498 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
"server-dev:button": "npm run server-dev -- --env.component button",
"server-dev:list": "npm run server-dev -- --env.component list",
"server-dev:progress-bar": "npm run server-dev -- --env.component progress-bar",
"server-dev:progress-spinner": "npm run server-dev -- --env.component progress-spinner",
"server-dev:radio": "npm run server-dev -- --env.component radio",
"server-dev:icon": "npm run server-dev -- --env.component icon",
"server-dev:theme-picker": "npm run server-dev -- --env.component theme-picker",
Expand Down
56 changes: 56 additions & 0 deletions src/lib-dev/progress-spinner/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { CommonModule } from '@angular/common';
import { Component, ViewEncapsulation, NgModule, OnDestroy } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { McProgressSpinnerModule } from '../../lib/progress-spinner/';


const INTERVAL: number = 300;
const STEP: number = 4;
const MAX_PERCENT: number = 100;

@Component({
selector: 'app',
template: require('./template.html'),
encapsulation: ViewEncapsulation.None,
styleUrls: ['./styles.scss']
})
export class ProgressSpinnerDemoComponent implements OnDestroy {
mode: string = 'determinate';
percent: number = 0;
intervalId: number;

constructor() {
setInterval(() => {
this.percent = (this.percent + STEP) % (MAX_PERCENT + STEP);
}, INTERVAL);
}

ngOnDestroy() {
clearInterval(this.intervalId);
}
}


@NgModule({
declarations: [
ProgressSpinnerDemoComponent
],
imports: [
CommonModule,
BrowserModule,
McProgressSpinnerModule,
FormsModule
],
bootstrap: [
ProgressSpinnerDemoComponent
]
})
export class ProgressSpinnerDemoModule {}

platformBrowserDynamic()
.bootstrapModule(ProgressSpinnerDemoModule);

39 changes: 39 additions & 0 deletions src/lib-dev/progress-spinner/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@import '../../lib/core/theming/prebuilt/default-theme';

.container {
display: flex;
align-items: center;

.percent {
margin-right: 8px;
width: 60px;
text-align: center;
flex-shrink: 0;
}

.spinners {
display: flex;
flex-grow: 1;
margin-top: 8px;
list-style: none;
padding: 0px;
}

.spinner-container {
margin-left: 16px;
}

.line-container:not(:first-child) {
margin-top: 16px;
}

.big-spinner {
width: 50px;
height: 50px;
}

.huge-spinner {
width: 100px;
height: 100px;
}
}
52 changes: 52 additions & 0 deletions src/lib-dev/progress-spinner/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<h1>Progress Spinner</h1>
<div>
Mode:
<select [(ngModel)]="mode">
<option [ngValue]="'determinate'">Determinate</option>
<option [ngValue]="'indeterminate'">Indeterminate</option>
</select>
</div>
<div class="container">
<div class="percent">{{ mode === 'indeterminate' ? '--' : percent }}%</div>
<div class="spinners-container">
<ul class="spinners">
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="primary"></mc-progress-spinner>
</li>
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="second"></mc-progress-spinner>
</li>
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="warn"></mc-progress-spinner>
</li>
</ul>
<ul class="spinners">
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="primary" class="big-spinner"></mc-progress-spinner>
</li>
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="second" class="big-spinner"></mc-progress-spinner>
</li>
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="warn" class="big-spinner"></mc-progress-spinner>
</li>
</ul>
<ul class="spinners">
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="primary" class="huge-spinner"></mc-progress-spinner>
</li>
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="second" class="huge-spinner"></mc-progress-spinner>
</li>
<li class="spinner-container">
<mc-progress-spinner [value]="percent" [mode]="mode" color="warn" class="huge-spinner"></mc-progress-spinner>
</li>
</ul>
</div>
</div>
<div class="container">
<span class="percent">100%</span> <mc-progress-spinner [value]="100" class="huge-spinner"></mc-progress-spinner>
</div>
<div class="container">
<span class="percent">0%</span> <mc-progress-spinner [value]="0" class="huge-spinner"></mc-progress-spinner>
</div>
2 changes: 2 additions & 0 deletions src/lib/core/theming/_all-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
@import '../../button/button-theme';
@import '../../list/list-theme';
@import '../../progress-bar/progress-bar-theme';
@import '../../progress-spinner/progress-spinner-theme';
@import '../../radio/radio-theme';
@import '../../checkbox/checkbox-theme';
@import '../../navbar/navbar-theme';
Expand All @@ -15,6 +16,7 @@
@include mc-button-theme($theme);
@include mc-list-theme($theme);
@include mc-progress-bar-theme($theme);
@include mc-progress-spinner-theme($theme);
@include mc-radio-theme($theme);
@include mc-checkbox-theme($theme);
@include mc-navbar-theme($theme);
Expand Down
Empty file.
22 changes: 22 additions & 0 deletions src/lib/progress-spinner/_progress-spinner-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@import '../core/theming/theming';
@import '../core/theming/palette';

@mixin mc-progress-spinner-theme($theme) {
$primary: map-get($theme, primary);
$second: map-get($theme, second);
$warn: map-get($theme, warn);

.mc-progress-spinner {
&.mc-primary &__circle {
stroke: mc-color($primary, 500);
}

&.mc-second &__circle {
stroke: mc-color($second, 500);
}

&.mc-warn &__circle {
stroke: mc-color($warn, 500);
}
}
}
1 change: 1 addition & 0 deletions src/lib/progress-spinner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public-api';
19 changes: 19 additions & 0 deletions src/lib/progress-spinner/progress-spinner.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<svg focusable="false"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 100 100"
class="mc-progress-spinner__inner"
[ngSwitch]="mode">
<circle *ngSwitchCase="'indeterminate'"
cx="50%"
cy="50%"
r="43.5%"
class="mc-progress-spinner__circle mc-progress-spinner__circle--indeterminate">
</circle>
<circle *ngSwitchDefault
cx="50%"
cy="50%"
r="43.5%"
class="mc-progress-spinner__circle"
[ngStyle]="{'stroke-dashoffset': dashOffsetPercent}">
</circle>
</svg>
134 changes: 134 additions & 0 deletions src/lib/progress-spinner/progress-spinner.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { Component } from '@angular/core';
import { fakeAsync, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { ThemePalette } from '@ptsecurity/mosaic/core';

import { McProgressSpinnerModule } from './index';


// tslint:disable no-magic-numbers
const percentPairs = [
[40, 0.4],
[-50, 0],
[140, 1]
];
// tslint:enable no-magic-numbers

describe('McProgressSpinner', () => {
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
imports: [McProgressSpinnerModule],
declarations: [TestApp]
});

TestBed.compileComponents();
}));

it('should apply class based on color attribute', () => {
const fixture = TestBed.createComponent(TestApp);
const testComponent = fixture.debugElement.componentInstance;
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.first'));

Object.keys(ThemePalette).forEach((key) => {
testComponent.color = ThemePalette[key];
fixture.detectChanges();
expect(progressSpinnerDebugElement.nativeElement.classList.contains(`mc-${ThemePalette[key]}`)).toBe(true);
});
});

it('should has default primary color', () => {
const fixture = TestBed.createComponent(TestApp);
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.default'));

expect(progressSpinnerDebugElement.nativeElement.classList.contains(`mc-${ThemePalette.Primary}`)).toBe(true);
});

it('should return percentage', () => {
const fixture = TestBed.createComponent(TestApp);

const testComponent = fixture.debugElement.componentInstance;
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.first'));

percentPairs.forEach(([percent, expected]) => {
testComponent.value = percent;
fixture.detectChanges();
expect(progressSpinnerDebugElement.componentInstance.percentage).toBe(expected);
});
});

it('should return 0 percentage by default', () => {
const fixture = TestBed.createComponent(TestApp);
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.default'));

expect(progressSpinnerDebugElement.componentInstance.percentage).toBe(0);
});

it('should show determinate circle', () => {
const fixture = TestBed.createComponent(TestApp);
const testComponent = fixture.debugElement.componentInstance;
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.first'));
testComponent.mode = 'determinate';
fixture.detectChanges();

expect(progressSpinnerDebugElement.query(By.css('.mc-progress-spinner__circle--indeterminate'))).toBeNull();
expect(progressSpinnerDebugElement.query(By.css('.mc-progress-spinner__circle'))).not.toBeNull();
});

it('should show indeterminate circle', () => {
const fixture = TestBed.createComponent(TestApp);
const testComponent = fixture.debugElement.componentInstance;
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.first'));
testComponent.mode = 'indeterminate';
fixture.detectChanges();

expect(progressSpinnerDebugElement.query(By.css('.mc-progress-spinner__circle--indeterminate'))).not.toBeNull();
});

it('should show determinate circle by default', () => {
const fixture = TestBed.createComponent(TestApp);
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.first'));
fixture.detectChanges();

expect(progressSpinnerDebugElement.query(By.css('.mc-progress-spinner__circle--indeterminate'))).toBeNull();
expect(progressSpinnerDebugElement.query(By.css('.mc-progress-spinner__circle'))).not.toBeNull();
});

it('should set id attribute', () => {
const fixture = TestBed.createComponent(TestApp);
const testComponent = fixture.debugElement.componentInstance;
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.first'));
testComponent.id = 'foo';
fixture.detectChanges();

expect(progressSpinnerDebugElement.nativeElement.getAttribute('id')).toBe('foo');
});

it('should auto generate id', () => {
const fixture = TestBed.createComponent(TestApp);
const progressSpinnerDebugElement = fixture.debugElement.query(By.css('.default'));

expect(progressSpinnerDebugElement.nativeElement.getAttribute('id')).toBeDefined();
});
});


@Component({
selector: 'test-app',
template: `
<mc-progress-spinner
class="first"
[id]="id"
[color]="color"
[value]="value"
[mode]="mode">
</mc-progress-spinner>
<mc-progress-spinner class="default"></mc-progress-spinner>
`
})
class TestApp {
color: ThemePalette;
value: number = 0;
mode: string;
id: string;
}
Loading

0 comments on commit ee127e7

Please sign in to comment.