@lion/progress-indicator
Advanced tools
Comparing version 0.9.0 to 0.10.0
@@ -74,2 +74,59 @@ { | ||
{ | ||
"kind": "field", | ||
"name": "indeterminate", | ||
"type": { | ||
"text": "boolean" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_progressPercentage", | ||
"type": { | ||
"text": "number | undefined" | ||
}, | ||
"description": "In case of a determinate progress-indicator it returns the progress percentage\nbased on value, min & max.\nCould be used for styling inside the _graphicTemplate" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "value", | ||
"type": { | ||
"text": "number" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "min", | ||
"type": { | ||
"text": "number" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "max", | ||
"type": { | ||
"text": "number" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_ariaLabel", | ||
"type": { | ||
"text": "string" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_ariaLabelledby", | ||
"type": { | ||
"text": "string" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "__hasDefaultLabelSet", | ||
"type": { | ||
"text": "boolean" | ||
} | ||
}, | ||
{ | ||
"kind": "method", | ||
@@ -83,2 +140,20 @@ "name": "_graphicTemplate", | ||
} | ||
}, | ||
{ | ||
"kind": "method", | ||
"name": "_resetAriaValueAttributes", | ||
"return": { | ||
"type": { | ||
"text": "void" | ||
} | ||
} | ||
}, | ||
{ | ||
"kind": "method", | ||
"name": "_setDefaultLabel", | ||
"return": { | ||
"type": { | ||
"text": "void" | ||
} | ||
} | ||
} | ||
@@ -120,2 +195,14 @@ ], | ||
{ | ||
"kind": "field", | ||
"name": "indeterminate", | ||
"type": { | ||
"text": "boolean" | ||
} | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_progressPercentage", | ||
"description": "In case of a determinate progress-indicator it returns the progress percentage\nbased on value, min & max.\nCould be used for styling inside the _graphicTemplate" | ||
}, | ||
{ | ||
"kind": "method", | ||
@@ -128,4 +215,92 @@ "name": "_graphicTemplate", | ||
"name": "onLocaleUpdated" | ||
}, | ||
{ | ||
"kind": "method", | ||
"name": "_resetAriaValueAttributes" | ||
}, | ||
{ | ||
"kind": "method", | ||
"name": "_setDefaultLabel" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "value", | ||
"type": { | ||
"text": "number" | ||
}, | ||
"default": "0", | ||
"privacy": "public", | ||
"attribute": "value" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "min", | ||
"type": { | ||
"text": "number" | ||
}, | ||
"default": "0", | ||
"privacy": "public", | ||
"attribute": "min" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "max", | ||
"type": { | ||
"text": "number" | ||
}, | ||
"default": "100", | ||
"privacy": "public", | ||
"attribute": "max" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_ariaLabel", | ||
"type": { | ||
"text": "string" | ||
}, | ||
"default": "''", | ||
"privacy": "public", | ||
"attribute": "aria-label" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_ariaLabelledby", | ||
"type": { | ||
"text": "string" | ||
}, | ||
"default": "''", | ||
"privacy": "public", | ||
"attribute": "aria-labelledby" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "__hasDefaultLabelSet", | ||
"type": { | ||
"text": "boolean" | ||
}, | ||
"default": "false" | ||
} | ||
], | ||
"attributes": [ | ||
{ | ||
"name": "value", | ||
"fieldName": "value" | ||
}, | ||
{ | ||
"name": "min", | ||
"fieldName": "min" | ||
}, | ||
{ | ||
"name": "max", | ||
"fieldName": "max" | ||
}, | ||
{ | ||
"name": "aria-label", | ||
"fieldName": "_ariaLabel" | ||
}, | ||
{ | ||
"name": "aria-labelledby", | ||
"fieldName": "_ariaLabelledby" | ||
} | ||
], | ||
"mixins": [ | ||
@@ -132,0 +307,0 @@ { |
@@ -5,8 +5,11 @@ # Progress Indicator >> Overview ||10 | ||
```js script | ||
import { html } from '@mdjs/mdjs-preview'; | ||
import '@lion/progress-indicator/define'; | ||
``` | ||
```html | ||
<lion-progress-indicator></lion-progress-indicator> | ||
<lion-progress-indicator aria-label="Interest rate" value="50"></lion-progress-indicator> | ||
``` | ||
Note: You don't see a live demo here as it would be empty, since there is no styling. Check out the [examples](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/components/progress-indicator/examples.md) if you want to see a possible implementation. | ||
## Features | ||
@@ -16,5 +19,9 @@ | ||
- Can be indeterminate or determinate, depending on whether it has a value. | ||
- Accessibility compliant | ||
- Localized "Loading" label | ||
- Localized "Loading" label in case of an indeterminate progress-indicator | ||
- Implementation independent of visuals | ||
- `value`: progress value, setting this makes the progress-indicator determinate. | ||
- `min`: progress min value | ||
- `max`: progress max value | ||
@@ -21,0 +28,0 @@ ## Installation |
{ | ||
"name": "@lion/progress-indicator", | ||
"version": "0.9.0", | ||
"version": "0.10.0", | ||
"description": "A progress indicator that is easily styleable and accessible in all contexts", | ||
@@ -46,2 +46,3 @@ "license": "MIT", | ||
"loading-indicator", | ||
"progress-bar", | ||
"progress-indicator", | ||
@@ -48,0 +49,0 @@ "spinner", |
@@ -5,8 +5,11 @@ # Progress Indicator >> Overview ||10 | ||
```js script | ||
import { html } from '@mdjs/mdjs-preview'; | ||
import '@lion/progress-indicator/define'; | ||
``` | ||
```html | ||
<lion-progress-indicator></lion-progress-indicator> | ||
<lion-progress-indicator aria-label="Interest rate" value="50"></lion-progress-indicator> | ||
``` | ||
Note: You don't see a live demo here as it would be empty, since there is no styling. Check out the [examples](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/components/progress-indicator/examples.md) if you want to see a possible implementation. | ||
## Features | ||
@@ -16,5 +19,9 @@ | ||
- Can be indeterminate or determinate, depending on whether it has a value. | ||
- Accessibility compliant | ||
- Localized "Loading" label | ||
- Localized "Loading" label in case of an indeterminate progress-indicator | ||
- Implementation independent of visuals | ||
- `value`: progress value, setting this makes the progress-indicator determinate. | ||
- `min`: progress min value | ||
- `max`: progress max value | ||
@@ -21,0 +28,0 @@ ## Installation |
declare const LionProgressIndicator_base: typeof LitElement & import("@open-wc/dedupe-mixin").Constructor<import("@lion/localize/types/LocalizeMixinTypes").LocalizeMixinHost> & Pick<typeof import("@lion/localize/types/LocalizeMixinTypes").LocalizeMixinHost, "prototype" | "localizeNamespaces" | "waitForLocalizeNamespaces"> & Pick<typeof LitElement, "prototype" | "_$litElement$" | "enabledWarnings" | "enableWarning" | "disableWarning" | "addInitializer" | "_initializers" | "elementProperties" | "properties" | "elementStyles" | "styles" | "observedAttributes" | "createProperty" | "shadowRootOptions">; | ||
/** | ||
* @typedef {import('@lion/core').TemplateResult} TemplateResult | ||
*/ | ||
export class LionProgressIndicator extends LionProgressIndicator_base { | ||
static get properties(): { | ||
value: { | ||
type: NumberConstructor; | ||
}; | ||
min: { | ||
type: NumberConstructor; | ||
}; | ||
max: { | ||
type: NumberConstructor; | ||
}; | ||
_ariaLabel: { | ||
attribute: string; | ||
type: StringConstructor; | ||
}; | ||
_ariaLabelledby: { | ||
attribute: string; | ||
type: StringConstructor; | ||
}; | ||
}; | ||
static get localizeNamespaces(): { | ||
'lion-progress-indicator': (locale: string) => Promise<typeof import("../translations/bg")>; | ||
}[]; | ||
/** | ||
* @readonly | ||
* @type {boolean} | ||
*/ | ||
readonly get indeterminate(): boolean; | ||
/** | ||
* In case of a determinate progress-indicator it returns the progress percentage | ||
* based on value, min & max. | ||
* Could be used for styling inside the _graphicTemplate | ||
* | ||
* @example | ||
* style="width: ${this._progressPercentage}%" | ||
*/ | ||
get _progressPercentage(): number | undefined; | ||
value: number; | ||
min: number; | ||
max: number; | ||
_ariaLabel: string; | ||
_ariaLabelledby: string; | ||
__hasDefaultLabelSet: boolean; | ||
/** @protected */ | ||
protected _graphicTemplate(): symbol; | ||
_resetAriaValueAttributes(): void; | ||
_setDefaultLabel(): void; | ||
} | ||
export type TemplateResult = import('@lion/core').TemplateResult; | ||
import { LitElement } from "@lion/core"; | ||
export {}; |
@@ -1,7 +0,25 @@ | ||
/* eslint-disable class-methods-use-this, import/no-extraneous-dependencies */ | ||
import { nothing, LitElement } from '@lion/core'; | ||
/* eslint-disable import/no-extraneous-dependencies */ | ||
import { LitElement, nothing } from '@lion/core'; | ||
import { localize, LocalizeMixin } from '@lion/localize'; | ||
/** | ||
* @typedef {import('@lion/core').TemplateResult} TemplateResult | ||
*/ | ||
export class LionProgressIndicator extends LocalizeMixin(LitElement) { | ||
static get properties() { | ||
return { | ||
value: { | ||
type: Number, | ||
}, | ||
min: { | ||
type: Number, | ||
}, | ||
max: { | ||
type: Number, | ||
}, | ||
_ariaLabel: { attribute: 'aria-label', type: String }, | ||
_ariaLabelledby: { attribute: 'aria-labelledby', type: String }, | ||
}; | ||
} | ||
static get localizeNamespaces() { | ||
@@ -70,3 +88,37 @@ return [ | ||
/** | ||
* @readonly | ||
* @type {boolean} | ||
*/ | ||
get indeterminate() { | ||
return !this.hasAttribute('value'); | ||
} | ||
/** | ||
* In case of a determinate progress-indicator it returns the progress percentage | ||
* based on value, min & max. | ||
* Could be used for styling inside the _graphicTemplate | ||
* | ||
* @example | ||
* style="width: ${this._progressPercentage}%" | ||
*/ | ||
get _progressPercentage() { | ||
if (this.indeterminate) { | ||
return undefined; | ||
} | ||
return ((this.value - this.min) / (this.max - this.min)) * 100; | ||
} | ||
constructor() { | ||
super(); | ||
this.value = 0; | ||
this.min = 0; | ||
this.max = 100; | ||
this._ariaLabel = ''; | ||
this._ariaLabelledby = ''; | ||
this.__hasDefaultLabelSet = false; | ||
} | ||
/** @protected */ | ||
// eslint-disable-next-line class-methods-use-this | ||
_graphicTemplate() { | ||
@@ -82,10 +134,74 @@ return nothing; | ||
super.connectedCallback(); | ||
this.setAttribute('role', 'status'); | ||
this.setAttribute('aria-live', 'polite'); | ||
this.setAttribute('role', 'progressbar'); | ||
} | ||
/** | ||
* Update aria labels on state change. | ||
* @param {import('@lion/core').PropertyValues } changedProperties | ||
*/ | ||
updated(changedProperties) { | ||
super.updated(changedProperties); | ||
if (this.indeterminate) { | ||
if (changedProperties.has('_ariaLabel') || changedProperties.has('_ariaLabelledby')) { | ||
this._setDefaultLabel(); | ||
} | ||
if (changedProperties.has('value')) { | ||
this._resetAriaValueAttributes(); | ||
this._setDefaultLabel(); | ||
} | ||
} else { | ||
if (changedProperties.has('value')) { | ||
if (!this.value || typeof this.value !== 'number') { | ||
this.removeAttribute('value'); | ||
} else if (this.value < this.min) { | ||
this.value = this.min; | ||
this.setAttribute('aria-valuenow', this.min.toString()); | ||
} else if (this.value > this.max) { | ||
this.value = this.max; | ||
this.setAttribute('aria-valuenow', this.max.toString()); | ||
} else { | ||
this.setAttribute('aria-valuenow', this.value.toString()); | ||
} | ||
if (this.__hasDefaultLabelSet === true) { | ||
this.removeAttribute('aria-label'); | ||
} | ||
} | ||
if (changedProperties.has('min')) { | ||
this.setAttribute('aria-valuemin', this.min.toString()); | ||
if (this.value < this.min) { | ||
this.value = this.min; | ||
} | ||
} | ||
if (changedProperties.has('max')) { | ||
this.setAttribute('aria-valuemax', this.max.toString()); | ||
if (this.value > this.max) { | ||
this.value = this.max; | ||
} | ||
} | ||
} | ||
} | ||
onLocaleUpdated() { | ||
const label = localize.msg('lion-progress-indicator:loading'); | ||
this.setAttribute('aria-label', label); | ||
super.onLocaleUpdated(); | ||
// only set default label for indeterminate | ||
if (this.indeterminate) { | ||
this._setDefaultLabel(); | ||
} | ||
} | ||
_resetAriaValueAttributes() { | ||
this.removeAttribute('aria-valuenow'); | ||
this.removeAttribute('aria-valuemin'); | ||
this.removeAttribute('aria-valuemax'); | ||
} | ||
_setDefaultLabel() { | ||
if (this._ariaLabelledby) { | ||
this.removeAttribute('aria-label'); | ||
} else if (!this._ariaLabel) { | ||
this.setAttribute('aria-label', localize.msg('lion-progress-indicator:loading')); | ||
this.__hasDefaultLabelSet = true; | ||
} | ||
} | ||
} |
@@ -1,1 +0,2 @@ | ||
export {}; | ||
export type LionProgressIndicator = import('../src/LionProgressIndicator').LionProgressIndicator; | ||
export type TemplateResult = import('@lion/core').TemplateResult; |
@@ -1,23 +0,211 @@ | ||
import { expect, fixture } from '@open-wc/testing'; | ||
import { html } from '@lion/core'; | ||
import { expect, fixture as _fixture } from '@open-wc/testing'; | ||
import '@lion/progress-indicator/define'; | ||
/** | ||
* @typedef {import('../src/LionProgressIndicator').LionProgressIndicator} LionProgressIndicator | ||
* @typedef {import('@lion/core').TemplateResult} TemplateResult | ||
*/ | ||
const fixture = /** @type {(arg: TemplateResult) => Promise<LionProgressIndicator>} */ (_fixture); | ||
describe('lion-progress-indicator', () => { | ||
describe('Accessibility', () => { | ||
it('adds a label', async () => { | ||
describe('indeterminate', async () => { | ||
it('is indeterminate when has no value attribute', async () => { | ||
const el = await fixture(html` <lion-progress-indicator></lion-progress-indicator> `); | ||
expect(el.indeterminate).to.be.true; | ||
}); | ||
it('adds a label by default', async () => { | ||
const el = await fixture(html` <lion-progress-indicator></lion-progress-indicator> `); | ||
await el.localizeNamespacesLoaded; | ||
expect(el.getAttribute('aria-label')).to.equal('Loading'); | ||
}); | ||
it('sets the right role', async () => { | ||
it('can override a label with "aria-label"', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
await el.localizeNamespacesLoaded; | ||
expect(el.getAttribute('aria-label')).to.equal('foo'); | ||
el.setAttribute('aria-label', 'bar'); | ||
expect(el.getAttribute('aria-label')).to.equal('bar'); | ||
el.removeAttribute('aria-label'); | ||
await el.updateComplete; | ||
expect(el.getAttribute('aria-label')).to.equal('Loading'); | ||
}); | ||
it('can override a label with "aria-labelledby"', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator aria-labelledby="foo-id"></lion-progress-indicator> `, | ||
); | ||
await el.localizeNamespacesLoaded; | ||
expect(el.getAttribute('aria-labelledby')).to.equal('foo-id'); | ||
expect(el.hasAttribute('aria-label')).to.be.false; | ||
el.setAttribute('aria-labelledby', 'bar-id'); | ||
expect(el.getAttribute('aria-labelledby')).to.equal('bar-id'); | ||
expect(el.hasAttribute('aria-label')).to.be.false; | ||
el.removeAttribute('aria-labelledby'); | ||
await el.updateComplete; | ||
expect(el.hasAttribute('aria-labelledby')).to.be.false; | ||
expect(el.getAttribute('aria-label')).to.equal('Loading'); | ||
}); | ||
it('loosses default aria-label when switch to determinate state', async () => { | ||
const el = await fixture(html` <lion-progress-indicator></lion-progress-indicator> `); | ||
expect(el.getAttribute('role')).to.equal('status'); | ||
await el.localizeNamespacesLoaded; | ||
expect(el.getAttribute('aria-label')).to.equal('Loading'); | ||
el.setAttribute('value', '30'); | ||
await el.updateComplete; | ||
expect(el.hasAttribute('aria-label')).to.be.false; | ||
}); | ||
it('sets aria-live to "polite"', async () => { | ||
it('keeps own aria-label when switch to determinate state', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.getAttribute('aria-label')).to.equal('foo'); | ||
el.setAttribute('value', '30'); | ||
await el.updateComplete; | ||
expect(el.getAttribute('aria-label')).to.equal('foo'); | ||
}); | ||
}); | ||
describe('determinate', async () => { | ||
it('is determinate when it has a value', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="25" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.indeterminate).to.be.false; | ||
}); | ||
it('can update value', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="25" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.getAttribute('aria-valuenow')).to.equal('25'); | ||
el.value = 30; | ||
await el.updateComplete; | ||
expect(el.getAttribute('aria-valuenow')).to.equal('30'); | ||
}); | ||
it('can update min', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="50" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.getAttribute('aria-valuemin')).to.equal('0'); | ||
el.min = 30; | ||
await el.updateComplete; | ||
expect(el.getAttribute('aria-valuemin')).to.equal('30'); | ||
}); | ||
it('can update max', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="50" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.getAttribute('aria-valuemax')).to.equal('100'); | ||
el.max = 70; | ||
await el.updateComplete; | ||
expect(el.getAttribute('aria-valuemax')).to.equal('70'); | ||
}); | ||
it('min & max limits value', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="150" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
// sets to default max: 100 | ||
expect(el.getAttribute('aria-valuenow')).to.equal('100'); | ||
el.value = -20; | ||
await el.updateComplete; | ||
// sets to default min: 0 | ||
expect(el.getAttribute('aria-valuenow')).to.equal('0'); | ||
}); | ||
// TODO make this feature available | ||
it.skip('supports valuetext', async () => { | ||
const el = await fixture( | ||
html` | ||
<lion-progress-indicator | ||
value="8" | ||
value-text="{value}% (34 minutes) remaining" | ||
></lion-progress-indicator> | ||
`, | ||
); | ||
expect(el.getAttribute('aria-valuetext')).to.equal('8% (34 minutes) remaining'); | ||
}); | ||
it('becomes indeterminate if value gets removed', async () => { | ||
const el = await fixture( | ||
html`<lion-progress-indicator value="30"></lion-progress-indicator> `, | ||
); | ||
el.removeAttribute('value'); | ||
await el.updateComplete; | ||
expect(el.indeterminate).to.be.true; | ||
expect(el.getAttribute('aria-label')).to.equal('Loading'); | ||
}); | ||
it("becomes indeterminate if value ain't a number", async () => { | ||
const el = await fixture( | ||
html`<lion-progress-indicator value="30"></lion-progress-indicator> `, | ||
); | ||
el.setAttribute('value', ''); | ||
await el.updateComplete; | ||
expect(el.indeterminate).to.be.true; | ||
await el.updateComplete; | ||
expect(el.hasAttribute('aria-valuenow')).to.be.false; | ||
expect(el.hasAttribute('aria-valuemin')).to.be.false; | ||
expect(el.hasAttribute('aria-valuemax')).to.be.false; | ||
expect(el.getAttribute('aria-label')).to.equal('Loading'); | ||
}); | ||
}); | ||
describe('Subclasers', () => { | ||
it('can use _progressPercentage getter to get the progress percentage', async () => { | ||
const el = await fixture( | ||
html` | ||
<lion-progress-indicator max="50" value="10" aria-label="foo"></lion-progress-indicator> | ||
`, | ||
); | ||
expect(el._progressPercentage).to.equal(20); | ||
}); | ||
}); | ||
describe('Accessibility', () => { | ||
it('by default', async () => { | ||
const el = await fixture(html` <lion-progress-indicator></lion-progress-indicator> `); | ||
expect(el.getAttribute('aria-live')).to.equal('polite'); | ||
expect(el.getAttribute('role')).to.equal('progressbar'); | ||
}); | ||
describe('indeterminate', () => { | ||
it('passes a11y test', async () => { | ||
const el = await fixture(html` <lion-progress-indicator></lion-progress-indicator> `); | ||
await expect(el).to.be.accessible(); | ||
}); | ||
}); | ||
describe('determinate', () => { | ||
it('passes a11y test', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="25" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
await expect(el).to.be.accessible(); | ||
}); | ||
it('once value is set', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="25" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.getAttribute('aria-valuenow')).to.equal('25'); | ||
}); | ||
it('allows to set min & max values', async () => { | ||
const el = await fixture( | ||
html` <lion-progress-indicator value="25" aria-label="foo"></lion-progress-indicator> `, | ||
); | ||
expect(el.getAttribute('aria-valuemin')).to.equal('0'); | ||
expect(el.getAttribute('aria-valuemax')).to.equal('100'); | ||
}); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40597
1318
37