Skip to content

Commit

Permalink
New Component: Progress (#44)
Browse files Browse the repository at this point in the history
* created progress component

* fixed custom label wrapping issue

* improved validation

* dropped ng-init jank
  • Loading branch information
langdonx authored and IdanCo committed Aug 6, 2017
1 parent 190c7fb commit fd5ef27
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/docs/demos/progress/progress-demo.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default class {
constructor() {
this.background = '';
this.height = 20;
this.label = '';
this.max = 100;
this.value = 25;
}
}
87 changes: 87 additions & 0 deletions src/docs/demos/progress/progress-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<style>
progress { width: 100%; }
</style>

<h6>Side-By-Side HTML5 and Bootstrap 4</h6>

<div class="mb-3">
<progress ng-attr-value="{{$ctrl.value}}" max="{{$ctrl.max}}" style="height: {{$ctrl.height}}px;">{{$ctrl.value}} perc.</progress>
<ngbs-progress ng-attr-value="$ctrl.value"
max="$ctrl.max"
auto-label="$ctrl.label === 'auto'"
animated-progress="$ctrl.animatedProgress"
animated-stripes="$ctrl.animatedStripes"
background="$ctrl.background"
striped="$ctrl.striped"
style="height: {{$ctrl.height}}px;">{{$ctrl.label === 'custom' ? $ctrl.value + ' perc.' : ''}}</ngbs-progress>
</div>

<div class="row">
<div class="col-6">
<div class="form-group">
<label class="form-label" for="progress-value">Value</label>
<input id="progress-value" class="form-control" type="number" ng-model="$ctrl.value" min="0" ng-attr-max="{{$ctrl.max}}"></input>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label class="form-label" for="progress-max">Max</label>
<input id="progress-max" class="form-control" type="number" min="0" ng-model="$ctrl.max" ng-attr-min="{{$ctrl.value}}">
</div>
</div>
<div class="col-6">
<div class="form-group">
<label class="form-label" for="progress-label">Label</label>
<select id="progress-label" class="form-control" ng-model="$ctrl.label">
<option value="">No Label</option>
<option value="auto">Automatic Label</option>
<option value="custom">Custom Label</option>
</select>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label class="form-label" for="progress-background">Background</label>
<select id="progress-background" class="form-control" ng-model="$ctrl.background">
<option value="">Unspecified</option>
<option value="primary">Primary</option>
<option value="success">Success</option>
<option value="info">Info</option>
<option value="warning">Warning</option>
<option value="danger">Danger</option>
<option value="inverse">Inverse</option>
<option value="faded">Faded</option>
</select>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label class="form-label" for="progress-height">Height</label>
<input id="progress-height" class="form-control" type="number" ng-model="$ctrl.height" min="4" max="80">
</div>
</div>
</div>
<div class="form-inline mb-4">
<div class="form-check mr-3">
<label class="form-check-label pl-0">
<input type="checkbox" ng-model="$ctrl.striped">&nbsp;Striped
</label>
</div>
<div class="form-check mr-3">
<label class="form-check-label pl-0">
<input type="checkbox" ng-model="$ctrl.animatedProgress">&nbsp;Animated Progress
</label>
</div>
<div class="form-check mr-3">
<label class="form-check-label pl-0">
<input type="checkbox" ng-model="$ctrl.animatedStripes">&nbsp;Animated Stripes
</label>
</div>
</div>
</div>

<h6>Indeterminate</h6>
<div class="mb-3">
<progress class="mb-3"></progress>
<ngbs-progress class="mb-3"></ngbs-progress>
</div>
17 changes: 17 additions & 0 deletions src/docs/demos/progress/progress-demo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## ngbs-progress

This component merges the simplicity of HTML5's `<progress>` with the beauty of Bootstrap 4's Progress component. In addition to the attributes below, the component's `height` style can be set for a taller (or shorter) progress indicator.

**max** (*number*, optional) - Represents how much of a particular task needs to be done before it is considered complete. If provided, the number must be greater than zero.

**value** (*number*, optional) - Represents how much of a particular task has been done. If provided, the number must be greater than or equal to 0 and less than or equal to `max`. This attribute is optional, which allows you to illustrate that a particular task is ongoing with no indication of how long it is expected to take.

**animated-progress** (*boolean*, optional) - Whether or not changes to the `value` should be animated. Defaults to `false`.

**auto-label** (*boolean*, optional) - Automatically displays a label inside of the progress indicator (e.g.- 25%). You can also specify your own custom label via `innerHTML`. Defaults to `false`.

**striped** (*boolean*, optional) - The display style of the progress indicator. Defaults to `false`.

**animated-striped** (*boolean*, optional) - Used in conjunction with the `striped` attribute. Defaults to `false`.

**background** (*string*, optional) - This maps to Bootstrap 4's colors. Values can be `'primary'`, `'success'`, `'info'`, `'warning'`, `'danger'`, `'inverse'`, or `'faded'`. Defaults to `'primary'`.
30 changes: 30 additions & 0 deletions src/docs/demos/progress/progress-demo.module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Import Angular Resources
import template from './progress-demo.html';
import controller from './progress-demo.controller.js';

// Import Raw Files
import TemplateRaw from '!raw-loader!./progress-demo.html';
import ControllerRaw from '!raw-loader!./progress-demo.controller.js';
import MarkdownRaw from '!raw-loader!./progress-demo.md';

// manipulate controller to pass raw files up to demo
controller.prototype.$onInit = function() {
this.demo.html = TemplateRaw;
this.demo.js = ControllerRaw;
this.demo.md = MarkdownRaw;
};

// Component definition
const Component = {
require: {
demo: '^demo'
},
template,
controller
};

// Register module, register component and export name
export default angular
.module('ng1bs4.docs.progressDemo', [])
.component('progressDemo', Component)
.name;
4 changes: 4 additions & 0 deletions src/docs/docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ <h1>Pagination</h1>
<demo>
<pagination-demo></pagination-demo>
</demo>
<h1>Progress</h1>
<demo>
<progress-demo></progress-demo>
</demo>
</div>
</div>

Expand Down
2 changes: 2 additions & 0 deletions src/docs/docs.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import TooltipDemo from './demos/tooltip/tooltip-demo.module';
import AlertDemo from './demos/alert/alert-demo.module';
import ModalDemo from './demos/modal/modal-demo.module';
import PaginationDemo from './demos/pagination/pagination-demo.module';
import ProgressDemo from './demos/progress/progress-demo.module';

// Register module, define components, configure routes and export name
export default angular
Expand All @@ -32,6 +33,7 @@ export default angular
AlertDemo,
ModalDemo,
PaginationDemo,
ProgressDemo,
])
.component('docs', Docs)
.name;
2 changes: 2 additions & 0 deletions src/library/library.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import TooltipModule from './tooltip/tooltip.module';
import AlertModule from './alert/alert.module';
import ModalModule from './modal/modal.module';
import PaginationModule from './pagination/pagination.module';
import ProgressModule from './progress/progress.module';

// Register module, inject components and export name
export default angular
Expand All @@ -25,6 +26,7 @@ export default angular
AlertModule,
ModalModule,
PaginationModule,
ProgressModule,
])
.config(function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
Expand Down
69 changes: 69 additions & 0 deletions src/library/progress/progress.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Import Template
import template from './progress.html';

const SUPPORTED_BACKGROUNDS = ['', 'primary', 'success', 'info', 'warning', 'danger', 'inverse', 'faded'];

// Set up controller
class controller {
constructor($log) {
Object.assign(this, {
$log
});

this.percentage = 0;
this.roundedPercentage = 0;
}

$onChanges(changesObj) {
// (re)validate bindings
if (this.max && (typeof this.max !== 'number' || isFinite(this.max) === false)) {
this.$log.error('invalid ngbsProgress::max:', JSON.stringify(this.max), 'expecting a number');
}

if (this.value && (typeof this.value !== 'number' || isFinite(this.value) === false)) {
this.$log.error('invalid ngbsProgress::value:', JSON.stringify(this.value), 'expecting a number');
}

if (this.animatedProgress && typeof this.animatedProgress !== 'boolean') {
this.$log.error('invalid ngbsProgress::animatedProgress:', JSON.stringify(this.animatedProgress), 'expecting a boolean');
}

if (this.autoLabel && typeof this.autoLabel !== 'boolean') {
this.$log.error('invalid ngbsProgress::autoLabel:', JSON.stringify(this.autoLabel), 'expecting a boolean');
}

if (this.striped && typeof this.striped !== 'boolean') {
this.$log.error('invalid ngbsProgress::striped:', JSON.stringify(this.striped), 'expecting a boolean');
}

if (this.animatedStripes && typeof this.animatedStripes !== 'boolean') {
this.$log.error('invalid ngbsProgress::animatedStripes:', JSON.stringify(this.animatedStripes), 'expecting a boolean');
}

if (this.background && SUPPORTED_BACKGROUNDS.includes(this.background) === false) {
this.$log.error('invalid ngbsProgress::background:', JSON.stringify(this.background), 'expecting one of the following', SUPPORTED_BACKGROUNDS);
}

// recalculate percentage if max/value change
if (changesObj.value || changesObj.max) {
this.percentage = this.value / this.max * 100;
this.roundedPercentage = Math.round(this.percentage);
}
}
}

// Define and export component
export default {
bindings: {
animatedProgress: '<',
animatedStripes: '<',
autoLabel: '<',
background: '<',
max: '<',
striped: '<',
value: '<',
},
transclude: true,
template,
controller,
};
17 changes: 17 additions & 0 deletions src/library/progress/progress.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div class="progress">
<div class="progress-bar" role="progressbar"
ng-if="$ctrl.value || $ctrl.value === 0"
ng-attr-aria-valuenow="{{$ctrl.value}}"
ng-attr-aria-valuemax="{{$ctrl.max}}"
ng-attr-style="width: {{$ctrl.percentage}}%"
ng-class="[$ctrl.background ? 'bg-' + $ctrl.background : '', { 'animated-progress': $ctrl.animatedProgress, 'progress-bar-animated': $ctrl.animatedStripes, 'progress-bar-striped': $ctrl.striped }]">
<span ng-if="$ctrl.autoLabel">{{$ctrl.roundedPercentage}}%</span>
<span ng-if="!$ctrl.autoLabel" ng-transclude></span>
</div>

<div class="progress-bar indeterminate" role="progressbar"
ng-if="!$ctrl.value && $ctrl.value !== 0"
aria-valuenow="Unknown"
aria-valuemax="Unknown"
ng-class="[$ctrl.background ? 'bg-' + $ctrl.background : '', { 'progress-bar-animated': $ctrl.animatedStripes, 'progress-bar-striped': $ctrl.striped }]"></div>
</div>
9 changes: 9 additions & 0 deletions src/library/progress/progress.module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Import Resources
import component from './progress.component';
import './progress.scss';

// Register module, register component and export name
export default angular
.module('ng1bs4.library.progress', [])
.component('ngbsProgress', component)
.name;
50 changes: 50 additions & 0 deletions src/library/progress/progress.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
ngbs-progress {
display: block;
height: 1rem;

> .progress {
height: 100%;

> .progress-bar {
position: relative;

&.animated-progress {
transition: width 500ms;
}

&.indeterminate {
width: 25%;
animation-duration: 2.5s;
animation-iteration-count: infinite;
animation-name: progress-bar-indeterminate;
animation-timing-function: linear;

@keyframes progress-bar-indeterminate {
0% {
left: 0;
}

50% {
left: 75%;
}

100% {
left: 0;
}
}
}

> span {
white-space: nowrap;
}
}
}

// patch to vertically align labels on taller progress bars, remove when this is merged https://github.com/twbs/bootstrap/pull/22703
> .progress > .progress-bar {
align-items: center;
display: flex;
height: 100%;
justify-content: center;
}
}

0 comments on commit fd5ef27

Please sign in to comment.