Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@lion/progress-indicator

Package Overview
Dependencies
Maintainers
2
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lion/progress-indicator - npm Package Compare versions

Comparing version 0.9.0 to 0.10.0

175

custom-elements.json

@@ -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 @@ {

15

docs/overview.md

@@ -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');
});
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc