Skip to content

Commit

Permalink
feat(progress-bar): added component progress-bar (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilfant authored and pimenovoleg committed Jul 11, 2018
1 parent 28a7ba6 commit 523cbc7
Show file tree
Hide file tree
Showing 18 changed files with 441 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
"server-dev": "webpack-dev-server --config tools/webpack/webpack.lib.dev.js",
"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: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-bar/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 { McProgressBarModule } from '../../lib/progress-bar/';


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 ProgressBarDemoComponent 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: [
ProgressBarDemoComponent
],
imports: [
CommonModule,
BrowserModule,
McProgressBarModule,
FormsModule
],
bootstrap: [
ProgressBarDemoComponent
]
})
export class ProgressBarDemoModule {}

platformBrowserDynamic()
.bootstrapModule(ProgressBarDemoModule);

22 changes: 22 additions & 0 deletions src/lib-dev/progress-bar/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@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;
}

.lines {
flex-grow: 1;
margin-top: 8px;
}

.line-container:not(:first-child) {
margin-top: 16px;
}
}
25 changes: 25 additions & 0 deletions src/lib-dev/progress-bar/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<h1>Progress bar</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="lines">
<div class="line-container">
<mc-progress-bar [value]="percent" [mode]="mode"></mc-progress-bar>
</div>
<div class="line-container">
<mc-progress-bar [value]="percent" [mode]="mode" color="primary"></mc-progress-bar>
</div>
<div class="line-container">
<mc-progress-bar [value]="percent" [mode]="mode" color="second"></mc-progress-bar>
</div>
<div class="line-container">
<mc-progress-bar [value]="percent" [mode]="mode" color="warn"></mc-progress-bar>
</div>
</div>
</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 @@ -3,6 +3,7 @@
@import '../styles/badges';
@import '../../button/button-theme';
@import '../../list/list-theme';
@import '../../progress-bar/progress-bar-theme';
@import '../../radio/radio-theme';
@import '../../checkbox/checkbox-theme';
@import '../../navbar/navbar-theme';
Expand All @@ -13,6 +14,7 @@
@include mc-badge-theme($theme);
@include mc-button-theme($theme);
@include mc-list-theme($theme);
@include mc-progress-bar-theme($theme);
@include mc-radio-theme($theme);
@include mc-checkbox-theme($theme);
@include mc-navbar-theme($theme);
Expand Down
Empty file added src/lib/progress-bar/README.md
Empty file.
24 changes: 24 additions & 0 deletions src/lib/progress-bar/_progress-bar-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@import '../core/theming/theming';
@import '../core/theming/palette';

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

.mc-progress-bar {
background-color: mc-color($mc-grey, 60);

&.mc-primary &__line {
background-color: mc-color($primary, 500);
}

&.mc-second &__line {
background-color: mc-color($second, 500);
}

&.mc-warn &__line {
background-color: mc-color($warn, 500);
}
}
}
1 change: 1 addition & 0 deletions src/lib/progress-bar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public-api';
12 changes: 12 additions & 0 deletions src/lib/progress-bar/progress-bar.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

<div class="mc-progress-bar__inner" [ngSwitch]="mode" [id]="id">
<div
*ngSwitchCase="'indeterminate'"
class="mc-progress-bar__line mc-progress-bar__line--indeterminate">
</div>
<div
*ngSwitchDefault
class="mc-progress-bar__line mc-progress-bar__line--determinate"
[ngStyle]="{transform: 'scaleX(' + percentage + ')'}">
</div>
</div>
131 changes: 131 additions & 0 deletions src/lib/progress-bar/progress-bar.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
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 { McProgressBarModule } from './index';


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

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

TestBed.compileComponents();
}));

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

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

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

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

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

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

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

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

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

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

expect(progressBarDebugElement.query(By.css('.mc-progress-bar__line--determinate'))).toBeDefined();
});

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

expect(progressBarDebugElement.query(By.css('.mc-progress-bar__line--indeterminate'))).toBeDefined();
});

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

expect(progressBarDebugElement.query(By.css('.mc-progress-bar__line--determinate'))).toBeDefined();
});

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

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

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

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


@Component({
selector: 'test-app',
template: `
<mc-progress-bar
class="first"
[id]="id"
[color]="color"
[value]="value"
[mode]="mode">
</mc-progress-bar>
<mc-progress-bar class="default"></mc-progress-bar>
`
})
class TestApp {
color: ThemePalette;
value: number = 0;
mode: string;
id: string;
}
48 changes: 48 additions & 0 deletions src/lib/progress-bar/progress-bar.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
ChangeDetectionStrategy,
Component,
ViewEncapsulation,
ElementRef,
Input
} from '@angular/core';
import { CanColor, mixinColor, ThemePalette } from '@ptsecurity/mosaic/core';


export type ProgressBarMode = 'determinate' | 'indeterminate';

let idIterator = 0;

const MIN_PERCENT = 0;
const MAX_PERCENT = 100;

export class McProgressBarBase {
constructor(public _elementRef: ElementRef) {}
}

export const _McProgressBarMixinBase = mixinColor(McProgressBarBase);

@Component({
selector: 'mc-progress-bar',
templateUrl: './progress-bar.component.html',
styleUrls: ['./progress-bar.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
host: {
class: 'mc-progress-bar',
'[attr.id]': 'id'
}
})
export class McProgressBar extends _McProgressBarMixinBase implements CanColor {
@Input() id: string = `mc-progress-bar-${idIterator++}`;
@Input() value: number = 0;
@Input() mode: ProgressBarMode = 'determinate';
@Input() color: ThemePalette = ThemePalette.Primary;

constructor(elementRef: ElementRef) {
super(elementRef);
}

get percentage(): number {
return Math.max(MIN_PERCENT, Math.min(MAX_PERCENT, this.value)) / MAX_PERCENT;
}
}
47 changes: 47 additions & 0 deletions src/lib/progress-bar/progress-bar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
`<mc-progress-bar>` is a component that allows display progress bar.

### Simple progress bar

A `<mc-progress-bar>` element can be used on its own to create a horizontal progress line with Mosaic theme

```html
<mc-progress-bar></mc-progress-bar>
```

### Props

#### `value`
Displaying length of progress bar depends on this property
The range of value is [0, 100]
Default: 0

```html
This will fill 30% of the hole progress bar
<mc-progress-bar value="30"></mc-progress-bar>
```

#### `mode`
Enum ('determinate', 'indeterminate')
Default: 'determinate'

```html
To show indeterminate progress
<mc-progress-bar mode="indeterminate"></mc-progress-bar>
Or for determinate progress
<mc-progress-bar mode="determinate" value="30"></mc-progress-bar>
```

#### `color`
Enum ('primary', 'second', 'warn')
Default: 'primary'
Set theming of element

```html
<mc-progress-bar color="primary"></mc-progress-bar>
<mc-progress-bar color="second"></mc-progress-bar>
<mc-progress-bar color="warn"></mc-progress-bar>
```

### Theming
The color of a `<mc-progress-bar>` can be changed by using the `color` property. By default, it
use the theme's `primary` color. This can be changed to `'second'` or `'warn'`.
Loading

0 comments on commit 523cbc7

Please sign in to comment.