diff --git a/docs/components/progress-ring.md b/docs/components/progress-ring.md index ba1c1a8c4..75d656d53 100644 --- a/docs/components/progress-ring.md +++ b/docs/components/progress-ring.md @@ -20,10 +20,10 @@ Use the `--size` custom property to set the diameter of the progress ring. ### Track Width -Use the `track-width` attribute to set the width of the progress ring's track. +Use the `--track-width` custom property to set the width of the progress ring's track. ```html preview - + ``` ### Colors diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 9efd99c39..143ecee0d 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -8,6 +8,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis ## Next +- Added `label` attribute to `` and `` to improve a11y - Updated to Bootstrap Icons to 1.6.0 ## 2.0.0-beta.57 diff --git a/package.json b/package.json index 6cfefd35e..02971dfa1 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "main": "dist/shoelace.js", "module": "dist/shoelace.js", - "customElements": "docs/dist/custom-elements.json", + "customElements": "dist/custom-elements.json", "type": "module", "types": "dist/shoelace.d.ts", "files": [ diff --git a/src/components/progress-bar/progress-bar.styles.ts b/src/components/progress-bar/progress-bar.styles.ts index ef48d5574..2c8ad8c3d 100644 --- a/src/components/progress-bar/progress-bar.styles.ts +++ b/src/components/progress-bar/progress-bar.styles.ts @@ -11,9 +11,6 @@ export default css` --label-color: rgb(var(--sl-color-neutral-0)); display: block; - } - - .progress-bar { position: relative; background-color: var(--track-color); height: var(--height); diff --git a/src/components/progress-bar/progress-bar.test.ts b/src/components/progress-bar/progress-bar.test.ts new file mode 100644 index 000000000..639a68b38 --- /dev/null +++ b/src/components/progress-bar/progress-bar.test.ts @@ -0,0 +1,89 @@ +import { expect, fixture, html } from '@open-wc/testing'; + +import '../../../dist/shoelace.js'; +import type SlProgressBar from './progress-bar'; + +describe('', () => { + let el: SlProgressBar; + + describe('when provided just a value parameter', async () => { + before(async () => { + el = await fixture(html``); + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + }); + + describe('when provided a title, and value parameter', async () => { + let base: HTMLDivElement; + let indicator: HTMLDivElement; + + before(async () => { + el = await fixture( + html`` + ); + base = el.shadowRoot?.querySelector('[part="base"]') as HTMLDivElement; + indicator = el.shadowRoot?.querySelector('[part="indicator"]') as HTMLDivElement; + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + + it('uses the value parameter on the base, as aria-valuenow', async () => { + expect(base).attribute('aria-valuenow', '25'); + }); + + it('appends a % to the value, and uses it as the the value parameter to determine the width on the "indicator" part', async () => { + expect(indicator).attribute('style', 'width:25%;'); + }); + }); + + describe('when provided an indeterminate parameter', async () => { + let base: HTMLDivElement; + + before(async () => { + el = await fixture( + html`` + ); + base = el.shadowRoot?.querySelector('[part="base"]') as HTMLDivElement; + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + + it('should append a progress-bar--indeterminate class to the "base" part.', async () => { + expect(base.classList.value.trim()).to.eq('progress-bar progress-bar--indeterminate'); + }); + }); + + describe('when provided a ariaLabel, and value parameter', async () => { + before(async () => { + el = await fixture( + html`` + ); + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + }); + + describe('when provided a ariaLabelledBy, and value parameter', async () => { + before(async () => { + el = await fixture( + html` + + + ` + ); + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + }); +}); diff --git a/src/components/progress-bar/progress-bar.ts b/src/components/progress-bar/progress-bar.ts index e9f010624..ec8a1a7a0 100644 --- a/src/components/progress-bar/progress-bar.ts +++ b/src/components/progress-bar/progress-bar.ts @@ -1,5 +1,6 @@ import { LitElement, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import styles from './progress-bar.styles'; @@ -29,6 +30,9 @@ export default class SlProgressBar extends LitElement { /** When true, percentage is ignored, the label is hidden, and the progress bar is drawn in an indeterminate state. */ @property({ type: Boolean, reflect: true }) indeterminate = false; + /** The progress bar's aria label. */ + @property() label = 'Progress'; // TODO - i18n + render() { return html`
${!this.indeterminate diff --git a/src/components/progress-ring/progress-ring.test.ts b/src/components/progress-ring/progress-ring.test.ts new file mode 100644 index 000000000..db316c293 --- /dev/null +++ b/src/components/progress-ring/progress-ring.test.ts @@ -0,0 +1,68 @@ +import { expect, fixture, html } from '@open-wc/testing'; + +import '../../../dist/shoelace.js'; +import type SlProgressRing from './progress-ring'; + +describe('', () => { + let el: SlProgressRing; + + describe('when provided just a value parameter', async () => { + before(async () => { + el = await fixture(html``); + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + }); + + describe('when provided a title, and value parameter', async () => { + let base: HTMLDivElement; + + before(async () => { + el = await fixture( + html`` + ); + base = el.shadowRoot?.querySelector('[part="base"]') as HTMLDivElement; + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + + it('uses the value parameter on the base, as aria-valuenow', async () => { + expect(base).attribute('aria-valuenow', '25'); + }); + + it('translates the value parameter to a percentage, and uses translation on the base, as percentage css variable', async () => { + expect(base).attribute('style', '--percentage: 0.25'); + }); + }); + + describe('when provided a ariaLabel, and value parameter', async () => { + before(async () => { + el = await fixture( + html`` + ); + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + }); + + describe('when provided a ariaLabelledBy, and value parameter', async () => { + before(async () => { + el = await fixture( + html` + + + ` + ); + }); + + it('should render a component that passes accessibility test.', async () => { + await expect(el).to.be.accessible(); + }); + }); +}); diff --git a/src/components/progress-ring/progress-ring.ts b/src/components/progress-ring/progress-ring.ts index 1eeccd65a..11ab3b609 100644 --- a/src/components/progress-ring/progress-ring.ts +++ b/src/components/progress-ring/progress-ring.ts @@ -1,5 +1,6 @@ import { LitElement, html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import styles from './progress-ring.styles'; /** @@ -27,6 +28,9 @@ export default class SlProgressRing extends LitElement { /** The current progress, 0 to 100. */ @property({ type: Number, reflect: true }) value = 0; + /** The progress ring's aria label. */ + @property() label = 'Progress'; // TODO - i18n + updated(changedProps: Map) { super.updated(changedProps); @@ -50,6 +54,7 @@ export default class SlProgressRing extends LitElement { part="base" class="progress-ring" role="progressbar" + aria-label=${ifDefined(this.label)} aria-valuemin="0" aria-valuemax="100" aria-valuenow="${this.value}"