Skip to content

Commit

Permalink
feat: progress-indicator component (#184)
Browse files Browse the repository at this point in the history
* feat(progress-indicator): completed progress-indicator component

* fix(progress-indicator): code review and fix

* fix(progress-indicator): fix storybook control bug and add jsdoc info

* fix(progress-indicator): fix jsdoc default values

* fix(progress-indicator): fix progress indicator text font
  • Loading branch information
DamlaDemir authored Aug 9, 2022
1 parent 3491805 commit c359b4d
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 5 deletions.
3 changes: 2 additions & 1 deletion commitlint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module.exports = {
'input',
'badge',
'tab',
'tooltip'
'tooltip',
'progress-indicator'
],
],
},
Expand Down
3 changes: 2 additions & 1 deletion src/baklava.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export { default as BlInput } from './components/input/bl-input';
export { default as BlTab } from './components/tab-group/tab/bl-tab';
export { default as BlTabGroup } from './components/tab-group/bl-tab-group';
export { default as BlTabPanel } from './components/tab-group/tab-panel/bl-tab-panel';
export { getIconPath, setIconPath } from './utilities/asset-paths';
export { default as BlTooltip } from './components/tooltip/bl-tooltip';
export { default as BlProgressIndicator } from './components/progress-indicator/bl-progress-indicator';
export { getIconPath, setIconPath } from './utilities/asset-paths';
3 changes: 0 additions & 3 deletions src/components/input/bl-input.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ import {
'label-fixed': {
control: 'boolean',
},
'': {
control: 'text',
},
helpText: {
control: 'text'
}
Expand Down
36 changes: 36 additions & 0 deletions src/components/progress-indicator/bl-progress-indicator.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.progress-indicator {
--max: 100;
--value: 0;
--value-color: var(--bl-color-success);
--height: var(--bl-size-2xs);
--radius: var(--bl-size-3xs);

position: relative;
background-color: var(--bl-color-secondary-background);
height: var(--height);
border-radius: var(--radius);
width: 100%;
}

.progress-indicator::before {
content: '';
position: absolute;
height: 100%;
width: calc(100% / var(--max) * var(--value));
background-color: var(--value-color);
border-radius: var(--radius);
}

:host([size='small']) .progress-indicator {
--height: var(--bl-size-3xs);
--radius: var(--bl-size-4xs);
}

:host([size='large']) .progress-indicator {
--height: var(--bl-size-xs);
--radius: 6px;
}

:host([failed]) .progress-indicator {
--value-color: var(--bl-color-danger);
}
100 changes: 100 additions & 0 deletions src/components/progress-indicator/bl-progress-indicator.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { styleMap } from 'lit/directives/style-map.js';
import { Meta, Canvas, ArgsTable, Story, Preview, Source } from '@storybook/addon-docs';

<Meta
title="Components/Progress Indicator"
component="bl-progress-indicator"
argTypes={{
size: {
control: {
type: 'select',
options: ['small','medium', 'large']
},
type: 'string'
},
max: {
control: 'text',
type: 'number'
},
value: {
control: 'text',
type: 'number'
},
failed: {
control: 'boolean',
},
}}
/>

export const ProgressIndicatorTemplate = (args) => html`
<bl-progress-indicator
size='${ifDefined(args.size)}'
max='${ifDefined(args.max)}'
value='${ifDefined(args.value)}'
?failed=${args.failed}
style='${ifDefined(args.styles ? styleMap(args.styles) : undefined)}'></bl-progress-indicator>`

export const FailedTemplate = (args) => html`
<div>
<p style='color: var(--bl-color-danger); margin: var(--bl-size-3xs); font: var(--bl-font-title-4-regular)'>Upload Failed - Image must not be larger than 3mb.</p>${ProgressIndicatorTemplate({ value:'100', failed:true, ...args })}
</div>`;

export const WithMaxTemplate = (args) => html`
<div>
<p style='color: var(--bl-color-content-secondary); margin: var(--bl-size-3xs); font: var(--bl-font-title-4-regular)'> Completed Tasks: <b style='color: var(--bl-color-success)'> 5/8 </b></p>${ProgressIndicatorTemplate({ max:'8', value: '5', ...args })}
</div>`;

# Progress Indicator

A progress indicator provides feedback about the duration and progression of a process to indicate how long a user will be waiting.

Progress indicator component used for a long operation or a process that can take a considerable or unknown amount of time. It visually shows the progression of a system operation such as downloading, uploading, loading data, submitting a form, or saving updates.


## Basic Usage

By default, the `max` is 100 and the progress indicator is evaluated over 100. So the `value` must be a valid floating point number between 0 and `max`, or between 0 and 100 if `max` is omitted.


<Canvas>
<Story name="Basic Usage" args={{ value: '50' }}>
{ProgressIndicatorTemplate.bind({})}
</Story>
</Canvas>

You don't have to pass the `value` according to 100 percent. For example, if you have a total of 8 tasks and completed 5 tasks you can pass parameters like `max="8" value="5"`. The progress indicator will divide into 8 parts and 5 parts will be full.

<Canvas>
<Story name="Usage With Max Value">
{WithMaxTemplate.bind({})}
</Story>
</Canvas>

## Progress Indicator Status
The progress indicator appears in success mode (green) by default. But if you need to show fail status for example failed to upload or failed to complete tasks you can pass `failed` parameters.

<Canvas>
<Story name="Progress Indicator Status">
{FailedTemplate.bind({})}
</Story>
</Canvas>

## Progress Indicator Sizes

We have 3 sizes of progress indicator: `large`, `medium`, `small`. Default size is `medium`.

<Canvas isColumn>
<Story name="Progress Indicator Small" args={{ size: 'small', value: '45' }}>
{ProgressIndicatorTemplate.bind({})}
</Story>
<Story name="Progress Indicator Medium" args={{ size: 'medium', value: '45' }}>
{ProgressIndicatorTemplate.bind({})}
</Story>
<Story name="Progress Indicator Large" args={{ size: 'large', value: '45' }}>
{ProgressIndicatorTemplate.bind({})}
</Story>
</Canvas>

<ArgsTable of="bl-progress-indicator" />
85 changes: 85 additions & 0 deletions src/components/progress-indicator/bl-progress-indicator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { assert, elementUpdated, expect, fixture, html } from '@open-wc/testing';
import BlProgressIndicator from './bl-progress-indicator';
import type typeOfBlProgressIndicator from './bl-progress-indicator';

describe('bl-progress-indicator', () => {
it('should be defined progress indicator instance', () => {
//when
const el = document.createElement('bl-progress-indicator');

//then
assert.instanceOf(el, BlProgressIndicator);
});

it('should be rendered with default values', async () => {
//when
const el = await fixture<typeOfBlProgressIndicator>(
html`<bl-progress-indicator></bl-progress-indicator>`
);

//then
assert.shadowDom.equal(
el,
`
<div
class="progress-indicator"
role="progressbar"
aria-valuemax="100"
aria-valuenow="0"
></div>
`
);
});

it('should have correct default values', async () => {
//when
const el = await fixture<typeOfBlProgressIndicator>(
html`<bl-progress-indicator></bl-progress-indicator>`
);

//then
expect(el.size).to.equal('medium');
expect(el.max).to.equal(100);
expect(el.value).to.equal(0);
expect(el.failed).to.equal(false);
});

it('should be rendered with correct size,max,failed,value attributes', async () => {
//when
const el = await fixture<typeOfBlProgressIndicator>(
html`<bl-progress-indicator size="large" max="8" value="3" failed></bl-progress-indicator>`
);

//then
const wrapper = el.shadowRoot?.querySelector('.progress-indicator') as HTMLDivElement;
const cssMaxVariable = getComputedStyle(wrapper).getPropertyValue('--max');
const cssValueVariable = getComputedStyle(wrapper).getPropertyValue('--value');

expect(el.size).to.eq('large');
expect(el.max).to.eq(8);
expect(el.value).to.eq(3);
expect(el.failed).to.eq(true);
expect(cssMaxVariable).to.eq('8');
expect(cssValueVariable).to.eq('3');
});

it('should be rendered with correct size,max,failed,value attributes when size,max,failed,value attributes was changed', async () => {
//given
const el = await fixture<typeOfBlProgressIndicator>(
html`<bl-progress-indicator size="large" max="8" value="3"></bl-progress-indicator>`
);
el.setAttribute('size', 'small');
el.setAttribute('max', '5');
el.setAttribute('value', '4');
el.setAttribute('failed', 'true');

//when
await elementUpdated(el);

//then
expect(el.size).to.eq('small');
expect(el.max).to.eq(5);
expect(el.value).to.eq(4);
expect(el.failed).to.eq(true);
});
});
82 changes: 82 additions & 0 deletions src/components/progress-indicator/bl-progress-indicator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { CSSResultGroup, html, LitElement, TemplateResult } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import style from './bl-progress-indicator.css';

export type ProgressIndicatorSize = 'small' | 'medium' | 'large';

/**
* @tag bl-progress-indicator
* @summary Baklava Progress Indicator component
*
* @property {max} [max=100]
* @property {number} [value=0]
*/

@customElement('bl-progress-indicator')
export default class BlProgressIndicator extends LitElement {
static get styles(): CSSResultGroup {
return style;
}

@query('.progress-indicator') private wrapper: HTMLElement;

/**
* Sets the size
*/
@property({ type: String })
size: ProgressIndicatorSize = 'medium';

/**
* Sets the status
*/
@property({ type: Boolean })
failed = false;

/**
* Sets the max
*/
@property({ type: Number })
get max() {
return this._max;
}
set max(max: number) {
this._max = max;
this.updateCssVariable();
}

/**
* Sets the value
*/
@property({ type: Number })
get value() {
return this._value;
}
set value(value: number) {
this._value = value;
this.updateCssVariable();
}

@state() private _max = 100;
@state() private _value = 0;

async updateCssVariable() {
await this.updateComplete;
this.wrapper.style.setProperty('--value', `${this.value}`);
this.wrapper.style.setProperty('--max', `${this.max}`);
}

render(): TemplateResult {
return html`<div
class="progress-indicator"
role="progressbar"
aria-valuemax="${this._max}"
aria-valuenow="${this._value}"
></div>`;
}
}

declare global {
interface HTMLElementTagNameMap {
'bl-progress-indicator': BlProgressIndicator;
}
}

0 comments on commit c359b4d

Please sign in to comment.