From e3cdfe64fbb3e26286f5d64a3690a90b5e8b65b7 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Wed, 31 May 2023 11:56:44 -0400 Subject: [PATCH 01/44] feat(progress): adding progress element, adding variants and styles --- elements/package.json | 1 + elements/pf-progress/README.md | 11 ++ elements/pf-progress/demo/demo.css | 3 + elements/pf-progress/demo/pf-progress.html | 41 +++++ elements/pf-progress/demo/pf-progress.js | 1 + elements/pf-progress/docs/pf-progress.md | 17 ++ elements/pf-progress/pf-progress.css | 169 ++++++++++++++++++ elements/pf-progress/pf-progress.ts | 66 +++++++ elements/pf-progress/test/pf-progress.e2e.ts | 12 ++ elements/pf-progress/test/pf-progress.spec.ts | 17 ++ 10 files changed, 338 insertions(+) create mode 100644 elements/pf-progress/README.md create mode 100644 elements/pf-progress/demo/demo.css create mode 100644 elements/pf-progress/demo/pf-progress.html create mode 100644 elements/pf-progress/demo/pf-progress.js create mode 100644 elements/pf-progress/docs/pf-progress.md create mode 100644 elements/pf-progress/pf-progress.css create mode 100644 elements/pf-progress/pf-progress.ts create mode 100644 elements/pf-progress/test/pf-progress.e2e.ts create mode 100644 elements/pf-progress/test/pf-progress.spec.ts diff --git a/elements/package.json b/elements/package.json index d165a80485..997ba7ce54 100644 --- a/elements/package.json +++ b/elements/package.json @@ -40,6 +40,7 @@ "./pf-panel/pf-panel.js": "./pf-panel/pf-panel.js", "./pf-progress-stepper/pf-progress-step.js": "./pf-progress-stepper/pf-progress-step.js", "./pf-progress-stepper/pf-progress-stepper.js": "./pf-progress-stepper/pf-progress-stepper.js", + "./pf-progress/pf-progress.js": "./pf-progress/pf-progress.js", "./pf-spinner/BaseSpinner.js": "./pf-spinner/BaseSpinner.js", "./pf-spinner/pf-spinner.js": "./pf-spinner/pf-spinner.js", "./pf-switch/BaseSwitch.js": "./pf-switch/BaseSwitch.js", diff --git a/elements/pf-progress/README.md b/elements/pf-progress/README.md new file mode 100644 index 0000000000..300a11fc4e --- /dev/null +++ b/elements/pf-progress/README.md @@ -0,0 +1,11 @@ +# Progress +Add a description of the component here. + +## Usage +Describe how best to use this web component along with best practices. + +```html + + + +``` diff --git a/elements/pf-progress/demo/demo.css b/elements/pf-progress/demo/demo.css new file mode 100644 index 0000000000..ee35300913 --- /dev/null +++ b/elements/pf-progress/demo/demo.css @@ -0,0 +1,3 @@ +pf-progress { + /* insert demo styles */ +} diff --git a/elements/pf-progress/demo/pf-progress.html b/elements/pf-progress/demo/pf-progress.html new file mode 100644 index 0000000000..5fe4d723f2 --- /dev/null +++ b/elements/pf-progress/demo/pf-progress.html @@ -0,0 +1,41 @@ + + + +

Default:

+ + +

Small:

+ + +

Large:

+ + +

Outside:

+ + +

Inside:

+ + +

Success:

+ + +

Danger:

+ + +

Warning:

+ + +

Inside Success:

+ + +

Outside Danger:

+ + +

Single Line:

+ + +

Without Measure:

+ + +

Danger Without Measure:

+ diff --git a/elements/pf-progress/demo/pf-progress.js b/elements/pf-progress/demo/pf-progress.js new file mode 100644 index 0000000000..bc46f8f80b --- /dev/null +++ b/elements/pf-progress/demo/pf-progress.js @@ -0,0 +1 @@ +import '@patternfly/elements/pf-progress/pf-progress.js'; diff --git a/elements/pf-progress/docs/pf-progress.md b/elements/pf-progress/docs/pf-progress.md new file mode 100644 index 0000000000..64bf1ef68e --- /dev/null +++ b/elements/pf-progress/docs/pf-progress.md @@ -0,0 +1,17 @@ +{% renderOverview %} + +{% endrenderOverview %} + +{% band header="Usage" %}{% endband %} + +{% renderSlots %}{% endrenderSlots %} + +{% renderAttributes %}{% endrenderAttributes %} + +{% renderMethods %}{% endrenderMethods %} + +{% renderEvents %}{% endrenderEvents %} + +{% renderCssCustomProperties %}{% endrenderCssCustomProperties %} + +{% renderCssParts %}{% endrenderCssParts %} diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css new file mode 100644 index 0000000000..4075a69f3d --- /dev/null +++ b/elements/pf-progress/pf-progress.css @@ -0,0 +1,169 @@ +.container { + --pf-c-progress--GridGap: var(--pf-global--spacer--md, 1rem); + --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100, #06c); + --pf-c-progress__bar--Height: var(--pf-global--spacer--md, 1rem); + --pf-c-progress__bar--BackgroundColor: var(--pf-global--BackgroundColor--light-100, #ffffff); + --pf-c-progress__measure--m-static-width--MinWidth: 4.5ch; + --pf-c-progress__status-icon--Color: var(--pf-global--Color--100, #151515); + --pf-c-progress__status-icon--MarginLeft: var(--pf-global--spacer--sm, 0.5rem); + --pf-c-progress__bar--before--Opacity: .2; + --pf-c-progress__indicator--Height: var(--pf-c-progress__bar--Height); + --pf-c-progress__indicator--BackgroundColor: var(--pf-c-progress__bar--before--BackgroundColor); + --pf-c-progress__helper-text--MarginTop: calc(var(--pf-global--spacer--xs, 0.25rem) - var(--pf-c-progress--GridGap)); + --pf-c-progress--m-success__bar--BackgroundColor: var(--pf-global--success-color--100, #3e8635); + --pf-c-progress--m-warning__bar--BackgroundColor: var(--pf-global--warning-color--100, #f0ab00); + --pf-c-progress--m-danger__bar--BackgroundColor: var(--pf-global--danger-color--100, #c9190b); + --pf-c-progress--m-success__status-icon--Color: var(--pf-global--success-color--100, #3e8635); + --pf-c-progress--m-warning__status-icon--Color: var(--pf-global--warning-color--100, #f0ab00); + --pf-c-progress--m-danger__status-icon--Color: var(--pf-global--danger-color--100, #c9190b); + --pf-c-progress--m-inside__indicator--MinWidth: var(--pf-global--spacer--xl, 2rem); + --pf-c-progress--m-inside__measure--Color: var(--pf-global--Color--light-100, #ffffff); + --pf-c-progress--m-success--m-inside__measure--Color: var(--pf-global--Color--light-100, #ffffff); + --pf-c-progress--m-warning--m-inside__measure--Color: var(--pf-global--Color--dark-100); + --pf-c-progress--m-inside__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); + --pf-c-progress--m-outside__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); + --pf-c-progress--m-sm__bar--Height: var(--pf-global--spacer--sm, 0.5rem); + --pf-c-progress--m-sm__description--FontSize: var(--pf-global--FontSize--sm, 0.875rem); + --pf-c-progress--m-sm__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); + --pf-c-progress--m-lg__bar--Height: var(--pf-global--spacer--lg, 1.5rem); + display: grid; + align-items: end; + grid-gap: var(--pf-c-progress--GridGap); + grid-template-columns: auto auto; + grid-template-rows: 1fr auto; +} +.sm { + --pf-c-progress__bar--Height: var(--pf-c-progress--m-sm__bar--Height); + --pf-c-progress__indicator--Height: var(--pf-c-progress--m-sm__bar--Height); +} +.sm .description { + font-size: var(--pf-c-progress--m-sm__description--FontSize); +} +.sm .measure { + font-size: var(--pf-c-progress--m-sm__measure--FontSize); +} +.lg { + --pf-c-progress__bar--Height: var(--pf-c-progress--m-lg__bar--Height); + --pf-c-progress__indicator--Height: var(--pf-c-progress--m-lg__bar--Height); +} +.inside .indicator { + display: flex; + align-items: center; + justify-content: center; + min-width: var(--pf-c-progress--m-inside__indicator--MinWidth); +} +.inside .measure { + font-size: var(--pf-c-progress--m-inside__measure--FontSize); + color: var(--pf-c-progress--m-inside__measure--Color); + text-align: center; +} +.outside .description { + grid-column: 1/3; +} +.outside .status { + grid-column: 2/3; + grid-row: 2/3; + align-self: center; +} +.outside .measure { + display: inline-block; + font-size: var(--pf-c-progress--m-outside__measure--FontSize); +} +.outside __measure.pf-m-static-width { + min-width: var(--pf-c-progress__measure--m-static-width--MinWidth); + text-align: left; +} +.outside .bar, +.outside .indicator { + grid-column: 1/2; +} +.singleline { + grid-template-rows: 1fr; +} +.singleline .description { + display: none; + visibility: hidden; +} +.singleline .bar { + grid-row: 1/2; + grid-column: 1/2; +} +.singleline .status { + grid-row: 1/2; + grid-column: 2/3; +} +.outside, .singleline { + grid-template-columns: 1fr fit-content(50%); +} +.success { + --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-success__bar--BackgroundColor); + --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-success__status-icon--Color); + --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-success--m-inside__measure--Color); +} +.warning { + --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-warning__bar--BackgroundColor); + --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-warning__status-icon--Color); + --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-warning--m-inside__measure--Color); +} +.danger { + --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-danger__bar--BackgroundColor); + --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-danger__status-icon--Color); + --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-danger--m-inside__measure--Color); +} +.description { + word-break: break-word; + grid-column: 1/2; +} +.description.pf-m-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.status { + grid-column: 2/3; + grid-row: 1/2; + text-align: right; + word-break: break-word; + display: flex; + align-items: center; + justify-content: end; +} +pf-icon { + margin-left: var(--pf-c-progress__status-icon--MarginLeft); + color: var(--pf-c-progress__status-icon--Color); +} +.bar { + position: relative; + grid-column: 1/3; + grid-row: 2/3; + align-self: center; + height: var(--pf-c-progress__bar--Height); + background-color: var(--pf-c-progress__bar--BackgroundColor); +} +.bar::before { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + content: ""; + background-color: var(--pf-c-progress__bar--before--BackgroundColor); + opacity: var(--pf-c-progress__bar--before--Opacity); +} +.indicator { + position: absolute; + top: 0; + left: 0; + height: var(--pf-c-progress__indicator--Height); + background-color: var(--pf-c-progress__indicator--BackgroundColor); +} +__helper-text { + grid-column: 1/3; + grid-row: 3/4; + margin-top: var(--pf-c-progress__helper-text--MarginTop); +} +:where(.pf-theme-dark) { + --pf-c-progress--m-inside__measure--Color: var(--pf-global--palette--black-900); + --pf-c-progress--m-success--m-inside__measure--Color: var(--pf-global--palette--black-900); + --pf-c-progress--m-warning--m-inside__measure--Color: var(--pf-global--palette--black-900); +} diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts new file mode 100644 index 0000000000..4890553754 --- /dev/null +++ b/elements/pf-progress/pf-progress.ts @@ -0,0 +1,66 @@ +import { LitElement, html } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { property } from 'lit/decorators/property.js'; + +import styles from './pf-progress.css'; + +/** + * Progress + * @slot - Place element content here + */ +@customElement('pf-progress') +export class PfProgress extends LitElement { + static readonly styles = [styles]; + + @property({ reflect: true, type: Number }) + value = 0; + + @property({ reflect: true }) + title = ''; + + @property({ reflect: true }) + size: 'sm' | 'lg' | '' = ''; + + @property({ reflect: true, attribute: 'measure-location' }) + measureLocation: '' | 'outside' | 'inside' | 'none' = ''; + + @property({ reflect: true }) + variant: '' | 'success' | 'danger' | 'warning' = ''; + + showStatus(status: Array) { + return status.includes(this.measureLocation); + } + + render() { + const { size, measureLocation, variant } = this; + const singleLine = this.title.length === 0 ? 'singleline' : ''; + return html` +
+
${this.title}
+
+ ${this.showStatus(['outside', '']) ? html`${this.value}%` : html``} + ${this.variant ? + html`` + : html`` +} +
+
+
+
${this.showStatus(['inside']) ? html`${this.value}%` : html``}
+
+
+
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'pf-progress': PfProgress; + } +} diff --git a/elements/pf-progress/test/pf-progress.e2e.ts b/elements/pf-progress/test/pf-progress.e2e.ts new file mode 100644 index 0000000000..e19cba99d9 --- /dev/null +++ b/elements/pf-progress/test/pf-progress.e2e.ts @@ -0,0 +1,12 @@ +import { test } from '@playwright/test'; +import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; + +const tagName = 'pf-progress'; + +test.describe(tagName, () => { + test('snapshot', async ({ page }) => { + const componentPage = new PfeDemoPage(page, tagName); + await componentPage.navigate(); + await componentPage.snapshot(); + }); +}); diff --git a/elements/pf-progress/test/pf-progress.spec.ts b/elements/pf-progress/test/pf-progress.spec.ts new file mode 100644 index 0000000000..7aa0c9b1c6 --- /dev/null +++ b/elements/pf-progress/test/pf-progress.spec.ts @@ -0,0 +1,17 @@ +import { expect, html } from '@open-wc/testing'; +import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; +import { PfProgress } from '@patternfly/elements/pf-progress/pf-progress.js'; + +describe('', function() { + describe('simply instantiating', function() { + let element: PfProgress; + it('should upgrade', async function() { + element = await createFixture(html``); + const klass = customElements.get('pf-progress'); + expect(element) + .to.be.an.instanceOf(klass) + .and + .to.be.an.instanceOf(PfProgress); + }); + }); +}); From 58c9cf32aba51c063467b014a3d50e900988a05e Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 1 Jun 2023 10:52:56 -0400 Subject: [PATCH 02/44] fix(progress): adding accessibility fixes for pf-progress without html5 element --- elements/pf-progress/demo/pf-progress.html | 24 +++++++++---------- elements/pf-progress/pf-progress.ts | 28 ++++++++++++++++++++-- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/elements/pf-progress/demo/pf-progress.html b/elements/pf-progress/demo/pf-progress.html index 5fe4d723f2..f5dd8ea9ec 100644 --- a/elements/pf-progress/demo/pf-progress.html +++ b/elements/pf-progress/demo/pf-progress.html @@ -5,37 +5,37 @@

Default:

Small:

- +

Large:

- +

Outside:

- +

Inside:

- +

Success:

- +

Danger:

- +

Warning:

- +

Inside Success:

- +

Outside Danger:

- +

Single Line:

- +

Without Measure:

- +

Danger Without Measure:

- + diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 4890553754..33b4b178d0 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -2,6 +2,7 @@ import { LitElement, html } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; +import { query } from 'lit/decorators/query.js'; import styles from './pf-progress.css'; @@ -19,6 +20,9 @@ export class PfProgress extends LitElement { @property({ reflect: true }) title = ''; + @property({ reflect: true }) + label = ''; + @property({ reflect: true }) size: 'sm' | 'lg' | '' = ''; @@ -28,16 +32,36 @@ export class PfProgress extends LitElement { @property({ reflect: true }) variant: '' | 'success' | 'danger' | 'warning' = ''; + @query('#bar') + bar!: HTMLElement; + showStatus(status: Array) { return status.includes(this.measureLocation); } + async #updateAccessibility() { + !!await this.updateComplete; + + const { bar, value } = this; + bar.setAttribute('aria-valuenow', `${value}`); + if (this.title.length > 0 && this.bar !== null) { + this.bar.setAttribute('aria-labelledby', 'description'); + } else if (this.bar !== null) { + this.bar.setAttribute('aria-label', this.label); + } + } + + connectedCallback() { + super.connectedCallback(); + this.#updateAccessibility(); + } + render() { const { size, measureLocation, variant } = this; const singleLine = this.title.length === 0 ? 'singleline' : ''; return html`
-
${this.title}
+
${this.title}
${this.showStatus(['outside', '']) ? html`${this.value}%` : html``} ${this.variant ? @@ -49,7 +73,7 @@ export class PfProgress extends LitElement { : html`` }
-
+
${this.showStatus(['inside']) ? html`${this.value}%` : html``}
From ca5db3b330b13fd53a5b74a0cc9db9c2961801a2 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 6 Jun 2023 10:32:52 -0400 Subject: [PATCH 03/44] fix: formatting for icons, html --- elements/pf-progress/pf-progress.css | 8 ++--- elements/pf-progress/pf-progress.ts | 44 ++++++++++++++++------------ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index 4075a69f3d..ae12a0530e 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -73,7 +73,7 @@ min-width: var(--pf-c-progress__measure--m-static-width--MinWidth); text-align: left; } -.outside .bar, +.outside #bar, .outside .indicator { grid-column: 1/2; } @@ -84,7 +84,7 @@ display: none; visibility: hidden; } -.singleline .bar { +.singleline #bar { grid-row: 1/2; grid-column: 1/2; } @@ -132,7 +132,7 @@ pf-icon { margin-left: var(--pf-c-progress__status-icon--MarginLeft); color: var(--pf-c-progress__status-icon--Color); } -.bar { +#bar { position: relative; grid-column: 1/3; grid-row: 2/3; @@ -140,7 +140,7 @@ pf-icon { height: var(--pf-c-progress__bar--Height); background-color: var(--pf-c-progress__bar--BackgroundColor); } -.bar::before { +#bar::before { position: absolute; top: 0; left: 0; diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 33b4b178d0..ea6a66fc89 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -3,9 +3,17 @@ import { classMap } from 'lit/directives/class-map.js'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { query } from 'lit/decorators/query.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { styleMap } from 'lit/directives/style-map.js'; import styles from './pf-progress.css'; +const ICONS = new Map(Object.entries({ + success: { icon: 'circle-check' }, + danger: { icon: 'circle-xmark' }, + warning: { icon: 'triangle-exclamation' } +})); + /** * Progress * @slot - Place element content here @@ -35,8 +43,8 @@ export class PfProgress extends LitElement { @query('#bar') bar!: HTMLElement; - showStatus(status: Array) { - return status.includes(this.measureLocation); + #showInsideStatus() { + return this.measureLocation === 'inside'; } async #updateAccessibility() { @@ -45,7 +53,7 @@ export class PfProgress extends LitElement { const { bar, value } = this; bar.setAttribute('aria-valuenow', `${value}`); if (this.title.length > 0 && this.bar !== null) { - this.bar.setAttribute('aria-labelledby', 'description'); + this.bar.setAttribute('aria-labelledby', 'title'); } else if (this.bar !== null) { this.bar.setAttribute('aria-label', this.label); } @@ -57,25 +65,25 @@ export class PfProgress extends LitElement { } render() { - const { size, measureLocation, variant } = this; - const singleLine = this.title.length === 0 ? 'singleline' : ''; + const { size, measureLocation, variant, value, title } = this; + const icon = variant && ICONS.get(variant)?.icon; + const singleLine = title.length === 0 ? 'singleline' : ''; + return html`
-
${this.title}
+
${title}
- ${this.showStatus(['outside', '']) ? html`${this.value}%` : html``} - ${this.variant ? - html`` - : html`` -} + ${html`${!this.#showInsideStatus() ? `${value}%` : ''}`} +
-
-
-
${this.showStatus(['inside']) ? html`${this.value}%` : html``}
+
+
+
+ ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} +
From 87a96707aca76f0f69c7519ccf3e9836fbac5078 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 6 Jun 2023 10:38:16 -0400 Subject: [PATCH 04/44] docs(progress): adding kitchen sink, adding example --- elements/pf-progress/demo/kitchen-sink.html | 41 +++++++++++++++++++++ elements/pf-progress/demo/pf-progress.html | 18 --------- elements/pf-progress/docs/pf-progress.md | 2 +- 3 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 elements/pf-progress/demo/kitchen-sink.html diff --git a/elements/pf-progress/demo/kitchen-sink.html b/elements/pf-progress/demo/kitchen-sink.html new file mode 100644 index 0000000000..f5dd8ea9ec --- /dev/null +++ b/elements/pf-progress/demo/kitchen-sink.html @@ -0,0 +1,41 @@ + + + +

Default:

+ + +

Small:

+ + +

Large:

+ + +

Outside:

+ + +

Inside:

+ + +

Success:

+ + +

Danger:

+ + +

Warning:

+ + +

Inside Success:

+ + +

Outside Danger:

+ + +

Single Line:

+ + +

Without Measure:

+ + +

Danger Without Measure:

+ diff --git a/elements/pf-progress/demo/pf-progress.html b/elements/pf-progress/demo/pf-progress.html index f5dd8ea9ec..29342b231e 100644 --- a/elements/pf-progress/demo/pf-progress.html +++ b/elements/pf-progress/demo/pf-progress.html @@ -4,9 +4,6 @@

Default:

-

Small:

- -

Large:

@@ -24,18 +21,3 @@

Danger:

Warning:

- -

Inside Success:

- - -

Outside Danger:

- - -

Single Line:

- - -

Without Measure:

- - -

Danger Without Measure:

- diff --git a/elements/pf-progress/docs/pf-progress.md b/elements/pf-progress/docs/pf-progress.md index 64bf1ef68e..1535ab49c0 100644 --- a/elements/pf-progress/docs/pf-progress.md +++ b/elements/pf-progress/docs/pf-progress.md @@ -1,5 +1,5 @@ {% renderOverview %} - + {% endrenderOverview %} {% band header="Usage" %}{% endband %} From 4920adc4fe6927958ceb1fe9437ad6b89331e264 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 6 Jun 2023 11:34:18 -0400 Subject: [PATCH 05/44] docs(progress): adding cssprop, summary, kitchen sink demo --- elements/pf-progress/README.md | 33 ++++++- elements/pf-progress/demo/demo.css | 3 - elements/pf-progress/demo/kitchen-sink.html | 1 - elements/pf-progress/demo/pf-progress.html | 1 - elements/pf-progress/pf-progress.css | 17 ---- elements/pf-progress/pf-progress.ts | 104 +++++++++++++++++++- 6 files changed, 129 insertions(+), 30 deletions(-) diff --git a/elements/pf-progress/README.md b/elements/pf-progress/README.md index 300a11fc4e..baefb3bfad 100644 --- a/elements/pf-progress/README.md +++ b/elements/pf-progress/README.md @@ -1,11 +1,34 @@ # Progress -Add a description of the component here. -## Usage -Describe how best to use this web component along with best practices. +A progress bar gives the user a visual representation of their completion status of an ongoing process or task. + +Read more about Progress Stepper in the [PatternFly Elements Progress +documentation][docs]. + +## Installation + +Load `` via CDN: ```html - + +``` + +Or, if you are using [NPM](https://npm.im), install it - +```bash +npm install @patternfly/elements ``` + +Then once installed, import it to your application: + +```js +import '@patternfly/elements/pf-progress/pf-progress.js'; +``` + +## Usage + +```html + +``` + +[docs]: https://patternflyelements.org/components/progress diff --git a/elements/pf-progress/demo/demo.css b/elements/pf-progress/demo/demo.css index ee35300913..e69de29bb2 100644 --- a/elements/pf-progress/demo/demo.css +++ b/elements/pf-progress/demo/demo.css @@ -1,3 +0,0 @@ -pf-progress { - /* insert demo styles */ -} diff --git a/elements/pf-progress/demo/kitchen-sink.html b/elements/pf-progress/demo/kitchen-sink.html index f5dd8ea9ec..6e76107a19 100644 --- a/elements/pf-progress/demo/kitchen-sink.html +++ b/elements/pf-progress/demo/kitchen-sink.html @@ -1,4 +1,3 @@ -

Default:

diff --git a/elements/pf-progress/demo/pf-progress.html b/elements/pf-progress/demo/pf-progress.html index 29342b231e..d5e5b0a1dd 100644 --- a/elements/pf-progress/demo/pf-progress.html +++ b/elements/pf-progress/demo/pf-progress.html @@ -1,4 +1,3 @@ -

Default:

diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index ae12a0530e..404df9e8ea 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -3,13 +3,11 @@ --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100, #06c); --pf-c-progress__bar--Height: var(--pf-global--spacer--md, 1rem); --pf-c-progress__bar--BackgroundColor: var(--pf-global--BackgroundColor--light-100, #ffffff); - --pf-c-progress__measure--m-static-width--MinWidth: 4.5ch; --pf-c-progress__status-icon--Color: var(--pf-global--Color--100, #151515); --pf-c-progress__status-icon--MarginLeft: var(--pf-global--spacer--sm, 0.5rem); --pf-c-progress__bar--before--Opacity: .2; --pf-c-progress__indicator--Height: var(--pf-c-progress__bar--Height); --pf-c-progress__indicator--BackgroundColor: var(--pf-c-progress__bar--before--BackgroundColor); - --pf-c-progress__helper-text--MarginTop: calc(var(--pf-global--spacer--xs, 0.25rem) - var(--pf-c-progress--GridGap)); --pf-c-progress--m-success__bar--BackgroundColor: var(--pf-global--success-color--100, #3e8635); --pf-c-progress--m-warning__bar--BackgroundColor: var(--pf-global--warning-color--100, #f0ab00); --pf-c-progress--m-danger__bar--BackgroundColor: var(--pf-global--danger-color--100, #c9190b); @@ -19,7 +17,6 @@ --pf-c-progress--m-inside__indicator--MinWidth: var(--pf-global--spacer--xl, 2rem); --pf-c-progress--m-inside__measure--Color: var(--pf-global--Color--light-100, #ffffff); --pf-c-progress--m-success--m-inside__measure--Color: var(--pf-global--Color--light-100, #ffffff); - --pf-c-progress--m-warning--m-inside__measure--Color: var(--pf-global--Color--dark-100); --pf-c-progress--m-inside__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); --pf-c-progress--m-outside__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); --pf-c-progress--m-sm__bar--Height: var(--pf-global--spacer--sm, 0.5rem); @@ -69,10 +66,6 @@ display: inline-block; font-size: var(--pf-c-progress--m-outside__measure--FontSize); } -.outside __measure.pf-m-static-width { - min-width: var(--pf-c-progress__measure--m-static-width--MinWidth); - text-align: left; -} .outside #bar, .outside .indicator { grid-column: 1/2; @@ -157,13 +150,3 @@ pf-icon { height: var(--pf-c-progress__indicator--Height); background-color: var(--pf-c-progress__indicator--BackgroundColor); } -__helper-text { - grid-column: 1/3; - grid-row: 3/4; - margin-top: var(--pf-c-progress__helper-text--MarginTop); -} -:where(.pf-theme-dark) { - --pf-c-progress--m-inside__measure--Color: var(--pf-global--palette--black-900); - --pf-c-progress--m-success--m-inside__measure--Color: var(--pf-global--palette--black-900); - --pf-c-progress--m-warning--m-inside__measure--Color: var(--pf-global--palette--black-900); -} diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index ea6a66fc89..4424ac97ba 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -15,8 +15,106 @@ const ICONS = new Map(Object.entries({ })); /** - * Progress - * @slot - Place element content here + * A progress bar gives the user a visual representation of their completion status of an ongoing process or task. + * + * @summary Display completion status of ongoing process or task. + * + * @cssprop {} --pf-c-progress--GridGap + * Gap between the sections of the progress bar. + * {@default `1rem`} + * + * @cssprop {} --pf-c-progress__bar--before--BackgroundColor + * Color of the progress bar. + * {@default `#06c`} + * + * @cssprop {} --pf-c-progress__bar--Height + * Height of the progress bar. + * {@default `1rem`} + * + * @cssprop {} --pf-c-progress__bar--BackgroundColor + * Background color of the progress bar. + * {@default `#ffffff`} + * + * @cssprop {} --pf-c-progress__status-icon--Color + * Color of the status icon. + * {@default `#151515`} + * + * @cssprop {} --pf-c-progress__status-icon--MarginLeft + * Margin left of the status icon. + * {@default `0.5rem`} + * + * @cssprop {} --pf-c-progress__bar--before--Opacity + * Opacity of the progress bar. + * {@default `.2`} + * + * @cssprop {} --pf-c-progress__indicator--Height + * Height of the progress bar indicator. + * {@default `1rem`} + * + * @cssprop {} --pf-c-progress__indicator--BackgroundColor + * Background color of the progress bar indicator. + * {@default `#ffffff`} + * + * @cssprop {} --pf-c-progress--m-success__bar--BackgroundColor + * Background color of the progress bar when variant is success. + * {@default `#3e8635`} + * + * @cssprop {} --pf-c-progress--m-warning__bar--BackgroundColor + * Background color of the progress bar when variant is warning. + * {@default `#f0ab00`} + * + * @cssprop {} --pf-c-progress--m-danger__bar--BackgroundColor + * Background color of the progress bar when variant is danger. + * {@default `#c9190b`} + * + * @cssprop {} --pf-c-progress--m-success__status-icon--Color + * Color of the status icon when variant is success. + * {@default `#3e8635`} + * + * @cssprop {} --pf-c-progress--m-warning__status-icon--Color + * Color of the status icon when variant is warning. + * {@default `#f0ab00`} + * + * @cssprop {} --pf-c-progress--m-danger__status-icon--Color + * Color of the status icon when variant is danger. + * {@default `#c9190b`} + * + * @cssprop {} --pf-c-progress--m-inside__indicator--MinWidth + * Minimum width of the progress bar indicator when measure location is inside. + * {@default `2rem`} + * + * @cssprop {} --pf-c-progress--m-inside__measure--Color + * Color of the progress bar measure when measure location is inside. + * {@default `#ffffff`} + * + * @cssprop {} --pf-c-progress--m-success--m-inside__measure--Color + * Color of the progress bar measure when variant is success and measure location is inside. + * {@default `#ffffff`} + * + * @cssprop {} --pf-c-progress--m-inside__measure--FontSize + * Font size of the progress bar measure when measure location is inside. + * {@default `0.875rem`} + * + * @cssprop {} --pf-c-progress--m-outside__measure--FontSize + * Font size of the progress bar measure when measure location is outside. + * {@default `0.875rem`} + * + * @cssprop {} --pf-c-progress--m-sm__bar--Height + * Height of the progress bar when the size is small. + * {@default `0.5rem`} + * + * @cssprop {} --pf-c-progress--m-sm__description--FontSize + * Font size of the progress bar description when the size is small. + * {@default `0.875rem`} + * + * @cssprop {} --pf-c-progress--m-sm__measure--FontSize + * Font size of the progress bar measure when the size is small. + * {@default `0.875rem`} + * + * @cssprop {} --pf-c-progress--m-lg__bar--Height + * Height of the progress bar when the size is large. + * {@default `1.5rem`} + * */ @customElement('pf-progress') export class PfProgress extends LitElement { @@ -70,7 +168,7 @@ export class PfProgress extends LitElement { const singleLine = title.length === 0 ? 'singleline' : ''; return html` -
+
${title}
${html`${!this.#showInsideStatus() ? `${value}%` : ''}`} From 1ac5001ecc09d1189eb6099c609f3cfbaa449fd7 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 6 Jun 2023 11:34:57 -0400 Subject: [PATCH 06/44] fix(progress): remove demo css file --- elements/pf-progress/demo/demo.css | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 elements/pf-progress/demo/demo.css diff --git a/elements/pf-progress/demo/demo.css b/elements/pf-progress/demo/demo.css deleted file mode 100644 index e69de29bb2..0000000000 From e800261d30960d1b6579309f3df8a2509c1d402f Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 6 Jun 2023 11:41:47 -0400 Subject: [PATCH 07/44] chore: adding changeset --- .changeset/rich-kangaroos-brake.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/rich-kangaroos-brake.md diff --git a/.changeset/rich-kangaroos-brake.md b/.changeset/rich-kangaroos-brake.md new file mode 100644 index 0000000000..37d6bb82fa --- /dev/null +++ b/.changeset/rich-kangaroos-brake.md @@ -0,0 +1,9 @@ +--- +"@patternfly/elements": minor +--- + +✨ Added `` + +```html + +``` From b03d2b7496f6cfd99111fbae24cdde5303f3538f Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Wed, 7 Jun 2023 15:08:04 -0400 Subject: [PATCH 08/44] test: adding test cases for pf-progress --- elements/pf-progress/test/pf-progress.spec.ts | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/elements/pf-progress/test/pf-progress.spec.ts b/elements/pf-progress/test/pf-progress.spec.ts index 7aa0c9b1c6..fc53c01315 100644 --- a/elements/pf-progress/test/pf-progress.spec.ts +++ b/elements/pf-progress/test/pf-progress.spec.ts @@ -1,17 +1,24 @@ -import { expect, html } from '@open-wc/testing'; -import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; +import { expect, html, fixture } from '@open-wc/testing'; import { PfProgress } from '@patternfly/elements/pf-progress/pf-progress.js'; describe('', function() { - describe('simply instantiating', function() { - let element: PfProgress; - it('should upgrade', async function() { - element = await createFixture(html``); - const klass = customElements.get('pf-progress'); - expect(element) - .to.be.an.instanceOf(klass) - .and - .to.be.an.instanceOf(PfProgress); - }); + let element: PfProgress; + + beforeEach(async function() { + element = await fixture(html` + + + `); + }); + + it('should upgrade', async function() { + const klass = customElements.get('pf-progress'); + expect(element).to.be.an.instanceOf(klass).and.to.be.an.instanceOf(PfProgress); + }); + + it('should be accessible', async function() { + await expect(element).shadowDom.to.be.accessible(); }); }); From fe0c283820d99ff57ddb81cf4d482c174ef649c8 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Mon, 26 Jun 2023 17:08:48 -0400 Subject: [PATCH 09/44] chore: checkpoint --- elements/pf-progress/demo/pf-progress.html | 35 ++++++++++------- elements/pf-progress/pf-progress.css | 44 +++++++++++++++++++++- elements/pf-progress/pf-progress.ts | 27 ++++++++++--- 3 files changed, 86 insertions(+), 20 deletions(-) diff --git a/elements/pf-progress/demo/pf-progress.html b/elements/pf-progress/demo/pf-progress.html index d5e5b0a1dd..b7367295b6 100644 --- a/elements/pf-progress/demo/pf-progress.html +++ b/elements/pf-progress/demo/pf-progress.html @@ -1,22 +1,31 @@

Default:

- + + -

Large:

- -

Outside:

- +

Progress:

+ + -

Inside:

- +

Meter:

+ + + + -

Success:

- + + -

Danger:

- + + -

Warning:

- + + + + + + + + diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index 404df9e8ea..4c27a51959 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -1,6 +1,6 @@ .container { --pf-c-progress--GridGap: var(--pf-global--spacer--md, 1rem); - --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100, #06c); + --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100, #0066cc); --pf-c-progress__bar--Height: var(--pf-global--spacer--md, 1rem); --pf-c-progress__bar--BackgroundColor: var(--pf-global--BackgroundColor--light-100, #ffffff); --pf-c-progress__status-icon--Color: var(--pf-global--Color--100, #151515); @@ -150,3 +150,45 @@ pf-icon { height: var(--pf-c-progress__indicator--Height); background-color: var(--pf-c-progress__indicator--BackgroundColor); } + +meter { + display: block; + margin: 0 auto; + width: 100%; + height: var(--pf-c-progress__bar--Height); + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + background: none; + background-color: #0066cc33; +} + +meter::-webkit-meter-bar { + background: none; + background-color: blue; + /* box-shadow: 0 5px 5px -5px #333 inset; */ +} + +meter::-moz-meter-bar { + background: none; + background-color: green; + background-size: 100% 100%; +} + +.measure { + width: 100%; + height: var(--pf-c-progress__bar--Height); + + display: block; +} + +.measure > span { + height: inherit; + background-color: var(--pf-c-progress__bar--before--BackgroundColor); + background-size: 100% 100%; + display: block; + text-index: -9999px; +} + diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 4424ac97ba..2675d46205 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -135,6 +135,9 @@ export class PfProgress extends LitElement { @property({ reflect: true, attribute: 'measure-location' }) measureLocation: '' | 'outside' | 'inside' | 'none' = ''; + @property({ reflect: true }) + markdown: 'html' | 'progress' | 'meter' = 'html'; + @property({ reflect: true }) variant: '' | 'success' | 'danger' | 'warning' = ''; @@ -163,7 +166,7 @@ export class PfProgress extends LitElement { } render() { - const { size, measureLocation, variant, value, title } = this; + const { size, measureLocation, variant, value, title, markdown } = this; const icon = variant && ICONS.get(variant)?.icon; const singleLine = title.length === 0 ? 'singleline' : ''; @@ -177,13 +180,25 @@ export class PfProgress extends LitElement { ?hidden="${!icon}" icon="${ifDefined(icon)}">
-
-
-
- ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} + ${markdown === 'html' ? html` +
+
+
+ ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} +
-
+ ` : markdown === 'progress' ? + html`` + : html` + +
+ + ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} + +
+
+ `}
`; } From b3716545dde6417f068660b8784170ca81ae5956 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 27 Jun 2023 12:23:56 -0400 Subject: [PATCH 10/44] feat: kitchen sink demo fixing, adding opacity, progress, meter styling --- elements/pf-progress/demo/kitchen-sink.html | 11 +- elements/pf-progress/demo/kitchen-sink.js | 13 +++ elements/pf-progress/pf-progress.css | 123 +++++++++++++++++--- elements/pf-progress/pf-progress.ts | 14 +-- 4 files changed, 133 insertions(+), 28 deletions(-) create mode 100644 elements/pf-progress/demo/kitchen-sink.js diff --git a/elements/pf-progress/demo/kitchen-sink.html b/elements/pf-progress/demo/kitchen-sink.html index 6e76107a19..7168cefe73 100644 --- a/elements/pf-progress/demo/kitchen-sink.html +++ b/elements/pf-progress/demo/kitchen-sink.html @@ -1,4 +1,13 @@ - + + + + + + + + + +

Default:

diff --git a/elements/pf-progress/demo/kitchen-sink.js b/elements/pf-progress/demo/kitchen-sink.js new file mode 100644 index 0000000000..45e24507e7 --- /dev/null +++ b/elements/pf-progress/demo/kitchen-sink.js @@ -0,0 +1,13 @@ +import '@patternfly/elements/pf-progress/pf-progress.js'; + +const progressElements = document.querySelectorAll('pf-progress'); + +function toggleMarkdown(event) { + progressElements.forEach(element => { + element.markdown = event.target.value; + }); +} + +for (const input of document.querySelectorAll('input[name="example_markdown"]')) { + input.addEventListener('change', toggleMarkdown); +} diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index 4c27a51959..f4a37b1038 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -1,6 +1,8 @@ .container { --pf-c-progress--GridGap: var(--pf-global--spacer--md, 1rem); --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100, #0066cc); + --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-global--primary-color--100, #0066cc33); + --pf-c-progress__bar--Height: var(--pf-global--spacer--md, 1rem); --pf-c-progress__bar--BackgroundColor: var(--pf-global--BackgroundColor--light-100, #ffffff); --pf-c-progress__status-icon--Color: var(--pf-global--Color--100, #151515); @@ -9,8 +11,14 @@ --pf-c-progress__indicator--Height: var(--pf-c-progress__bar--Height); --pf-c-progress__indicator--BackgroundColor: var(--pf-c-progress__bar--before--BackgroundColor); --pf-c-progress--m-success__bar--BackgroundColor: var(--pf-global--success-color--100, #3e8635); + --pf-c-progress--m-success__bar--BackgroundColorWithOpacity: var(--pf-global--success-color--100, #3e863533); + --pf-c-progress--m-warning__bar--BackgroundColor: var(--pf-global--warning-color--100, #f0ab00); + --pf-c-progress--m-warning__bar--BackgroundColorWithOpacity: var(--pf-global--warning-color--100, #f0ab0033); + --pf-c-progress--m-danger__bar--BackgroundColor: var(--pf-global--danger-color--100, #c9190b); + --pf-c-progress--m-danger__bar--BackgroundColorWithOpacity: var(--pf-global--danger-color--100, #c9190b33); + --pf-c-progress--m-success__status-icon--Color: var(--pf-global--success-color--100, #3e8635); --pf-c-progress--m-warning__status-icon--Color: var(--pf-global--warning-color--100, #f0ab00); --pf-c-progress--m-danger__status-icon--Color: var(--pf-global--danger-color--100, #c9190b); @@ -36,7 +44,7 @@ .sm .description { font-size: var(--pf-c-progress--m-sm__description--FontSize); } -.sm .measure { +.sm .indicator{ font-size: var(--pf-c-progress--m-sm__measure--FontSize); } .lg { @@ -48,12 +56,15 @@ align-items: center; justify-content: center; min-width: var(--pf-c-progress--m-inside__indicator--MinWidth); -} -.inside .measure { font-size: var(--pf-c-progress--m-inside__measure--FontSize); color: var(--pf-c-progress--m-inside__measure--Color); text-align: center; } +/* .inside .measure { */ +/* font-size: var(--pf-c-progress--m-inside__measure--FontSize); */ +/* color: var(--pf-c-progress--m-inside__measure--Color); */ +/* text-align: center; */ +/* } */ .outside .description { grid-column: 1/3; } @@ -62,12 +73,16 @@ grid-row: 2/3; align-self: center; } -.outside .measure { - display: inline-block; - font-size: var(--pf-c-progress--m-outside__measure--FontSize); -} +/* .outside .measure { */ +/* display: inline-block; */ +/* font-size: var(--pf-c-progress--m-outside__measure--FontSize); */ +/* } */ .outside #bar, +.outside meter, +.outside progress, .outside .indicator { + display: inline-block; + font-size: var(--pf-c-progress--m-outside__measure--FontSize); grid-column: 1/2; } .singleline { @@ -77,7 +92,9 @@ display: none; visibility: hidden; } -.singleline #bar { +.singleline #bar, +.singleline meter, +.singleline progress { grid-row: 1/2; grid-column: 1/2; } @@ -90,16 +107,19 @@ } .success { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-success__bar--BackgroundColor); + --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-c-progress--m-success__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-success__status-icon--Color); --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-success--m-inside__measure--Color); } .warning { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-warning__bar--BackgroundColor); + --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-c-progress--m-warning__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-warning__status-icon--Color); --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-warning--m-inside__measure--Color); } .danger { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-danger__bar--BackgroundColor); + --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-c-progress--m-danger__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-danger__status-icon--Color); --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-danger--m-inside__measure--Color); } @@ -125,7 +145,9 @@ pf-icon { margin-left: var(--pf-c-progress__status-icon--MarginLeft); color: var(--pf-c-progress__status-icon--Color); } -#bar { +#bar, +meter, +progress { position: relative; grid-column: 1/3; grid-row: 2/3; @@ -162,33 +184,98 @@ meter { appearance: none; background: none; - background-color: #0066cc33; + background-color: var(--pf-c-progress__bar--before--BackgroundColorWithOpacity); } -meter::-webkit-meter-bar { +meter::-moz-meter-bar { background: none; - background-color: blue; - /* box-shadow: 0 5px 5px -5px #333 inset; */ + background-color: var(--pf-c-progress__bar--before--BackgroundColor); + background-size: 100% 100%; } -meter::-moz-meter-bar { +meter::-webkit-meter-bar { background: none; - background-color: green; + background-image: linear-gradient( 90deg, + var(--pf-c-progress__bar--before--BackgroundColorWithOpacity) 100%, + var(--pf-c-progress__bar--before--BackgroundColorWithOpacity) 100%); background-size: 100% 100%; } -.measure { + +meter::-webkit-meter-optimum-value { + background-image: linear-gradient( 90deg, + var(--pf-c-progress__bar--before--BackgroundColor) 100%, + var(--pf-c-progress__bar--before--BackgroundColor) 100%); + background-size: 100% 100%; +} + +.indicator, +meter { width: 100%; height: var(--pf-c-progress__bar--Height); display: block; } -.measure > span { +meter > span +{ height: inherit; background-color: var(--pf-c-progress__bar--before--BackgroundColor); background-size: 100% 100%; display: block; - text-index: -9999px; + /* text-index: -9999px; */ } +meter::after { + content: attr(value); + position: relative; + top: 0; + left: 0; +} + +span { + grid-area: 1 / 1 / 3 / 3; + height: var(--pf-c-progress__bar--Height); + font-size: var(--pf-c-progress--m-inside__measure--FontSize); +} + +span::after { + content: attr(data-value); + position: relative; + top: -5px; + left: 50%; +} + +progress[value] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + background: var(--pf-c-progress__bar--before--BackgroundColorWithOpacity); + + width: 100%; + height: var(--pf-c-progress__bar--Height); +} + +progress:not([value]) { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +progress[value]::-webkit-progress-bar +{ + background: var(--pf-c-progress__bar--before--BackgroundColorWithOpacity); +} + +progress[value]::-moz-progress-bar { + background: var(--pf-c-progress__bar--before--BackgroundColor); +} + +progress[value]::-webkit-progress-value { + background-image: linear-gradient( 90deg, + var(--pf-c-progress__bar--before--BackgroundColor) 100%, + var(--pf-c-progress__bar--before--BackgroundColor) 100%); + + background-size: 100% 100%; +} diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 2675d46205..199702c61c 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -183,21 +183,17 @@ export class PfProgress extends LitElement { ${markdown === 'html' ? html`
-
${html`${this.#showInsideStatus() ? `${value}%` : ''}`} -
` : markdown === 'progress' ? - html`` + html`` : html` -
- - ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} - -
-
+ + + ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} + `}
`; From 0284fa9aeab38269cb11c656354146b54a4c3472 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Wed, 28 Jun 2023 17:12:44 -0400 Subject: [PATCH 11/44] feat(progress): progress html5 element, updating tabindex and aria values, cleaning up css --- elements/pf-progress/demo/accessibility.html | 23 +++ elements/pf-progress/demo/kitchen-sink.css | 4 + elements/pf-progress/demo/kitchen-sink.html | 148 ++++++++++++++----- elements/pf-progress/demo/kitchen-sink.js | 13 -- elements/pf-progress/pf-progress.css | 112 ++------------ elements/pf-progress/pf-progress.ts | 115 ++++++++------ 6 files changed, 222 insertions(+), 193 deletions(-) create mode 100644 elements/pf-progress/demo/accessibility.html create mode 100644 elements/pf-progress/demo/kitchen-sink.css delete mode 100644 elements/pf-progress/demo/kitchen-sink.js diff --git a/elements/pf-progress/demo/accessibility.html b/elements/pf-progress/demo/accessibility.html new file mode 100644 index 0000000000..b5ec0555f0 --- /dev/null +++ b/elements/pf-progress/demo/accessibility.html @@ -0,0 +1,23 @@ + + +

Labelled

+ + + +

Danger Labelled

+ + + +

Danger Labelled w/ inside measure

+ + + +

Danger Titled

+ + +

With title

+ + +

Fancy label title

+ + \ No newline at end of file diff --git a/elements/pf-progress/demo/kitchen-sink.css b/elements/pf-progress/demo/kitchen-sink.css new file mode 100644 index 0000000000..6271c537ff --- /dev/null +++ b/elements/pf-progress/demo/kitchen-sink.css @@ -0,0 +1,4 @@ +pf-progress { + padding-bottom: 0.25rem; + display: block; +} \ No newline at end of file diff --git a/elements/pf-progress/demo/kitchen-sink.html b/elements/pf-progress/demo/kitchen-sink.html index 7168cefe73..df401d0432 100644 --- a/elements/pf-progress/demo/kitchen-sink.html +++ b/elements/pf-progress/demo/kitchen-sink.html @@ -1,49 +1,131 @@ - + + - - +

pf-progress

- - +

Default States

- - + -

Default:

- +

Value

+ -

Small:

- +

Title

+ -

Large:

- +

Aria-label

+ -

Outside:

- +

Max

+ -

Inside:

- +

Min

+ -

Success:

- +

Size (sm, lg)

+ + -

Danger:

- +

Measure Location (Inside, Outside, None)

+ + + -

Warning:

- +

Variant (Sucess, danger, warning)

+ + + -

Inside Success:

- +

Variant (Success, Danger, Warning) and Size (sm, lg)

+ + + + + + -

Outside Danger:

- +

Variant (Success, Danger, Warning) and Measure Location (Inside, Outside, None)

+ + + + + + + + + -

Single Line:

- +

Variant (Success, Danger, Warning), Size (sm, lg) and Measure Location (Inside, Outside, None)

+ + + + + + + + + + + + + + + + + + -

Without Measure:

- +

Label w/ no title

+ +

Value

+ + + + +

Size (sm, lg)

+ + + + + + + +

Measure Location (Inside, Outside)

+ + + + + + + +

Variant (Sucess, danger, warning)

+ + + + + + + + + + +

Variant (Success, Danger, Warning) and Size (sm, lg)

+ + + + + + + + + + + + + + + + + + -

Danger Without Measure:

- diff --git a/elements/pf-progress/demo/kitchen-sink.js b/elements/pf-progress/demo/kitchen-sink.js deleted file mode 100644 index 45e24507e7..0000000000 --- a/elements/pf-progress/demo/kitchen-sink.js +++ /dev/null @@ -1,13 +0,0 @@ -import '@patternfly/elements/pf-progress/pf-progress.js'; - -const progressElements = document.querySelectorAll('pf-progress'); - -function toggleMarkdown(event) { - progressElements.forEach(element => { - element.markdown = event.target.value; - }); -} - -for (const input of document.querySelectorAll('input[name="example_markdown"]')) { - input.addEventListener('change', toggleMarkdown); -} diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index f4a37b1038..bde9adae72 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -44,27 +44,10 @@ .sm .description { font-size: var(--pf-c-progress--m-sm__description--FontSize); } -.sm .indicator{ - font-size: var(--pf-c-progress--m-sm__measure--FontSize); -} .lg { --pf-c-progress__bar--Height: var(--pf-c-progress--m-lg__bar--Height); --pf-c-progress__indicator--Height: var(--pf-c-progress--m-lg__bar--Height); } -.inside .indicator { - display: flex; - align-items: center; - justify-content: center; - min-width: var(--pf-c-progress--m-inside__indicator--MinWidth); - font-size: var(--pf-c-progress--m-inside__measure--FontSize); - color: var(--pf-c-progress--m-inside__measure--Color); - text-align: center; -} -/* .inside .measure { */ -/* font-size: var(--pf-c-progress--m-inside__measure--FontSize); */ -/* color: var(--pf-c-progress--m-inside__measure--Color); */ -/* text-align: center; */ -/* } */ .outside .description { grid-column: 1/3; } @@ -73,14 +56,8 @@ grid-row: 2/3; align-self: center; } -/* .outside .measure { */ -/* display: inline-block; */ -/* font-size: var(--pf-c-progress--m-outside__measure--FontSize); */ -/* } */ -.outside #bar, -.outside meter, .outside progress, -.outside .indicator { +.outside span { display: inline-block; font-size: var(--pf-c-progress--m-outside__measure--FontSize); grid-column: 1/2; @@ -88,13 +65,12 @@ .singleline { grid-template-rows: 1fr; } -.singleline .description { +.singleline .title { display: none; visibility: hidden; } -.singleline #bar, -.singleline meter, -.singleline progress { +.singleline progress, +.singleline span { grid-row: 1/2; grid-column: 1/2; } @@ -145,8 +121,6 @@ pf-icon { margin-left: var(--pf-c-progress__status-icon--MarginLeft); color: var(--pf-c-progress__status-icon--Color); } -#bar, -meter, progress { position: relative; grid-column: 1/3; @@ -155,16 +129,6 @@ progress { height: var(--pf-c-progress__bar--Height); background-color: var(--pf-c-progress__bar--BackgroundColor); } -#bar::before { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - content: ""; - background-color: var(--pf-c-progress__bar--before--BackgroundColor); - opacity: var(--pf-c-progress__bar--before--Opacity); -} .indicator { position: absolute; top: 0; @@ -173,77 +137,25 @@ progress { background-color: var(--pf-c-progress__indicator--BackgroundColor); } -meter { - display: block; - margin: 0 auto; - width: 100%; - height: var(--pf-c-progress__bar--Height); - - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - - background: none; - background-color: var(--pf-c-progress__bar--before--BackgroundColorWithOpacity); -} - -meter::-moz-meter-bar { - background: none; - background-color: var(--pf-c-progress__bar--before--BackgroundColor); - background-size: 100% 100%; -} -meter::-webkit-meter-bar { - background: none; - background-image: linear-gradient( 90deg, - var(--pf-c-progress__bar--before--BackgroundColorWithOpacity) 100%, - var(--pf-c-progress__bar--before--BackgroundColorWithOpacity) 100%); - background-size: 100% 100%; -} - - -meter::-webkit-meter-optimum-value { - background-image: linear-gradient( 90deg, - var(--pf-c-progress__bar--before--BackgroundColor) 100%, - var(--pf-c-progress__bar--before--BackgroundColor) 100%); - background-size: 100% 100%; -} - -.indicator, -meter { +.indicator { width: 100%; height: var(--pf-c-progress__bar--Height); display: block; } -meter > span -{ - height: inherit; - background-color: var(--pf-c-progress__bar--before--BackgroundColor); - background-size: 100% 100%; - display: block; - /* text-index: -9999px; */ -} - -meter::after { - content: attr(value); - position: relative; - top: 0; - left: 0; -} - -span { - grid-area: 1 / 1 / 3 / 3; - height: var(--pf-c-progress__bar--Height); - font-size: var(--pf-c-progress--m-inside__measure--FontSize); +span { + grid-column: 1/3; + grid-row: 2/3; + text-align: center; + color: var(--pf-c-progress--m-success--m-inside__measure--Color); } span::after { content: attr(data-value); position: relative; - top: -5px; - left: 50%; + height: 100%; } progress[value] { @@ -278,4 +190,4 @@ progress[value]::-webkit-progress-value { var(--pf-c-progress__bar--before--BackgroundColor) 100%); background-size: 100% 100%; -} +} \ No newline at end of file diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 199702c61c..7cd93f3782 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -6,6 +6,8 @@ import { query } from 'lit/decorators/query.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; +import { Logger } from '@patternfly/pfe-core/controllers/logger.js'; + import styles from './pf-progress.css'; const ICONS = new Map(Object.entries({ @@ -120,83 +122,102 @@ const ICONS = new Map(Object.entries({ export class PfProgress extends LitElement { static readonly styles = [styles]; + static readonly formAssociated = true; + + #calculatedPercentage = 0; + + #logger = new Logger(this); + @property({ reflect: true, type: Number }) value = 0; - @property({ reflect: true }) + @property() title = ''; - @property({ reflect: true }) - label = ''; + @property({ attribute: 'aria-label' }) + ariaLabel = ''; + + @property({ type: Number }) + max = 100; + + @property({ type: Number }) + min = 0; - @property({ reflect: true }) + @property() size: 'sm' | 'lg' | '' = ''; @property({ reflect: true, attribute: 'measure-location' }) measureLocation: '' | 'outside' | 'inside' | 'none' = ''; - @property({ reflect: true }) - markdown: 'html' | 'progress' | 'meter' = 'html'; - - @property({ reflect: true }) + @property() variant: '' | 'success' | 'danger' | 'warning' = ''; - @query('#bar') - bar!: HTMLElement; + @query('progress') + progressElement!: HTMLProgressElement; #showInsideStatus() { return this.measureLocation === 'inside'; } - async #updateAccessibility() { - !!await this.updateComplete; - - const { bar, value } = this; - bar.setAttribute('aria-valuenow', `${value}`); - if (this.title.length > 0 && this.bar !== null) { - this.bar.setAttribute('aria-labelledby', 'title'); - } else if (this.bar !== null) { - this.bar.setAttribute('aria-label', this.label); + #calculatePercentage() { + const { value, max, min } = this; + if (value === null ) { + this.#logger.warn(`A progress element requires a value attribute.`); + return; } + const percentage = (value - min) / (max - min); + this.#calculatedPercentage = Math.round(percentage * 100); } - connectedCallback() { + connectedCallback(): void { super.connectedCallback(); + this.#calculatePercentage(); this.#updateAccessibility(); } + #updateAccessibility() { + const { value, title, ariaLabel, max, progressElement } = this; + if (progressElement) { + progressElement.setAttribute('aria-valuemin', '0'); + if (title || ariaLabel) { + progressElement.setAttribute('aria-label', `${title ? title : ariaLabel}`); + } + if (max != null) { + progressElement.setAttribute('aria-valuemax', `${max}`); + } + if (value) { + progressElement.setAttribute('aria-valuenow', `${value}`); + } + } + } + render() { - const { size, measureLocation, variant, value, title, markdown } = this; + const { size, measureLocation, variant, title } = this; const icon = variant && ICONS.get(variant)?.icon; const singleLine = title.length === 0 ? 'singleline' : ''; return html` -
-
${title}
-
- ${html`${!this.#showInsideStatus() ? `${value}%` : ''}`} - -
- ${markdown === 'html' ? html` -
-
- ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} -
-
- ` : markdown === 'progress' ? - html`` - : html` - - - - ${html`${this.#showInsideStatus() ? `${value}%` : ''}`} - - `} -
- `; +
+ + ${title ? + html` +
${title}
` : ''} + + ${measureLocation !== 'none' ? html`
+ ${html`${!this.#showInsideStatus() ? `${this.#calculatedPercentage}%` : ''}`} + +
` : ''} + + + + ${this.#showInsideStatus() ? html` + ` + : ''} +
`; } } From 3eda55148eb5392c15b9d5dcfaa68c65e3fe8792 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 29 Jun 2023 13:32:48 -0400 Subject: [PATCH 12/44] feat(progress): jsdocs, element internals, inline accessibility template --- elements/pf-progress/demo/accessibility.html | 23 ++-- elements/pf-progress/demo/pf-progress.html | 30 +---- elements/pf-progress/pf-progress.css | 35 ++---- elements/pf-progress/pf-progress.ts | 126 ++++++++----------- 4 files changed, 74 insertions(+), 140 deletions(-) diff --git a/elements/pf-progress/demo/accessibility.html b/elements/pf-progress/demo/accessibility.html index b5ec0555f0..a9cad683ab 100644 --- a/elements/pf-progress/demo/accessibility.html +++ b/elements/pf-progress/demo/accessibility.html @@ -1,22 +1,15 @@ -

Labelled

- - +

Progress Bar With Title

+ -

Danger Labelled

- - +

Progress Bar With Label

+ + -

Danger Labelled w/ inside measure

- - - -

Danger Titled

- - -

With title

- +

Progress Bar With Title and Label

+ +

Fancy label title

diff --git a/elements/pf-progress/demo/pf-progress.html b/elements/pf-progress/demo/pf-progress.html index b7367295b6..adfee3bcf2 100644 --- a/elements/pf-progress/demo/pf-progress.html +++ b/elements/pf-progress/demo/pf-progress.html @@ -1,31 +1,5 @@

Default:

- - - - -

Progress:

- - - -

Meter:

- - - - - - - - - - - - - - - - - - - + + \ No newline at end of file diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index bde9adae72..3f6647cc30 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -1,35 +1,27 @@ .container { + --_pf-c-progress__bar--before--BackgroundColorWithOpacity: #0066cc33; /* WARNING: not a recognized token value */ + --_pf-c-progress--m-success__bar--BackgroundColorWithOpacity: #3e863533; /* WARNING: not a recognized token value */ + --_pf-c-progress--m-warning__bar--BackgroundColorWithOpacity: #f0ab0033; /* WARNING: not a recognized token value */ + --_pf-c-progress--m-danger__bar--BackgroundColorWithOpacity: #c9190b33; /* WARNING: not a recognized token value */ + --pf-c-progress--GridGap: var(--pf-global--spacer--md, 1rem); --pf-c-progress__bar--before--BackgroundColor: var(--pf-global--primary-color--100, #0066cc); - --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-global--primary-color--100, #0066cc33); - --pf-c-progress__bar--Height: var(--pf-global--spacer--md, 1rem); --pf-c-progress__bar--BackgroundColor: var(--pf-global--BackgroundColor--light-100, #ffffff); --pf-c-progress__status-icon--Color: var(--pf-global--Color--100, #151515); --pf-c-progress__status-icon--MarginLeft: var(--pf-global--spacer--sm, 0.5rem); - --pf-c-progress__bar--before--Opacity: .2; --pf-c-progress__indicator--Height: var(--pf-c-progress__bar--Height); --pf-c-progress__indicator--BackgroundColor: var(--pf-c-progress__bar--before--BackgroundColor); --pf-c-progress--m-success__bar--BackgroundColor: var(--pf-global--success-color--100, #3e8635); - --pf-c-progress--m-success__bar--BackgroundColorWithOpacity: var(--pf-global--success-color--100, #3e863533); - --pf-c-progress--m-warning__bar--BackgroundColor: var(--pf-global--warning-color--100, #f0ab00); - --pf-c-progress--m-warning__bar--BackgroundColorWithOpacity: var(--pf-global--warning-color--100, #f0ab0033); - --pf-c-progress--m-danger__bar--BackgroundColor: var(--pf-global--danger-color--100, #c9190b); - --pf-c-progress--m-danger__bar--BackgroundColorWithOpacity: var(--pf-global--danger-color--100, #c9190b33); - --pf-c-progress--m-success__status-icon--Color: var(--pf-global--success-color--100, #3e8635); --pf-c-progress--m-warning__status-icon--Color: var(--pf-global--warning-color--100, #f0ab00); --pf-c-progress--m-danger__status-icon--Color: var(--pf-global--danger-color--100, #c9190b); - --pf-c-progress--m-inside__indicator--MinWidth: var(--pf-global--spacer--xl, 2rem); - --pf-c-progress--m-inside__measure--Color: var(--pf-global--Color--light-100, #ffffff); --pf-c-progress--m-success--m-inside__measure--Color: var(--pf-global--Color--light-100, #ffffff); - --pf-c-progress--m-inside__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); --pf-c-progress--m-outside__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); --pf-c-progress--m-sm__bar--Height: var(--pf-global--spacer--sm, 0.5rem); --pf-c-progress--m-sm__description--FontSize: var(--pf-global--FontSize--sm, 0.875rem); - --pf-c-progress--m-sm__measure--FontSize: var(--pf-global--FontSize--sm, 0.875rem); --pf-c-progress--m-lg__bar--Height: var(--pf-global--spacer--lg, 1.5rem); display: grid; align-items: end; @@ -83,21 +75,18 @@ } .success { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-success__bar--BackgroundColor); - --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-c-progress--m-success__bar--BackgroundColorWithOpacity); + --_pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--_pf-c-progress--m-success__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-success__status-icon--Color); - --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-success--m-inside__measure--Color); } .warning { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-warning__bar--BackgroundColor); - --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-c-progress--m-warning__bar--BackgroundColorWithOpacity); + --_pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--_pf-c-progress--m-warning__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-warning__status-icon--Color); - --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-warning--m-inside__measure--Color); } .danger { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-danger__bar--BackgroundColor); - --pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--pf-c-progress--m-danger__bar--BackgroundColorWithOpacity); + --_pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--_pf-c-progress--m-danger__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-danger__status-icon--Color); - --pf-c-progress--m-inside__measure--Color: var(--pf-c-progress--m-danger--m-inside__measure--Color); } .description { word-break: break-word; @@ -145,7 +134,7 @@ progress { display: block; } -span { +span { grid-column: 1/3; grid-row: 2/3; text-align: center; @@ -163,7 +152,7 @@ progress[value] { -moz-appearance: none; appearance: none; - background: var(--pf-c-progress__bar--before--BackgroundColorWithOpacity); + background: var(--_pf-c-progress__bar--before--BackgroundColorWithOpacity); width: 100%; height: var(--pf-c-progress__bar--Height); @@ -177,7 +166,7 @@ progress:not([value]) { progress[value]::-webkit-progress-bar { - background: var(--pf-c-progress__bar--before--BackgroundColorWithOpacity); + background: var(--_pf-c-progress__bar--before--BackgroundColorWithOpacity); } progress[value]::-moz-progress-bar { @@ -190,4 +179,4 @@ progress[value]::-webkit-progress-value { var(--pf-c-progress__bar--before--BackgroundColor) 100%); background-size: 100% 100%; -} \ No newline at end of file +} diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 7cd93f3782..324cc5f8a6 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -1,12 +1,12 @@ +import type { PropertyValues } from 'lit'; import { LitElement, html } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; -import { query } from 'lit/decorators/query.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { Logger } from '@patternfly/pfe-core/controllers/logger.js'; +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; import styles from './pf-progress.css'; @@ -45,10 +45,6 @@ const ICONS = new Map(Object.entries({ * Margin left of the status icon. * {@default `0.5rem`} * - * @cssprop {} --pf-c-progress__bar--before--Opacity - * Opacity of the progress bar. - * {@default `.2`} - * * @cssprop {} --pf-c-progress__indicator--Height * Height of the progress bar indicator. * {@default `1rem`} @@ -81,22 +77,10 @@ const ICONS = new Map(Object.entries({ * Color of the status icon when variant is danger. * {@default `#c9190b`} * - * @cssprop {} --pf-c-progress--m-inside__indicator--MinWidth - * Minimum width of the progress bar indicator when measure location is inside. - * {@default `2rem`} - * - * @cssprop {} --pf-c-progress--m-inside__measure--Color - * Color of the progress bar measure when measure location is inside. - * {@default `#ffffff`} - * * @cssprop {} --pf-c-progress--m-success--m-inside__measure--Color * Color of the progress bar measure when variant is success and measure location is inside. * {@default `#ffffff`} * - * @cssprop {} --pf-c-progress--m-inside__measure--FontSize - * Font size of the progress bar measure when measure location is inside. - * {@default `0.875rem`} - * * @cssprop {} --pf-c-progress--m-outside__measure--FontSize * Font size of the progress bar measure when measure location is outside. * {@default `0.875rem`} @@ -109,10 +93,6 @@ const ICONS = new Map(Object.entries({ * Font size of the progress bar description when the size is small. * {@default `0.875rem`} * - * @cssprop {} --pf-c-progress--m-sm__measure--FontSize - * Font size of the progress bar measure when the size is small. - * {@default `0.875rem`} - * * @cssprop {} --pf-c-progress--m-lg__bar--Height * Height of the progress bar when the size is large. * {@default `1.5rem`} @@ -124,70 +104,52 @@ export class PfProgress extends LitElement { static readonly formAssociated = true; - #calculatedPercentage = 0; - - #logger = new Logger(this); + #internals = new InternalsController(this); + /** Represents the value of the progress bar */ @property({ reflect: true, type: Number }) value = 0; + /** Title above the progress bar */ @property() title = ''; - @property({ attribute: 'aria-label' }) - ariaLabel = ''; - - @property({ type: Number }) + /** Maximum value for the progress bar */ + @property({ type: Number, reflect: true }) max = 100; - @property({ type: Number }) + /** Minimum value for the progress bar */ + @property({ type: Number, reflect: true }) min = 0; + /** Size of the progress bar (height) */ @property() size: 'sm' | 'lg' | '' = ''; + /** Where the percentage will be displayed with the progress element */ @property({ reflect: true, attribute: 'measure-location' }) measureLocation: '' | 'outside' | 'inside' | 'none' = ''; + /** Variant of the progress bar */ @property() variant: '' | 'success' | 'danger' | 'warning' = ''; - @query('progress') - progressElement!: HTMLProgressElement; - - #showInsideStatus() { - return this.measureLocation === 'inside'; - } - - #calculatePercentage() { - const { value, max, min } = this; - if (value === null ) { - this.#logger.warn(`A progress element requires a value attribute.`); - return; + get #calculatedPercentage(): number { + const { value, min, max } = this; + const percentage = Math.round((value - min) / (max - min) * 100); + if (isNaN(percentage) || percentage < 0) { + return 0; } - const percentage = (value - min) / (max - min); - this.#calculatedPercentage = Math.round(percentage * 100); - } - - connectedCallback(): void { - super.connectedCallback(); - this.#calculatePercentage(); - this.#updateAccessibility(); + if (percentage > 100) { + return 100; + } + return percentage; } - #updateAccessibility() { - const { value, title, ariaLabel, max, progressElement } = this; - if (progressElement) { - progressElement.setAttribute('aria-valuemin', '0'); - if (title || ariaLabel) { - progressElement.setAttribute('aria-label', `${title ? title : ariaLabel}`); - } - if (max != null) { - progressElement.setAttribute('aria-valuemax', `${max}`); - } - if (value) { - progressElement.setAttribute('aria-valuenow', `${value}`); - } + willUpdate(_changedProperties: PropertyValues) { + super.willUpdate(_changedProperties); + if ( _changedProperties.has('value') ) { + this.#internals.setFormValue(String(this.value)); } } @@ -199,24 +161,40 @@ export class PfProgress extends LitElement { return html`
- + ${title ? html` -
${title}
` : ''} - - ${measureLocation !== 'none' ? html`
- ${html`${!this.#showInsideStatus() ? `${this.#calculatedPercentage}%` : ''}`} + ` : ''} + + ${measureLocation !== 'none' ? html`` : ''} - - - - ${this.#showInsideStatus() ? html` - ` - : ''} + + + + + ${measureLocation === 'inside' ? html` + ` + : ''}
`; } } From 45732cb7ea2f5facf93c50e6e51b29748659cd27 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Wed, 5 Jul 2023 08:48:17 -0400 Subject: [PATCH 13/44] Update elements/pf-progress/pf-progress.ts Co-authored-by: Benny Powers --- elements/pf-progress/pf-progress.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 324cc5f8a6..72a8bab30e 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -140,10 +140,7 @@ export class PfProgress extends LitElement { if (isNaN(percentage) || percentage < 0) { return 0; } - if (percentage > 100) { - return 100; - } - return percentage; + return Math.min(percentage, 100); } willUpdate(_changedProperties: PropertyValues) { From 76b5bd29e820555bee41e15602ab500581549dc1 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Wed, 5 Jul 2023 09:12:09 -0400 Subject: [PATCH 14/44] fix(progress): remove willUpdate super method call --- elements/pf-progress/pf-progress.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 72a8bab30e..2cfc376bdb 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -144,7 +144,6 @@ export class PfProgress extends LitElement { } willUpdate(_changedProperties: PropertyValues) { - super.willUpdate(_changedProperties); if ( _changedProperties.has('value') ) { this.#internals.setFormValue(String(this.value)); } From ee2fa82ce54cacce9ed3bd403edec806465ca89a Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 6 Jul 2023 12:24:35 -0400 Subject: [PATCH 15/44] feat(progress): adding label attribute and span element for screen readers, optional --- elements/pf-progress/demo/accessibility.html | 28 +++++++++++++------- elements/pf-progress/pf-progress.css | 1 - elements/pf-progress/pf-progress.ts | 25 +++++++++++------ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/elements/pf-progress/demo/accessibility.html b/elements/pf-progress/demo/accessibility.html index a9cad683ab..9e3d40f46f 100644 --- a/elements/pf-progress/demo/accessibility.html +++ b/elements/pf-progress/demo/accessibility.html @@ -1,16 +1,26 @@ -

Progress Bar With Title

- +

Focusable Progress Bar

+ -

Progress Bar With Label

+

Focusable Progress Bar With Title

+ + +

Focusable Progress Bar With Label Element

- + + +

Focusable Progress Bar With Label Attribute

+ + +

Focusable Progress Bar With Title and Label

+ + -

Progress Bar With Title and Label

- - +

Focusable Progress Bar With Title and Label

+ + -

Fancy label title

+

Focusable Fancy label title

- \ No newline at end of file + \ No newline at end of file diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index 3f6647cc30..a7793ba36f 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -126,7 +126,6 @@ progress { background-color: var(--pf-c-progress__indicator--BackgroundColor); } - .indicator { width: 100%; height: var(--pf-c-progress__bar--Height); diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 2cfc376bdb..26926dafe6 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -127,13 +127,16 @@ export class PfProgress extends LitElement { size: 'sm' | 'lg' | '' = ''; /** Where the percentage will be displayed with the progress element */ - @property({ reflect: true, attribute: 'measure-location' }) + @property({ attribute: 'measure-location' }) measureLocation: '' | 'outside' | 'inside' | 'none' = ''; /** Variant of the progress bar */ @property() variant: '' | 'success' | 'danger' | 'warning' = ''; + @property() + label = ''; + get #calculatedPercentage(): number { const { value, min, max } = this; const percentage = Math.round((value - min) / (max - min) * 100); @@ -150,7 +153,7 @@ export class PfProgress extends LitElement { } render() { - const { size, measureLocation, variant, title } = this; + const { size, measureLocation, variant, title, value, max, label } = this; const icon = variant && ICONS.get(variant)?.icon; const singleLine = title.length === 0 ? 'singleline' : ''; @@ -162,11 +165,18 @@ export class PfProgress extends LitElement { html` ` : ''} + ${html` + + ${label !== '' ? label : `Current Progress: ${value} of ${max}`} + `} + ${measureLocation !== 'none' ? html`` : ''} - ${measureLocation === 'inside' ? html` From 9ea75e513697306fc3eb49e35b17d7fd741238ff Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 6 Jul 2023 16:35:49 -0400 Subject: [PATCH 16/44] refactor(progress): removing label, form associated internals, add tests --- elements/pf-progress/demo/accessibility.html | 26 ----------------- elements/pf-progress/pf-progress.ts | 27 ++---------------- elements/pf-progress/test/pf-progress.spec.ts | 28 +++++++++++++++++++ 3 files changed, 31 insertions(+), 50 deletions(-) delete mode 100644 elements/pf-progress/demo/accessibility.html diff --git a/elements/pf-progress/demo/accessibility.html b/elements/pf-progress/demo/accessibility.html deleted file mode 100644 index 9e3d40f46f..0000000000 --- a/elements/pf-progress/demo/accessibility.html +++ /dev/null @@ -1,26 +0,0 @@ - - -

Focusable Progress Bar

- - -

Focusable Progress Bar With Title

- - -

Focusable Progress Bar With Label Element

- - - -

Focusable Progress Bar With Label Attribute

- - -

Focusable Progress Bar With Title and Label

- - - -

Focusable Progress Bar With Title and Label

- - - -

Focusable Fancy label title

- - \ No newline at end of file diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 26926dafe6..d3d933f424 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -6,8 +6,6 @@ import { property } from 'lit/decorators/property.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; - import styles from './pf-progress.css'; const ICONS = new Map(Object.entries({ @@ -104,8 +102,6 @@ export class PfProgress extends LitElement { static readonly formAssociated = true; - #internals = new InternalsController(this); - /** Represents the value of the progress bar */ @property({ reflect: true, type: Number }) value = 0; @@ -134,9 +130,6 @@ export class PfProgress extends LitElement { @property() variant: '' | 'success' | 'danger' | 'warning' = ''; - @property() - label = ''; - get #calculatedPercentage(): number { const { value, min, max } = this; const percentage = Math.round((value - min) / (max - min) * 100); @@ -146,14 +139,8 @@ export class PfProgress extends LitElement { return Math.min(percentage, 100); } - willUpdate(_changedProperties: PropertyValues) { - if ( _changedProperties.has('value') ) { - this.#internals.setFormValue(String(this.value)); - } - } - render() { - const { size, measureLocation, variant, title, value, max, label } = this; + const { size, measureLocation, variant, title } = this; const icon = variant && ICONS.get(variant)?.icon; const singleLine = title.length === 0 ? 'singleline' : ''; @@ -170,13 +157,6 @@ export class PfProgress extends LitElement { ${title}
` : ''} - ${html` - - ${label !== '' ? label : `Current Progress: ${value} of ${max}`} - `} - ${measureLocation !== 'none' ? html``; From b158c191ddc63ce4fbfecf36cc463ed87ef6d6a2 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Mon, 24 Jul 2023 14:08:36 -0400 Subject: [PATCH 18/44] Update elements/pf-progress/pf-progress.ts Co-authored-by: Benny Powers --- elements/pf-progress/pf-progress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index dbe650466a..579a0926a8 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -141,7 +141,7 @@ export class PfProgress extends LitElement { render() { const { size, measureLocation, variant, title } = this; const icon = variant && ICONS.get(variant)?.icon; - const singleLine = title.length === 0 ? 'singleline' : ''; + const singleline = title.length === 0; return html`
Date: Thu, 3 Aug 2023 10:21:32 -0400 Subject: [PATCH 19/44] fix(progress): singleLine class fix --- elements/pf-progress/pf-progress.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 579a0926a8..e86e69d2c2 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -141,11 +141,11 @@ export class PfProgress extends LitElement { render() { const { size, measureLocation, variant, title } = this; const icon = variant && ICONS.get(variant)?.icon; - const singleline = title.length === 0; + const singleLine = title.length === 0; return html`
+ class="container ${classMap({ [size]: !!size, [measureLocation]: !!measureLocation, [variant]: !!variant, ['singleLine']: !!singleLine })}"> ${title ? html` From c75f42f81eefb4d81db2b0e046a14f46a3b6dab5 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 3 Aug 2023 14:54:37 -0400 Subject: [PATCH 20/44] Update elements/pf-progress/pf-progress.ts Co-authored-by: Benny Powers --- elements/pf-progress/pf-progress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index e86e69d2c2..192ba0a40e 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -132,7 +132,7 @@ export class PfProgress extends LitElement { get #calculatedPercentage(): number { const { value, min, max } = this; const percentage = Math.round((value - min) / (max - min) * 100); - if (isNaN(percentage) || percentage < 0) { + if (Number.isNaN(percentage) || percentage < 0) { return 0; } return Math.min(percentage, 100); From 17a567246ec148afabacb1a1913fa9624a770627 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 3 Aug 2023 14:54:47 -0400 Subject: [PATCH 21/44] Update elements/pf-progress/pf-progress.ts Co-authored-by: Benny Powers --- elements/pf-progress/pf-progress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 192ba0a40e..d9754a29e9 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -145,7 +145,7 @@ export class PfProgress extends LitElement { return html`
+ class="container ${classMap({ [size]: !!size, [measureLocation]: !!measureLocation, [variant]: !!variant, singleLine })}"> ${title ? html` From 25638eed284e6915f000931059bb0e45d494600d Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Thu, 3 Aug 2023 14:58:34 -0400 Subject: [PATCH 22/44] style(progress): adding new lines too styling classes --- elements/pf-progress/pf-progress.css | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index a7793ba36f..b42a2fe96b 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -29,74 +29,91 @@ grid-template-columns: auto auto; grid-template-rows: 1fr auto; } + .sm { --pf-c-progress__bar--Height: var(--pf-c-progress--m-sm__bar--Height); --pf-c-progress__indicator--Height: var(--pf-c-progress--m-sm__bar--Height); } + .sm .description { font-size: var(--pf-c-progress--m-sm__description--FontSize); } + .lg { --pf-c-progress__bar--Height: var(--pf-c-progress--m-lg__bar--Height); --pf-c-progress__indicator--Height: var(--pf-c-progress--m-lg__bar--Height); } + .outside .description { grid-column: 1/3; } + .outside .status { grid-column: 2/3; grid-row: 2/3; align-self: center; } + .outside progress, .outside span { display: inline-block; font-size: var(--pf-c-progress--m-outside__measure--FontSize); grid-column: 1/2; } + .singleline { grid-template-rows: 1fr; } + .singleline .title { display: none; visibility: hidden; } + .singleline progress, .singleline span { grid-row: 1/2; grid-column: 1/2; } + .singleline .status { grid-row: 1/2; grid-column: 2/3; } + .outside, .singleline { grid-template-columns: 1fr fit-content(50%); } + .success { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-success__bar--BackgroundColor); --_pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--_pf-c-progress--m-success__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-success__status-icon--Color); } + .warning { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-warning__bar--BackgroundColor); --_pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--_pf-c-progress--m-warning__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-warning__status-icon--Color); } + .danger { --pf-c-progress__bar--before--BackgroundColor: var(--pf-c-progress--m-danger__bar--BackgroundColor); --_pf-c-progress__bar--before--BackgroundColorWithOpacity: var(--_pf-c-progress--m-danger__bar--BackgroundColorWithOpacity); --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-danger__status-icon--Color); } + .description { word-break: break-word; grid-column: 1/2; } + .description.pf-m-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .status { grid-column: 2/3; grid-row: 1/2; @@ -106,10 +123,12 @@ align-items: center; justify-content: end; } + pf-icon { margin-left: var(--pf-c-progress__status-icon--MarginLeft); color: var(--pf-c-progress__status-icon--Color); } + progress { position: relative; grid-column: 1/3; @@ -118,6 +137,7 @@ progress { height: var(--pf-c-progress__bar--Height); background-color: var(--pf-c-progress__bar--BackgroundColor); } + .indicator { position: absolute; top: 0; From 903533dca52114b09640e9345b8e7b5853184ad1 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Fri, 4 Aug 2023 16:14:46 -0400 Subject: [PATCH 23/44] docs(card): patterns page fixing image, broken ctas --- elements/pf-progress/demo/form.html | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 elements/pf-progress/demo/form.html diff --git a/elements/pf-progress/demo/form.html b/elements/pf-progress/demo/form.html new file mode 100644 index 0000000000..6c906fe3d7 --- /dev/null +++ b/elements/pf-progress/demo/form.html @@ -0,0 +1,40 @@ + + +

Default:

+
+ + + + + +
+ + + + + + + + + + + + +


+ + + + + + + + + \ No newline at end of file From 3b95431a15c1fbd886e2bdac791b2cfc10289606 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Mon, 7 Aug 2023 13:49:14 -0400 Subject: [PATCH 24/44] fix(progress): remove form association from progress bar, form demo --- elements/pf-progress/demo/form.html | 40 ------------------------ elements/pf-progress/docs/pf-progress.md | 2 ++ elements/pf-progress/pf-progress.ts | 20 ++++++++++-- 3 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 elements/pf-progress/demo/form.html diff --git a/elements/pf-progress/demo/form.html b/elements/pf-progress/demo/form.html deleted file mode 100644 index 6c906fe3d7..0000000000 --- a/elements/pf-progress/demo/form.html +++ /dev/null @@ -1,40 +0,0 @@ - - -

Default:

-
- - - - - -
- - - - - - - - - - - - -


- - - - - - - - - \ No newline at end of file diff --git a/elements/pf-progress/docs/pf-progress.md b/elements/pf-progress/docs/pf-progress.md index 1535ab49c0..eeeeb930c2 100644 --- a/elements/pf-progress/docs/pf-progress.md +++ b/elements/pf-progress/docs/pf-progress.md @@ -1,3 +1,5 @@ +{% renderInstallation %} {% endrenderInstallation %} + {% renderOverview %} {% endrenderOverview %} diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index d9754a29e9..4a5846e1e0 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -6,6 +6,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; import styles from './pf-progress.css'; +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; const ICONS = new Map(Object.entries({ success: { icon: 'circle-check' }, @@ -99,8 +100,6 @@ const ICONS = new Map(Object.entries({ export class PfProgress extends LitElement { static readonly styles = [styles]; - static readonly formAssociated = true; - /** Represents the value of the progress bar */ @property({ reflect: true, type: Number }) value = 0; @@ -119,7 +118,7 @@ export class PfProgress extends LitElement { /** Size of the progress bar (height) */ @property() - size: 'sm' | 'lg' | '' = ''; + size: '' | 'sm' | 'lg' = ''; /** Where the percentage will be displayed with the progress element */ @property({ attribute: 'measure-location' }) @@ -129,6 +128,12 @@ export class PfProgress extends LitElement { @property() variant: '' | 'success' | 'danger' | 'warning' = ''; + #mo = new MutationObserver(() => this.#onMutation()); + + #onMutation() { + this.#internals.ariaValueNow = this.#calculatedPercentage.toString(); + } + get #calculatedPercentage(): number { const { value, min, max } = this; const percentage = Math.round((value - min) / (max - min) * 100); @@ -138,6 +143,15 @@ export class PfProgress extends LitElement { return Math.min(percentage, 100); } + #internals = new InternalsController(this, { + ariaValueNow: this.#calculatedPercentage.toString() + }); + + connectedCallback(): void { + super.connectedCallback(); + this.#mo.observe(this, { attributes: true }); + } + render() { const { size, measureLocation, variant, title } = this; const icon = variant && ICONS.get(variant)?.icon; From 65c964dd26a90c5b6e744e26970971836106bd80 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Mon, 7 Aug 2023 16:38:03 -0400 Subject: [PATCH 25/44] fix(progress): willUpdate for internals, attachInternals instead of controller --- elements/pf-progress/pf-progress.ts | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index 4a5846e1e0..ffcf2d26bc 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -1,3 +1,4 @@ +import type { PropertyValues } from 'lit'; import { LitElement, html } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; import { customElement } from 'lit/decorators/custom-element.js'; @@ -6,7 +7,6 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; import styles from './pf-progress.css'; -import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; const ICONS = new Map(Object.entries({ success: { icon: 'circle-check' }, @@ -100,6 +100,8 @@ const ICONS = new Map(Object.entries({ export class PfProgress extends LitElement { static readonly styles = [styles]; + #internals = this.attachInternals(); + /** Represents the value of the progress bar */ @property({ reflect: true, type: Number }) value = 0; @@ -128,12 +130,6 @@ export class PfProgress extends LitElement { @property() variant: '' | 'success' | 'danger' | 'warning' = ''; - #mo = new MutationObserver(() => this.#onMutation()); - - #onMutation() { - this.#internals.ariaValueNow = this.#calculatedPercentage.toString(); - } - get #calculatedPercentage(): number { const { value, min, max } = this; const percentage = Math.round((value - min) / (max - min) * 100); @@ -143,13 +139,10 @@ export class PfProgress extends LitElement { return Math.min(percentage, 100); } - #internals = new InternalsController(this, { - ariaValueNow: this.#calculatedPercentage.toString() - }); - - connectedCallback(): void { - super.connectedCallback(); - this.#mo.observe(this, { attributes: true }); + willUpdate(changed: PropertyValues) { + if (changed.has('value') || changed.has('min') || changed.has('max')) { + this.#internals.ariaValueNow = this.#calculatedPercentage.toString(); + } } render() { From f990a7921acc92666b8264f760c5cb79ec72f687 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 15:58:25 +0300 Subject: [PATCH 26/44] style(switch): whitespace --- elements/pf-switch/pf-switch.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elements/pf-switch/pf-switch.ts b/elements/pf-switch/pf-switch.ts index fcd45a37b6..31c8234a17 100644 --- a/elements/pf-switch/pf-switch.ts +++ b/elements/pf-switch/pf-switch.ts @@ -47,8 +47,8 @@ export class PfSwitch extends BaseSwitch { static readonly styles = [...BaseSwitch.styles, styles]; } - declare global { - interface HTMLElementTagNameMap { - 'pf-switch': PfSwitch; +declare global { + interface HTMLElementTagNameMap { + 'pf-switch': PfSwitch; } } From 9387379258eab409402c965a9ad7a3609b022f46 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 16:14:27 +0300 Subject: [PATCH 27/44] feat(tooltip): trigger, flip --- .changeset/pf-tooltip-deprecate-base.md | 5 + .changeset/pf-tooltip-flip.md | 4 + .changeset/pf-tooltip-trigger.md | 11 ++ elements/pf-tooltip/BaseTooltip.css | 6 +- elements/pf-tooltip/BaseTooltip.ts | 9 +- elements/pf-tooltip/demo/flip.html | 56 ++++++++++ elements/pf-tooltip/demo/trigger.html | 8 ++ elements/pf-tooltip/pf-tooltip.css | 65 +++++++++++- elements/pf-tooltip/pf-tooltip.ts | 130 +++++++++++++++++++++++- 9 files changed, 277 insertions(+), 17 deletions(-) create mode 100644 .changeset/pf-tooltip-deprecate-base.md create mode 100644 .changeset/pf-tooltip-flip.md create mode 100644 .changeset/pf-tooltip-trigger.md create mode 100644 elements/pf-tooltip/demo/flip.html create mode 100644 elements/pf-tooltip/demo/trigger.html diff --git a/.changeset/pf-tooltip-deprecate-base.md b/.changeset/pf-tooltip-deprecate-base.md new file mode 100644 index 0000000000..c3b6300a24 --- /dev/null +++ b/.changeset/pf-tooltip-deprecate-base.md @@ -0,0 +1,5 @@ +--- +"@patternfly/elements": patch +--- +``: marks `BaseTooltip` and it's stylesheet as deprecated. +The files will remain in place until the next major version. diff --git a/.changeset/pf-tooltip-flip.md b/.changeset/pf-tooltip-flip.md new file mode 100644 index 0000000000..1240cc71d9 --- /dev/null +++ b/.changeset/pf-tooltip-flip.md @@ -0,0 +1,4 @@ +--- +"@patternfly/elements": minor +--- +``: added `no-flip` and `flip-behaviour` attributes as in `` diff --git a/.changeset/pf-tooltip-trigger.md b/.changeset/pf-tooltip-trigger.md new file mode 100644 index 0000000000..710698e908 --- /dev/null +++ b/.changeset/pf-tooltip-trigger.md @@ -0,0 +1,11 @@ +--- +"@patternfly/element": minor +--- +`` added the `trigger` attribute to specify a tooltip-invoking +element outside of the tooltip's children. + +```html +Button + +``` diff --git a/elements/pf-tooltip/BaseTooltip.css b/elements/pf-tooltip/BaseTooltip.css index faae1f87d8..43a366a4f7 100644 --- a/elements/pf-tooltip/BaseTooltip.css +++ b/elements/pf-tooltip/BaseTooltip.css @@ -6,14 +6,10 @@ #container { display: inline-flex; position: relative; + max-width: 100%; --_floating-arrow-size: 0.5rem; } -#invoker { - display: inline-block; - position: relative; -} - #tooltip, #tooltip::after { position: absolute; diff --git a/elements/pf-tooltip/BaseTooltip.ts b/elements/pf-tooltip/BaseTooltip.ts index 2791e83e79..0d6843f8f6 100644 --- a/elements/pf-tooltip/BaseTooltip.ts +++ b/elements/pf-tooltip/BaseTooltip.ts @@ -11,6 +11,9 @@ import style from './BaseTooltip.css'; const enterEvents = ['focusin', 'tap', 'click', 'mouseenter']; const exitEvents = ['focusout', 'blur', 'mouseleave']; +/** + * @deprecated - Will be removed in the next major version. Use FloatingDOMController + */ export abstract class BaseTooltip extends LitElement { static readonly styles = [style]; @@ -48,9 +51,9 @@ export abstract class BaseTooltip extends LitElement { return html`
+ class="${classMap({ open, + [anchor]: !!anchor, + [alignment]: !!alignment })}"> + + Tooltip! + + + +
Flip fallback
+ + +
+ + Tooltip! + +
No flip
+
+ + + + + diff --git a/elements/pf-tooltip/demo/trigger.html b/elements/pf-tooltip/demo/trigger.html new file mode 100644 index 0000000000..1e789d4d7c --- /dev/null +++ b/elements/pf-tooltip/demo/trigger.html @@ -0,0 +1,8 @@ + +Button + + + diff --git a/elements/pf-tooltip/pf-tooltip.css b/elements/pf-tooltip/pf-tooltip.css index 825da52d9c..cbe17e4435 100644 --- a/elements/pf-tooltip/pf-tooltip.css +++ b/elements/pf-tooltip/pf-tooltip.css @@ -1,11 +1,38 @@ :host { --_timestamp-text-decoration: underline dashed 1px; --_timestamp-text-underline-offset: 4px; + display: inline; } +* { box-sizing: border-box; } + +#container { + display: inline-flex; + position: relative; + max-width: 100%; + --_floating-arrow-size: var(--pf-c-tooltip__arrow--Width, 0.5rem); +} + +#tooltip, +#tooltip::after { + position: absolute; +} #tooltip { --_timestamp-text-decoration: none; --_timestamp-text-underline-offset: initial; + display: block; + opacity: 0; + pointer-events: none; + z-index: 10000; + transition: opacity 300ms cubic-bezier(0.54, 1.5, 0.38, 1.11) 0s; + text-align: center; + word-break: break-word; + translate: var(--_floating-content-translate); + max-width: calc(100vw - 10px); + width: max-content; + top: 0; + left: 0; + will-change: opacity; line-height: var(--pf-c-tooltip--line-height, 1.5); max-width: var(--pf-c-tooltip--MaxWidth, 18.75rem); box-shadow: var(--pf-c-tooltip--BoxShadow, @@ -29,12 +56,42 @@ var(--pf-global--BackgroundColor--dark-100, #151515)); } -#container { - --_floating-arrow-size: var(--pf-c-tooltip__arrow--Width, 0.5rem); -} - #tooltip::after { + display: block; + content: ''; + rotate: 45deg; + width: var(--_floating-arrow-size); + height: var(--_floating-arrow-size); + will-change: left top right bottom; background-color: var(--pf-c-tooltip__content--BackgroundColor, var(--pf-global--BackgroundColor--dark-100, #151515)); } +.open #tooltip { + opacity: 1; +} + +/* LEFT */ +.left #tooltip::after { right: calc(-0.5 * var(--_floating-arrow-size)); } +.left.center #tooltip::after { top: calc(50% - 0.5 * var(--_floating-arrow-size)); } +.left.start #tooltip::after { top: var(--_floating-arrow-size); } +.left.end #tooltip::after { bottom: var(--_floating-arrow-size); } + +/* TOP */ +.top #tooltip::after { top: calc(100% - 0.5 * var(--_floating-arrow-size)); } +.top.center #tooltip::after { right: calc(50% - 0.5 * var(--_floating-arrow-size)); } +.top.start #tooltip::after { left: var(--_floating-arrow-size); } +.top.end #tooltip::after { right: var(--_floating-arrow-size); } + +/* RIGHT */ +.right #tooltip::after { right: calc(100% - 0.5 * var(--_floating-arrow-size)); } +.right.center #tooltip::after { top: calc(50% - 0.5 * var(--_floating-arrow-size)); } +.right.start #tooltip::after { top: var(--_floating-arrow-size); } +.right.end #tooltip::after { bottom: var(--_floating-arrow-size); } + +/* BOTTOM */ +.bottom #tooltip::after { bottom: calc(100% - 0.5 * var(--_floating-arrow-size)); } +.bottom.center #tooltip::after { right: calc(50% - 0.5 * var(--_floating-arrow-size)); } +.bottom.start #tooltip::after { left: var(--_floating-arrow-size); } +.bottom.end #tooltip::after { right: var(--_floating-arrow-size); } + diff --git a/elements/pf-tooltip/pf-tooltip.ts b/elements/pf-tooltip/pf-tooltip.ts index 04596d885c..2f00d1e8c0 100644 --- a/elements/pf-tooltip/pf-tooltip.ts +++ b/elements/pf-tooltip/pf-tooltip.ts @@ -1,11 +1,24 @@ -import type { Placement } from '@patternfly/pfe-core/controllers/floating-dom-controller.js'; - +import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; -import { BaseTooltip } from './BaseTooltip.js'; +import { styleMap } from 'lit/directives/style-map.js'; +import { classMap } from 'lit/directives/class-map.js'; + +import { + FloatingDOMController, + type Placement, +} from '@patternfly/pfe-core/controllers/floating-dom-controller.js'; + +import { bound } from '@patternfly/pfe-core/decorators/bound.js'; + +import { StringListConverter } from '@patternfly/pfe-core'; + import styles from './pf-tooltip.css'; +const EnterEvents = ['focusin', 'tap', 'click', 'mouseenter']; +const ExitEvents = ['focusout', 'blur', 'mouseleave']; + /** * A **tooltip** is in-app messaging used to identify elements on a page with short, * clarifying text. @@ -94,13 +107,120 @@ import styles from './pf-tooltip.css'; * {@default `45deg`} */ @customElement('pf-tooltip') -export class PfTooltip extends BaseTooltip { - static readonly styles = [...BaseTooltip.styles, styles]; +export class PfTooltip extends LitElement { + static readonly styles = [styles]; + /** The position of the tooltip, relative to the invoking content */ @property() position: Placement = 'top'; /** Tooltip content. Overridden by the content slot */ @property() content?: string; + + /** If false, prevents the tooltip from trying to remain in view by flipping itself when necessary */ + @property({ type: Boolean, attribute: 'no-flip' }) noFlip = false; + + @property() trigger?: string | Element; + + /** + * The flip order when flip is enabled and the initial position is not possible. + * There are 12 options: `top`, `bottom`, `left`, `right`, `top-start`, `top-end`, + * `bottom-start`, `bottom-end`, `left-start`, `left-end`,`right-start`, `right-end`. + * The default is [oppositePlacement], where only the opposite placement is tried. + */ + @property({ + attribute: 'flip-behavior', + converter: StringListConverter, + }) flipBehavior?: Placement[]; + + #referenceTrigger?: Element | null; + + #float = new FloatingDOMController(this, { + content: (): HTMLElement | undefined | null => + this.shadowRoot?.querySelector('#tooltip'), + invoker: () => this.#referenceTrigger ?? + this.shadowRoot?.querySelector('#invoker') + ?.assignedElements().at(0), + }); + + override connectedCallback() { + super.connectedCallback(); + this.#updateTrigger(); + } + + /** + * Removes event listeners from the old trigger element and attaches + * them to the new trigger element. + */ + override willUpdate(changed: PropertyValues) { + if (changed.has('trigger')) { + this.#updateTrigger(); + } + } + + override render() { + const { alignment, anchor, open, styles } = this.#float; + + return html` +
+ + ${this.content} +
+ `; + } + + #getReferenceTrigger() { + return (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger); + } + + #updateTrigger() { + const oldReferenceTrigger = this.#referenceTrigger; + this.#referenceTrigger = + this.trigger instanceof Element ? this.trigger + : typeof this.trigger === 'string' ? this.#getReferenceTrigger() + : null; + for (const evt of EnterEvents) { + if (this.#referenceTrigger) { + this.removeEventListener(evt, this.show); + this.#referenceTrigger.addEventListener(evt, this.show); + } else { + oldReferenceTrigger?.removeEventListener(evt, this.show); + this.addEventListener(evt, this.show); + } + } + for (const evt of ExitEvents) { + if (this.#referenceTrigger) { + this.removeEventListener(evt, this.hide); + this.#referenceTrigger.addEventListener(evt, this.hide); + } else { + oldReferenceTrigger?.removeEventListener(evt, this.hide); + this.addEventListener(evt, this.hide); + } + } + } + + @bound async show() { + await this.updateComplete; + const placement = this.position; + const offset = + !placement?.match(/top|bottom/) ? 15 + : { mainAxis: 15, alignmentAxis: -4 }; + await this.#float.show({ + offset, + placement, + flip: !this.noFlip, + fallbackPlacements: this.flipBehavior, + }); + } + + @bound async hide() { + await this.#float.hide(); + } } declare global { From 8155ba3c552abedbbd011571a3a59f644b2f9130 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 16:15:19 +0300 Subject: [PATCH 28/44] docs(popover): added flip demo --- elements/pf-popover/demo/flip.html | 41 ++++++++++++++++++++++++ elements/pf-popover/demo/pf-popover.html | 4 +-- elements/pf-popover/demo/pf-popover.js | 4 +-- elements/pf-popover/pf-popover.ts | 18 +++++------ 4 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 elements/pf-popover/demo/flip.html diff --git a/elements/pf-popover/demo/flip.html b/elements/pf-popover/demo/flip.html new file mode 100644 index 0000000000..6d94889b6d --- /dev/null +++ b/elements/pf-popover/demo/flip.html @@ -0,0 +1,41 @@ + + + +
+
+ No flip + + Toggle popover + +
+ +
+ Flip fallback + + + Toggle popover + +
+
diff --git a/elements/pf-popover/demo/pf-popover.html b/elements/pf-popover/demo/pf-popover.html index cf0b399c22..e36c6a8578 100644 --- a/elements/pf-popover/demo/pf-popover.html +++ b/elements/pf-popover/demo/pf-popover.html @@ -1,5 +1,5 @@ - - + +

Basic

diff --git a/elements/pf-popover/demo/pf-popover.js b/elements/pf-popover/demo/pf-popover.js index f7eaeb01e6..0a7b7ed7bf 100644 --- a/elements/pf-popover/demo/pf-popover.js +++ b/elements/pf-popover/demo/pf-popover.js @@ -12,11 +12,11 @@ select.addEventListener('change', event => // Close popover from content const closeButton = document.getElementById('close-button'); -closeButton.addEventListener('click', event => event.target.closest('pf-popover').hide()); +closeButton?.addEventListener('click', event => event.target.closest('pf-popover').hide()); // Alert variants const alert = document.getElementById('alert'); -alert.addEventListener('change', event => +alert?.addEventListener('change', event => alert .querySelector('pf-popover') .setAttribute('alert-severity', event.target.closest('form').elements.severity.value)); diff --git a/elements/pf-popover/pf-popover.ts b/elements/pf-popover/pf-popover.ts index d1f3ad5ba8..ee3ad2a0b7 100644 --- a/elements/pf-popover/pf-popover.ts +++ b/elements/pf-popover/pf-popover.ts @@ -1,4 +1,4 @@ -import { LitElement, nothing, html } from 'lit'; +import { LitElement, nothing, html, type PropertyValues } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { query } from 'lit/decorators/query.js'; @@ -9,7 +9,6 @@ import { FloatingDOMController } from '@patternfly/pfe-core/controllers/floating import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; import { bound } from '@patternfly/pfe-core/decorators/bound.js'; import { ComposedEvent, StringListConverter } from '@patternfly/pfe-core/core.js'; -import { observed } from '@patternfly/pfe-core/decorators/observed.js'; import type { Placement } from '@patternfly/pfe-core/controllers/floating-dom-controller.js'; import '@patternfly/elements/pf-button/pf-button.js'; import styles from './pf-popover.css'; @@ -301,7 +300,6 @@ export class PfPopover extends LitElement { /** * The ID of the element to attach the popover to. */ - @observed('triggerChanged') @property({ reflect: true }) trigger?: string; @query('#popover') private _popover!: HTMLDialogElement; @@ -420,15 +418,15 @@ export class PfPopover extends LitElement { * Removes event listeners from the old trigger element and attaches * them to the new trigger element. */ - triggerChanged(oldValue?: string, newValue?: string) { - if (oldValue) { + override willUpdate(changed: PropertyValues) { + if (changed.has('trigger')) { this.#referenceTrigger?.removeEventListener('click', this.show); this.#referenceTrigger?.removeEventListener('keydown', this.onKeydown); - } - if (newValue) { - this.#referenceTrigger = (this.getRootNode() as Document | ShadowRoot).getElementById(newValue); - this.#referenceTrigger?.addEventListener('click', this.show); - this.#referenceTrigger?.addEventListener('keydown', this.onKeydown); + if (this.trigger) { + this.#referenceTrigger = (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger); + this.#referenceTrigger?.addEventListener('click', this.show); + this.#referenceTrigger?.addEventListener('keydown', this.onKeydown); + } } } From 23e666bec69ac050bdaa5482c08d5983cefef7b5 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 16:15:58 +0300 Subject: [PATCH 29/44] feat(progress): truncated title --- elements/pf-progress/demo/demo.css | 6 + elements/pf-progress/demo/kitchen-sink.html | 13 +- .../pf-progress/demo/truncated-title.html | 10 ++ elements/pf-progress/pf-progress.css | 41 +++--- elements/pf-progress/pf-progress.ts | 119 ++++++++++-------- 5 files changed, 116 insertions(+), 73 deletions(-) create mode 100644 elements/pf-progress/demo/demo.css create mode 100644 elements/pf-progress/demo/truncated-title.html diff --git a/elements/pf-progress/demo/demo.css b/elements/pf-progress/demo/demo.css new file mode 100644 index 0000000000..4ef939b648 --- /dev/null +++ b/elements/pf-progress/demo/demo.css @@ -0,0 +1,6 @@ +[data-demo="pf-progress"] { + max-width: 600px; +} +pf-progress { + width: 100%; +} diff --git a/elements/pf-progress/demo/kitchen-sink.html b/elements/pf-progress/demo/kitchen-sink.html index df401d0432..d5f19ced86 100644 --- a/elements/pf-progress/demo/kitchen-sink.html +++ b/elements/pf-progress/demo/kitchen-sink.html @@ -10,8 +10,8 @@

Default States

Value

-

Title

- +

Description

+

Aria-label

@@ -75,7 +75,7 @@

Variant (Success, Danger, Warning), Size (sm, lg) and Measure Location (Insi -

Label w/ no title

+

Label w/ no description

Value

@@ -129,3 +129,10 @@

Variant (Success, Danger, Warning) and Size (sm, lg)

+

Truncated description

+ + diff --git a/elements/pf-progress/demo/truncated-title.html b/elements/pf-progress/demo/truncated-title.html new file mode 100644 index 0000000000..62993a68c4 --- /dev/null +++ b/elements/pf-progress/demo/truncated-title.html @@ -0,0 +1,10 @@ + + + + diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index b42a2fe96b..c411911881 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -1,4 +1,8 @@ -.container { +* { + box-sizing: border-box; +} + +#container { --_pf-c-progress__bar--before--BackgroundColorWithOpacity: #0066cc33; /* WARNING: not a recognized token value */ --_pf-c-progress--m-success__bar--BackgroundColorWithOpacity: #3e863533; /* WARNING: not a recognized token value */ --_pf-c-progress--m-warning__bar--BackgroundColorWithOpacity: #f0ab0033; /* WARNING: not a recognized token value */ @@ -26,8 +30,9 @@ display: grid; align-items: end; grid-gap: var(--pf-c-progress--GridGap); - grid-template-columns: auto auto; + grid-template-columns: 1fr auto; grid-template-rows: 1fr auto; + width: 100%; } .sm { @@ -35,7 +40,7 @@ --pf-c-progress__indicator--Height: var(--pf-c-progress--m-sm__bar--Height); } -.sm .description { +.sm #description { font-size: var(--pf-c-progress--m-sm__description--FontSize); } @@ -44,11 +49,11 @@ --pf-c-progress__indicator--Height: var(--pf-c-progress--m-lg__bar--Height); } -.outside .description { +.outside #description { grid-column: 1/3; } -.outside .status { +.outside #status { grid-column: 2/3; grid-row: 2/3; align-self: center; @@ -65,7 +70,7 @@ grid-template-rows: 1fr; } -.singleline .title { +.singleline #description { display: none; visibility: hidden; } @@ -76,7 +81,7 @@ grid-column: 1/2; } -.singleline .status { +.singleline #status { grid-row: 1/2; grid-column: 2/3; } @@ -103,18 +108,18 @@ --pf-c-progress__status-icon--Color: var(--pf-c-progress--m-danger__status-icon--Color); } -.description { +#description { word-break: break-word; grid-column: 1/2; } -.description.pf-m-truncate { - overflow: hidden; +.descriptionTruncated #description { + overflow-x: hidden; text-overflow: ellipsis; white-space: nowrap; } -.status { +#status { grid-column: 2/3; grid-row: 1/2; text-align: right; @@ -183,8 +188,7 @@ progress:not([value]) { appearance: none; } -progress[value]::-webkit-progress-bar -{ +progress[value]::-webkit-progress-bar { background: var(--_pf-c-progress__bar--before--BackgroundColorWithOpacity); } @@ -193,9 +197,10 @@ progress[value]::-moz-progress-bar { } progress[value]::-webkit-progress-value { - background-image: linear-gradient( 90deg, - var(--pf-c-progress__bar--before--BackgroundColor) 100%, - var(--pf-c-progress__bar--before--BackgroundColor) 100%); - - background-size: 100% 100%; + background-size: 100% 100%; + background-image: linear-gradient( + 90deg, + var(--pf-c-progress__bar--before--BackgroundColor) 100%, + var(--pf-c-progress__bar--before--BackgroundColor) 100% + ); } diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index ffcf2d26bc..c50759c612 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -103,32 +103,27 @@ export class PfProgress extends LitElement { #internals = this.attachInternals(); /** Represents the value of the progress bar */ - @property({ reflect: true, type: Number }) - value = 0; + @property({ reflect: true, type: Number }) value = 0; /** Title above the progress bar */ - @property() - title = ''; + @property() description?: string; + + @property({ type: Boolean, reflect: true, attribute: 'description-truncated' }) descriptionTruncated = false; /** Maximum value for the progress bar */ - @property({ type: Number, reflect: true }) - max = 100; + @property({ type: Number, reflect: true }) max = 100; /** Minimum value for the progress bar */ - @property({ type: Number, reflect: true }) - min = 0; + @property({ type: Number, reflect: true }) min = 0; /** Size of the progress bar (height) */ - @property() - size: '' | 'sm' | 'lg' = ''; + @property() size?: 'sm' | 'lg'; /** Where the percentage will be displayed with the progress element */ - @property({ attribute: 'measure-location' }) - measureLocation: '' | 'outside' | 'inside' | 'none' = ''; + @property({ attribute: 'measure-location' }) measureLocation?: 'outside' | 'inside' | 'none'; /** Variant of the progress bar */ - @property() - variant: '' | 'success' | 'danger' | 'warning' = ''; + @property() variant?: 'success' | 'danger' | 'warning'; get #calculatedPercentage(): number { const { value, min, max } = this; @@ -139,52 +134,72 @@ export class PfProgress extends LitElement { return Math.min(percentage, 100); } - willUpdate(changed: PropertyValues) { + get #icon() { + return ICONS.get(this.variant ?? '')?.icon; + } + + override willUpdate(changed: PropertyValues) { if (changed.has('value') || changed.has('min') || changed.has('max')) { this.#internals.ariaValueNow = this.#calculatedPercentage.toString(); } + if (this.#icon) { + import('@patternfly/elements/pf-icon/pf-icon.js'); + } + if (this.descriptionTruncated) { + import('@patternfly/elements/pf-tooltip/pf-tooltip.js'); + } } render() { - const { size, measureLocation, variant, title } = this; - const icon = variant && ICONS.get(variant)?.icon; - const singleLine = title.length === 0; + const { size, measureLocation, variant, description, descriptionTruncated } = this; + const icon = this.#icon; + const singleLine = description?.length === 0; + const pct = this.#calculatedPercentage; + const width = `${pct}%`; + + const descriptionTemplate = (description ?? '') && html` + + `; return html` -
- - ${title ? - html` - ` : ''} - - ${measureLocation !== 'none' ? html`` : ''} - - - - - ${measureLocation === 'inside' ? html` - ` - : ''} +
+ + + ${!descriptionTruncated ? '' : html` + + `} + + ${measureLocation === 'none' ? '' : html` + + `} + + + + ${measureLocation !== 'inside' ? '' : html` + + `}
`; } } From dbf36c6bb76cc70edf1e36c4f88cd897391261cf Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 16:22:43 +0300 Subject: [PATCH 30/44] docs(progress): typos --- elements/pf-progress/README.md | 3 +-- .../demo/{truncated-title.html => truncated-description.html} | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename elements/pf-progress/demo/{truncated-title.html => truncated-description.html} (100%) diff --git a/elements/pf-progress/README.md b/elements/pf-progress/README.md index baefb3bfad..b03913e672 100644 --- a/elements/pf-progress/README.md +++ b/elements/pf-progress/README.md @@ -2,8 +2,7 @@ A progress bar gives the user a visual representation of their completion status of an ongoing process or task. -Read more about Progress Stepper in the [PatternFly Elements Progress -documentation][docs]. +Read more about Progress in the [PatternFly Elements Progress documentation][docs]. ## Installation diff --git a/elements/pf-progress/demo/truncated-title.html b/elements/pf-progress/demo/truncated-description.html similarity index 100% rename from elements/pf-progress/demo/truncated-title.html rename to elements/pf-progress/demo/truncated-description.html From 30871a4d8041540df8ba76e0b040706da2052840 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 16:26:40 +0300 Subject: [PATCH 31/44] fix(progress): truncated --- elements/pf-progress/pf-progress.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elements/pf-progress/pf-progress.css b/elements/pf-progress/pf-progress.css index c411911881..6f4226a05b 100644 --- a/elements/pf-progress/pf-progress.css +++ b/elements/pf-progress/pf-progress.css @@ -204,3 +204,7 @@ progress[value]::-webkit-progress-value { var(--pf-c-progress__bar--before--BackgroundColor) 100% ); } + +pf-tooltip { + height: 0.01px; +} From a6886f6a1ff86e573a42fe69af5722a3931401fb Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 18:09:21 +0300 Subject: [PATCH 32/44] fix(tooltip): detect when invoker slot should be block level --- elements/pf-tooltip/pf-tooltip.css | 5 +++++ elements/pf-tooltip/pf-tooltip.ts | 28 +++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/elements/pf-tooltip/pf-tooltip.css b/elements/pf-tooltip/pf-tooltip.css index cbe17e4435..b731903f80 100644 --- a/elements/pf-tooltip/pf-tooltip.css +++ b/elements/pf-tooltip/pf-tooltip.css @@ -13,10 +13,15 @@ --_floating-arrow-size: var(--pf-c-tooltip__arrow--Width, 0.5rem); } +#invoker.block { + display: block; +} + #tooltip, #tooltip::after { position: absolute; } + #tooltip { --_timestamp-text-decoration: none; --_timestamp-text-underline-offset: initial; diff --git a/elements/pf-tooltip/pf-tooltip.ts b/elements/pf-tooltip/pf-tooltip.ts index 2f00d1e8c0..1a211357bb 100644 --- a/elements/pf-tooltip/pf-tooltip.ts +++ b/elements/pf-tooltip/pf-tooltip.ts @@ -132,14 +132,21 @@ export class PfTooltip extends LitElement { converter: StringListConverter, }) flipBehavior?: Placement[]; - #referenceTrigger?: Element | null; + get #invoker(): HTMLSlotElement | null { + return this.shadowRoot?.querySelector('#invoker') ?? null; + } + + get #content(): HTMLElement | null { + return this.shadowRoot?.querySelector('#tooltip') ?? null; + } + + #blockInvoker: boolean; + + #referenceTrigger?: HTMLElement | null; #float = new FloatingDOMController(this, { - content: (): HTMLElement | undefined | null => - this.shadowRoot?.querySelector('#tooltip'), - invoker: () => this.#referenceTrigger ?? - this.shadowRoot?.querySelector('#invoker') - ?.assignedElements().at(0), + content: (): HTMLElement | null | undefined => this.#content, + invoker: (): HTMLElement | null | undefined => this.#referenceTrigger ?? this.#invoker, }); override connectedCallback() { @@ -152,6 +159,7 @@ export class PfTooltip extends LitElement { * them to the new trigger element. */ override willUpdate(changed: PropertyValues) { + this.#blockInvoker = this.#invoker?.assignedElements().length === 0 && this.#invoker?.assignedNodes().length > 0; if (changed.has('trigger')) { this.#updateTrigger(); } @@ -160,13 +168,19 @@ export class PfTooltip extends LitElement { override render() { const { alignment, anchor, open, styles } = this.#float; + const block = this.#blockInvoker; + return html`
- + ${this.content} From f49edc1a54b2048e6a4f01aa77cd95829904cc6c Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 8 Aug 2023 18:40:55 +0300 Subject: [PATCH 33/44] test(popover): clarify tests --- elements/pf-popover/test/pf-popover.spec.ts | 98 ++++++++++++++------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/elements/pf-popover/test/pf-popover.spec.ts b/elements/pf-popover/test/pf-popover.spec.ts index 0b32d38ff2..b37b2efbeb 100644 --- a/elements/pf-popover/test/pf-popover.spec.ts +++ b/elements/pf-popover/test/pf-popover.spec.ts @@ -84,7 +84,11 @@ describe('', function() { expect(snapshot.children).to.deep.equal([{ focused: true, name: 'Toggle popover', role: 'button' }]); }); - it('should properly clean up event handlers', async () => { + describe('with a trigger and a sibling button', function() { + let snapshot: A11yTreeSnapshot; + let popover: PfPopover; + let btn1: HTMLButtonElement; + let btn2: HTMLButtonElement; const expectClose = () => expect(snapshot.children).to.deep.equal([ { @@ -126,38 +130,64 @@ describe('', function() { role: 'button', }, ]); - fixtureCleanup(); - const container = await fixture(html` -
- - - - -
- `); - snapshot = await a11ySnapshot(); - const popover: PfPopover | null = container.querySelector('pf-popover'); - const btn1: HTMLButtonElement | null = container.querySelector('#btn-1'); - const btn2: HTMLButtonElement | null = container.querySelector('#btn-2'); - expectClose(); - btn1?.click(); - snapshot = await a11ySnapshot(); - expectOpen(); - // Close the popover - await sendKeys({ press: 'Enter' }); - // Update trigger element - popover?.setAttribute('trigger', 'btn-2'); - btn1?.click(); - snapshot = await a11ySnapshot(); - expectClose(); - btn2?.click(); - snapshot = await a11ySnapshot(); - expectOpen(); + beforeEach(async function() { + fixtureCleanup(); + const container = await fixture(html` +
+ + + + +
+ `); + popover = container.querySelector('pf-popover')!; + btn1 = container.querySelector('#btn-1')!; + btn2 = container.querySelector('#btn-2')!; + snapshot = await a11ySnapshot(); + }); + it('starts closed', expectClose); + describe('clicking the trigger', function() { + beforeEach(async function() { + btn1.click(); + await popover.updateComplete; + snapshot = await a11ySnapshot(); + }); + it('shows the popover', expectOpen); + describe('then pressing the Enter key', function() { + beforeEach(async function() { + // Close the popover + await sendKeys({ press: 'Enter' }); + }); + it('closes the popover', expectClose); + describe('then setting the trigger to the sibling button', function() { + beforeEach(async function() { + // Update trigger element + popover.setAttribute('trigger', 'btn-2'); + await popover.updateComplete; + snapshot = await a11ySnapshot(); + }); + describe('clicking the first button', function() { + beforeEach(async function() { + btn1.click(); + }); + it('remains closed', expectClose); + }); + describe('clicking the sibling button', function() { + beforeEach(async function() { + btn2.click(); + await popover.updateComplete; + snapshot = await a11ySnapshot(); + }); + it('shows the popup', expectOpen); + }); + }); + }); + }); }); }); From 372f2eddc03fb3746392845ac800d61eeac69050 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Tue, 8 Aug 2023 15:27:18 -0400 Subject: [PATCH 34/44] fix(tooltip): tooltip invoker is called depending on whether it has assigned elements --- elements/pf-tooltip/demo/flip.html | 10 ++++------ elements/pf-tooltip/pf-tooltip.ts | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/elements/pf-tooltip/demo/flip.html b/elements/pf-tooltip/demo/flip.html index f5d21e2a4f..dbbc4b63dc 100644 --- a/elements/pf-tooltip/demo/flip.html +++ b/elements/pf-tooltip/demo/flip.html @@ -1,7 +1,6 @@
- Tooltip! @@ -27,9 +26,8 @@
- Tooltip! diff --git a/elements/pf-tooltip/pf-tooltip.ts b/elements/pf-tooltip/pf-tooltip.ts index 1a211357bb..1c2b86e8ac 100644 --- a/elements/pf-tooltip/pf-tooltip.ts +++ b/elements/pf-tooltip/pf-tooltip.ts @@ -1,3 +1,4 @@ +import type { PropertyValues } from 'lit'; import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; @@ -140,13 +141,23 @@ export class PfTooltip extends LitElement { return this.shadowRoot?.querySelector('#tooltip') ?? null; } - #blockInvoker: boolean; + #blockInvoker = false; #referenceTrigger?: HTMLElement | null; #float = new FloatingDOMController(this, { content: (): HTMLElement | null | undefined => this.#content, - invoker: (): HTMLElement | null | undefined => this.#referenceTrigger ?? this.#invoker, + invoker: (): HTMLElement | null | undefined => { + if (this.#referenceTrigger) { + return this.#referenceTrigger; + } + if (this.#invoker !== null && this.#invoker instanceof HTMLSlotElement && this.#invoker.assignedElements().length > 0) { + return this.#invoker.assignedElements().at(0) as HTMLElement; + } else if (this.#invoker !== null) { + return this.#invoker; + } + return undefined; + }, }); override connectedCallback() { @@ -189,13 +200,13 @@ export class PfTooltip extends LitElement { } #getReferenceTrigger() { - return (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger); + return (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger?.normalize() ?? ''); } #updateTrigger() { const oldReferenceTrigger = this.#referenceTrigger; this.#referenceTrigger = - this.trigger instanceof Element ? this.trigger + this.trigger instanceof HTMLElement ? this.trigger : typeof this.trigger === 'string' ? this.#getReferenceTrigger() : null; for (const evt of EnterEvents) { From ad77a779b0151163ce99d5515ffae5660332d410 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Wed, 9 Aug 2023 09:07:41 +0300 Subject: [PATCH 35/44] perf(popover): reassign trigger less often --- elements/pf-popover/pf-popover.ts | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/elements/pf-popover/pf-popover.ts b/elements/pf-popover/pf-popover.ts index ee3ad2a0b7..c23126ff56 100644 --- a/elements/pf-popover/pf-popover.ts +++ b/elements/pf-popover/pf-popover.ts @@ -358,7 +358,10 @@ export class PfPopover extends LitElement {
- +
@@ -391,6 +394,23 @@ export class PfPopover extends LitElement { this.#referenceTrigger?.removeEventListener('keydown', this.onKeydown); } + #getReferenceTrigger() { + const root = this.getRootNode() as Document | ShadowRoot; + return !this.trigger ? null : root.getElementById(this.trigger); + } + + + #triggerChanged() { + const oldReferenceTrigger = this.#referenceTrigger; + this.#referenceTrigger = this.#getReferenceTrigger(); + if (oldReferenceTrigger !== this.#referenceTrigger) { + oldReferenceTrigger?.removeEventListener('click', this.show); + oldReferenceTrigger?.removeEventListener('keydown', this.onKeydown); + this.#referenceTrigger?.addEventListener('click', this.show); + this.#referenceTrigger?.addEventListener('keydown', this.onKeydown); + } + } + @bound private onKeydown(event: KeyboardEvent) { switch (event.key) { case 'Escape': @@ -420,13 +440,7 @@ export class PfPopover extends LitElement { */ override willUpdate(changed: PropertyValues) { if (changed.has('trigger')) { - this.#referenceTrigger?.removeEventListener('click', this.show); - this.#referenceTrigger?.removeEventListener('keydown', this.onKeydown); - if (this.trigger) { - this.#referenceTrigger = (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger); - this.#referenceTrigger?.addEventListener('click', this.show); - this.#referenceTrigger?.addEventListener('keydown', this.onKeydown); - } + this.#triggerChanged(); } } From 75af29b052adb73e89cddbb23ccf767b63c6d971 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Wed, 9 Aug 2023 09:08:57 +0300 Subject: [PATCH 36/44] feat(tools): click element center test util --- .changeset/test-tools-click-el.md | 4 ++++ tools/pfe-tools/test/utils.ts | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/test-tools-click-el.md diff --git a/.changeset/test-tools-click-el.md b/.changeset/test-tools-click-el.md new file mode 100644 index 0000000000..d0166aab01 --- /dev/null +++ b/.changeset/test-tools-click-el.md @@ -0,0 +1,4 @@ +--- +"@patternfly/pfe-tools": minor +--- +Test: add `clickElementCenter` utility function for tests diff --git a/tools/pfe-tools/test/utils.ts b/tools/pfe-tools/test/utils.ts index 6ce1f0f986..5691d11d6c 100644 --- a/tools/pfe-tools/test/utils.ts +++ b/tools/pfe-tools/test/utils.ts @@ -1,3 +1,4 @@ +import { sendMouse } from '@web/test-runner-commands'; import type { ReactiveElement } from 'lit'; export type Position = [x: number, y: number]; @@ -11,6 +12,11 @@ export function getElementPosition(element: Element): Position { ]; } +export async function clickElementCenter(element: Element): Promise { + const position = getElementPosition(element); + await sendMouse({ type: 'click', position }); +} + /** * Waits for an element to completely finish updating, or throws after 100 attempts * Will also throw if the element doesn't have an `updateComplete` promise From e08600a54e34f6f6ca17aa4bc2cd7ccd2721a9f1 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Wed, 9 Aug 2023 09:09:42 +0300 Subject: [PATCH 37/44] test(popover): rationalize tests --- elements/pf-popover/test/pf-popover.spec.ts | 245 +++++++++++--------- 1 file changed, 140 insertions(+), 105 deletions(-) diff --git a/elements/pf-popover/test/pf-popover.spec.ts b/elements/pf-popover/test/pf-popover.spec.ts index b37b2efbeb..a7051f6f77 100644 --- a/elements/pf-popover/test/pf-popover.spec.ts +++ b/elements/pf-popover/test/pf-popover.spec.ts @@ -1,96 +1,123 @@ import { expect, html, fixture, fixtureCleanup } from '@open-wc/testing'; -import type { A11yTreeSnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; -import { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; -import { sendKeys } from '@web/test-runner-commands'; +import { a11ySnapshot, type A11yTreeSnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; +import { clickElementCenter } from '@patternfly/pfe-tools/test/utils.js'; +import { sendKeys, resetMouse } from '@web/test-runner-commands'; import { PfPopover } from '@patternfly/elements/pf-popover/pf-popover.js'; import { PfButton } from '@patternfly/elements/pf-button/pf-button.js'; -describe('', function() { - let element: PfPopover; - let snapshot: A11yTreeSnapshot; - - beforeEach(async function() { - element = await fixture(html` - - Toggle popover - - `); - snapshot = await a11ySnapshot(); - }); +const takeProps = (props: string[]) => (obj: object) => + Object.fromEntries(Object.entries(obj).filter(([k]) => props.includes(k))); - it('imperatively instantiates', function() { - expect(document.createElement('pf-popover')).to.be.an.instanceof(PfPopover); - }); +function press(key: string) { + return async function() { + await sendKeys({ press: key }); + }; +} - it('should upgrade', async function() { - const klass = customElements.get('pf-popover'); - expect(element).to.be.an.instanceOf(klass).and.to.be.an.instanceOf(PfPopover); - }); +describe('', function() { + describe('simply instantiating', function() { + let element: PfPopover; + let snapshot: A11yTreeSnapshot; - it('should be accessible', async function() { - await expect(element).shadowDom.to.be.accessible(); + beforeEach(async function() { + element = await fixture(html``); + snapshot = await a11ySnapshot(); + }); + it('should upgrade', async function() { + const klass = customElements.get('pf-popover'); + expect(element).to.be.an.instanceOf(klass).and.to.be.an.instanceOf(PfPopover); + }); + it('should be accessible', async function() { + await expect(element).to.be.accessible(); + }); + it('imperatively instantiates', function() { + expect(document.createElement('pf-popover')).to.be.an.instanceof(PfPopover); + }); + it('should hide popover content from assistive technology', function() { + expect(snapshot.children).to.be.undefined; + }); }); - it('should hide popover content from assistive technology', function() { - expect(snapshot.children).to.deep.equal([{ name: 'Toggle popover', role: 'button' }]); - }); + describe('with a slotted trigger and heading, body, and footer attributes', function() { + let element: PfPopover; - it('should show popover content to assistive technology', async function() { - await sendKeys({ press: 'Tab' }); - expect(document.activeElement).to.be.an.instanceof(PfButton); - await sendKeys({ press: 'Enter' }); - snapshot = await a11ySnapshot(); - expect(snapshot.children).to.deep.equal([ - { + async function expectClosed() { + const snapshot = await a11ySnapshot(); + expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([{ name: 'Toggle popover', role: 'button', - }, - { - focused: true, - name: 'Close popover', - role: 'button', - }, - { - level: 6, - name: 'Popover heading', - role: 'heading', - }, - { - name: 'Popovers are triggered by click rather than hover.', - role: 'text', - }, - { - name: 'Popover footer', - role: 'text', - }, - ]); - }); + }]); + } - it('should be closeable on close button select', async function() { - await sendKeys({ press: 'Tab' }); - await sendKeys({ press: 'Enter' }); - await sendKeys({ press: 'Enter' }); - snapshot = await a11ySnapshot(); - expect(snapshot.children).to.deep.equal([{ focused: true, name: 'Toggle popover', role: 'button' }]); - }); + async function expectOpen() { + const snapshot = await a11ySnapshot(); + expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([ + { + name: 'Toggle popover', + role: 'button', + }, + { + name: 'Close popover', + role: 'button', + }, + { + name: 'Popover heading', + role: 'heading', + }, + { + name: 'Popovers are triggered by click rather than hover.', + role: 'text', + }, + { + name: 'Popover footer', + role: 'text', + }, + ]); + } - it('should be closeable on escape', async function() { - await sendKeys({ press: 'Tab' }); - await sendKeys({ press: 'Enter' }); - await sendKeys({ press: 'Escape' }); - snapshot = await a11ySnapshot(); - expect(snapshot.children).to.deep.equal([{ focused: true, name: 'Toggle popover', role: 'button' }]); + beforeEach(async function() { + element = await fixture(html` + + Toggle popover + + `); + }); + it('should be accessible', async function() { + await expect(element).to.be.accessible(); + }); + it('should hide popover content from assistive technology', expectClosed); + describe('tabbing to the trigger', function() { + beforeEach(press('Tab')); + beforeEach(function() { + expect(document.activeElement).to.be.an.instanceof(PfButton); + }); + + describe('and pressing Enter', function() { + beforeEach(press('Enter')); + it('should show popover content to assistive technology', expectOpen); + describe('then pressing enter again', function() { + beforeEach(press('Enter')); + it('should hide popover content from assistive technology', expectClosed); + }); + describe('then pressing Escape', function() { + beforeEach(press('Escape')); + it('should hide popover content from assistive technology', expectClosed); + }); + }); + }); }); describe('with a trigger and a sibling button', function() { - let snapshot: A11yTreeSnapshot; - let popover: PfPopover; + let element: PfPopover; let btn1: HTMLButtonElement; let btn2: HTMLButtonElement; - const expectClose = () => - expect(snapshot.children).to.deep.equal([ + + async function expectClose() { + const snapshot = await a11ySnapshot(); + expect(snapshot.children.length).to.equal(2); + expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([ { name: 'Toggle popover 1', role: 'button', @@ -100,16 +127,17 @@ describe('', function() { role: 'button', }, ]); + } - const expectOpen = () => - expect(snapshot.children).to.deep.equal([ + async function expectOpen() { + const snapshot = await a11ySnapshot(); + expect(snapshot.children.length).to.equal(6); + expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([ { - focused: true, name: 'Close popover', role: 'button', }, { - level: 6, name: 'Popover heading', role: 'heading', }, @@ -130,7 +158,10 @@ describe('', function() { role: 'button', }, ]); + } + beforeEach(async function() { + resetMouse(); fixtureCleanup(); const container = await fixture(html`
@@ -146,48 +177,52 @@ describe('', function() {
`); - popover = container.querySelector('pf-popover')!; + element = container.querySelector('pf-popover')!; btn1 = container.querySelector('#btn-1')!; btn2 = container.querySelector('#btn-2')!; - snapshot = await a11ySnapshot(); }); + it('starts closed', expectClose); describe('clicking the trigger', function() { beforeEach(async function() { - btn1.click(); - await popover.updateComplete; - snapshot = await a11ySnapshot(); + await element.updateComplete; + await clickElementCenter(btn1); + await element.updateComplete; }); it('shows the popover', expectOpen); - describe('then pressing the Enter key', function() { + describe('then setting the trigger to the sibling button', function() { beforeEach(async function() { - // Close the popover - await sendKeys({ press: 'Enter' }); + await element.updateComplete; + // Update trigger element + element.setAttribute('trigger', 'btn-2'); + await element.updateComplete; }); - it('closes the popover', expectClose); - describe('then setting the trigger to the sibling button', function() { + describe('clicking the first button', function() { beforeEach(async function() { - // Update trigger element - popover.setAttribute('trigger', 'btn-2'); - await popover.updateComplete; - snapshot = await a11ySnapshot(); - }); - describe('clicking the first button', function() { - beforeEach(async function() { - btn1.click(); - }); - it('remains closed', expectClose); + await element.updateComplete; + await clickElementCenter(btn1); + await element.updateComplete; }); - describe('clicking the sibling button', function() { - beforeEach(async function() { - btn2.click(); - await popover.updateComplete; - snapshot = await a11ySnapshot(); - }); - it('shows the popup', expectOpen); + it('remains closed', expectClose); + }); + describe('clicking the sibling button', function() { + beforeEach(async function() { + await element.updateComplete; + await clickElementCenter(btn2); + await element.updateComplete; }); + it('shows the popup', expectOpen); }); }); }); + describe('then pressing the Enter key', function() { + beforeEach(async function() { + // Close the popover + await element.updateComplete; + await sendKeys({ press: 'Enter' }); + await element.updateComplete; + }); + it('closes the popover', expectClose); + }); }); }); From 8a0290225e1441dfb48d9bdfaf99fa1d551463fc Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Wed, 9 Aug 2023 09:10:58 +0300 Subject: [PATCH 38/44] perf(tooltip): calculate internal state less often --- elements/pf-tooltip/pf-tooltip.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/elements/pf-tooltip/pf-tooltip.ts b/elements/pf-tooltip/pf-tooltip.ts index 1c2b86e8ac..ca7c56ebb8 100644 --- a/elements/pf-tooltip/pf-tooltip.ts +++ b/elements/pf-tooltip/pf-tooltip.ts @@ -150,18 +150,17 @@ export class PfTooltip extends LitElement { invoker: (): HTMLElement | null | undefined => { if (this.#referenceTrigger) { return this.#referenceTrigger; - } - if (this.#invoker !== null && this.#invoker instanceof HTMLSlotElement && this.#invoker.assignedElements().length > 0) { + } else if (this.#invoker instanceof HTMLSlotElement && this.#invoker.assignedElements().length > 0) { return this.#invoker.assignedElements().at(0) as HTMLElement; - } else if (this.#invoker !== null) { + } else { return this.#invoker; } - return undefined; }, }); override connectedCallback() { super.connectedCallback(); + this.#invokerChanged(); this.#updateTrigger(); } @@ -170,7 +169,6 @@ export class PfTooltip extends LitElement { * them to the new trigger element. */ override willUpdate(changed: PropertyValues) { - this.#blockInvoker = this.#invoker?.assignedElements().length === 0 && this.#invoker?.assignedNodes().length > 0; if (changed.has('trigger')) { this.#updateTrigger(); } @@ -189,7 +187,7 @@ export class PfTooltip extends LitElement { [alignment]: !!alignment })}"> 0; + this.requestUpdate(); + } + #getReferenceTrigger() { return (this.getRootNode() as Document | ShadowRoot).getElementById(this.trigger?.normalize() ?? ''); } From 87878514f4f1301ecba293fc6f8efd5271935531 Mon Sep 17 00:00:00 2001 From: Ivana Rodriguez Date: Thu, 10 Aug 2023 10:21:04 -0400 Subject: [PATCH 39/44] fix: trigger attached by reference should toggle popover --- elements/pf-popover/pf-popover.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elements/pf-popover/pf-popover.ts b/elements/pf-popover/pf-popover.ts index c23126ff56..be5dd10262 100644 --- a/elements/pf-popover/pf-popover.ts +++ b/elements/pf-popover/pf-popover.ts @@ -390,7 +390,7 @@ export class PfPopover extends LitElement { disconnectedCallback() { super.disconnectedCallback(); PfPopover.instances.delete(this); - this.#referenceTrigger?.removeEventListener('click', this.show); + this.#referenceTrigger?.removeEventListener('click', this.toggle); this.#referenceTrigger?.removeEventListener('keydown', this.onKeydown); } @@ -404,9 +404,9 @@ export class PfPopover extends LitElement { const oldReferenceTrigger = this.#referenceTrigger; this.#referenceTrigger = this.#getReferenceTrigger(); if (oldReferenceTrigger !== this.#referenceTrigger) { - oldReferenceTrigger?.removeEventListener('click', this.show); + oldReferenceTrigger?.removeEventListener('click', this.toggle); oldReferenceTrigger?.removeEventListener('keydown', this.onKeydown); - this.#referenceTrigger?.addEventListener('click', this.show); + this.#referenceTrigger?.addEventListener('click', this.toggle); this.#referenceTrigger?.addEventListener('keydown', this.onKeydown); } } From ff49508d57f751f339866e78d0f49c41865966ea Mon Sep 17 00:00:00 2001 From: Ivana Rodriguez Date: Fri, 11 Aug 2023 15:06:29 -0400 Subject: [PATCH 40/44] fix: test nesting --- elements/pf-popover/test/pf-popover.spec.ts | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/elements/pf-popover/test/pf-popover.spec.ts b/elements/pf-popover/test/pf-popover.spec.ts index a7051f6f77..613dab337d 100644 --- a/elements/pf-popover/test/pf-popover.spec.ts +++ b/elements/pf-popover/test/pf-popover.spec.ts @@ -190,29 +190,29 @@ describe('', function() { await element.updateComplete; }); it('shows the popover', expectOpen); - describe('then setting the trigger to the sibling button', function() { + }); + describe('then setting the trigger to the sibling button', function() { + beforeEach(async function() { + await element.updateComplete; + // Update trigger element + element.setAttribute('trigger', 'btn-2'); + await element.updateComplete; + }); + describe('clicking the first button', function() { beforeEach(async function() { await element.updateComplete; - // Update trigger element - element.setAttribute('trigger', 'btn-2'); + await clickElementCenter(btn1); await element.updateComplete; }); - describe('clicking the first button', function() { - beforeEach(async function() { - await element.updateComplete; - await clickElementCenter(btn1); - await element.updateComplete; - }); - it('remains closed', expectClose); - }); - describe('clicking the sibling button', function() { - beforeEach(async function() { - await element.updateComplete; - await clickElementCenter(btn2); - await element.updateComplete; - }); - it('shows the popup', expectOpen); + it('remains closed', expectClose); + }); + describe('clicking the sibling button', function() { + beforeEach(async function() { + await element.updateComplete; + await clickElementCenter(btn2); + await element.updateComplete; }); + it('shows the popup', expectOpen); }); }); describe('then pressing the Enter key', function() { From d73065523d5dcd6c5b6297aede6cca9da9f10688 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 20 Aug 2023 12:13:35 +0300 Subject: [PATCH 41/44] test(popover): refactor tests --- elements/pf-popover/test/pf-popover.spec.ts | 280 ++++++++++++-------- 1 file changed, 172 insertions(+), 108 deletions(-) diff --git a/elements/pf-popover/test/pf-popover.spec.ts b/elements/pf-popover/test/pf-popover.spec.ts index 613dab337d..91ed38445d 100644 --- a/elements/pf-popover/test/pf-popover.spec.ts +++ b/elements/pf-popover/test/pf-popover.spec.ts @@ -15,43 +15,110 @@ function press(key: string) { } describe('', function() { + let element: PfPopover; + + /** create a simple test fixture */ + async function setupSimpleInstance() { + element = await fixture(html``); + } + + /** create a test fixture with slotted trigger and content attrs */ + async function setupPopoverWithSlottedTriggerAndContentAttrs() { + element = await fixture(html` + + Toggle popover + + `); + } + + /** Wait on the element's update cycle */ + async function updateComplete() { + await element.updateComplete; + } + + /** Asserts that an aXe audit on the page passes */ + async function expectA11yAxe() { + await expect(element).to.be.accessible(); + } + + /** + * Assert that the accessibility tree reports the expected snapshot + * e.g. for a closed popover, does not announce popover child content + * e.g. for an opened popover, it does announce popover child content + * If the expected children snapshot is undefined, then assistive technology + * reports nothing at all, e.g. a popover element with no attrs and no children + */ + function expectA11ySnapshot(expected?: Pick[]) { + return async function() { + const snapshot = await a11ySnapshot(); + expect(snapshot.children?.map(takeProps(['name', 'role']))) + .to.deep.equal(expected); + }; + } + + function resetElement() { + // @ts-expect-error: resetting test state, so we don't mind the ts error. + element = undefined; + } + + afterEach(resetElement); + afterEach(fixtureCleanup); + describe('simply instantiating', function() { - let element: PfPopover; - let snapshot: A11yTreeSnapshot; + /** Setup the a11y tree snapshot expected results for this suite */ + const snapshots = { + opened: [ + { + name: 'Toggle popover', + role: 'button', + }, + { + name: 'Close popover', + role: 'button', + }, + { + name: 'Popover heading', + role: 'heading', + }, + { + name: 'Popovers are triggered by click rather than hover.', + role: 'text', + }, + { + name: 'Popover footer', + role: 'text', + }, + ], + closed: [ + { + name: 'Toggle popover', + role: 'button', + } + ], + }; - beforeEach(async function() { - element = await fixture(html``); - snapshot = await a11ySnapshot(); - }); + beforeEach(setupSimpleInstance); it('should upgrade', async function() { const klass = customElements.get('pf-popover'); - expect(element).to.be.an.instanceOf(klass).and.to.be.an.instanceOf(PfPopover); - }); - it('should be accessible', async function() { - await expect(element).to.be.accessible(); + expect(element) + .to.be.an.instanceOf(klass) + .and + .to.be.an.instanceOf(PfPopover); }); + it('should be accessible', expectA11yAxe); it('imperatively instantiates', function() { - expect(document.createElement('pf-popover')).to.be.an.instanceof(PfPopover); - }); - it('should hide popover content from assistive technology', function() { - expect(snapshot.children).to.be.undefined; + expect(document.createElement('pf-popover')) + .to.be.an.instanceof(PfPopover); }); + it('should not report anything to assistive technology', expectA11ySnapshot()); }); - describe('with a slotted trigger and heading, body, and footer attributes', function() { - let element: PfPopover; - - async function expectClosed() { - const snapshot = await a11ySnapshot(); - expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([{ - name: 'Toggle popover', - role: 'button', - }]); - } - - async function expectOpen() { - const snapshot = await a11ySnapshot(); - expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([ + describe('with a slotted trigger; and with heading, body, and footer attributes', function() { + /** Setup the a11y tree snapshot expected results for this suite */ + const snapshots = { + opened: [ { name: 'Toggle popover', role: 'button', @@ -72,67 +139,57 @@ describe('', function() { name: 'Popover footer', role: 'text', }, - ]); - } + ], + closed: [ + { + name: 'Toggle popover', + role: 'button', + } + ], + }; + + beforeEach(setupPopoverWithSlottedTriggerAndContentAttrs); + + it('should be accessible', expectA11yAxe); + it('should hide popover content from assistive technology', expectA11ySnapshot(snapshots.closed)); - beforeEach(async function() { - element = await fixture(html` - - Toggle popover - - `); - }); - it('should be accessible', async function() { - await expect(element).to.be.accessible(); - }); - it('should hide popover content from assistive technology', expectClosed); describe('tabbing to the trigger', function() { + beforeEach(updateComplete); beforeEach(press('Tab')); - beforeEach(function() { + beforeEach(updateComplete); + + it('doesn\'t steal tab order', function() { expect(document.activeElement).to.be.an.instanceof(PfButton); }); describe('and pressing Enter', function() { + beforeEach(updateComplete); beforeEach(press('Enter')); - it('should show popover content to assistive technology', expectOpen); - describe('then pressing enter again', function() { + beforeEach(updateComplete); + it('should show popover content to assistive technology', expectA11ySnapshot(snapshots.opened)); + describe('then pressing Enter again', function() { + beforeEach(updateComplete); beforeEach(press('Enter')); - it('should hide popover content from assistive technology', expectClosed); + beforeEach(updateComplete); + it('should hide popover content from assistive technology', expectA11ySnapshot(snapshots.closed)); }); describe('then pressing Escape', function() { + beforeEach(updateComplete); beforeEach(press('Escape')); - it('should hide popover content from assistive technology', expectClosed); + beforeEach(updateComplete); + it('should hide popover content from assistive technology', expectA11ySnapshot(snapshots.closed)); }); }); }); }); describe('with a trigger and a sibling button', function() { - let element: PfPopover; let btn1: HTMLButtonElement; let btn2: HTMLButtonElement; - async function expectClose() { - const snapshot = await a11ySnapshot(); - expect(snapshot.children.length).to.equal(2); - expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([ - { - name: 'Toggle popover 1', - role: 'button', - }, - { - name: 'Toggle popover 2', - role: 'button', - }, - ]); - } - - async function expectOpen() { - const snapshot = await a11ySnapshot(); - expect(snapshot.children.length).to.equal(6); - expect(snapshot.children.map(takeProps(['name', 'role']))).to.deep.equal([ + /** Setup the a11y tree snapshot expected results for this suite */ + const snapshots = { + opened: [ { name: 'Close popover', role: 'button', @@ -157,22 +214,37 @@ describe('', function() { name: 'Toggle popover 2', role: 'button', }, - ]); + ], + closed: [ + { + name: 'Toggle popover 1', + role: 'button', + }, + { + name: 'Toggle popover 2', + role: 'button', + }, + ], + }; + + async function clickButton1() { + await clickElementCenter(btn1); + await resetMouse(); + } + + async function clickButton2() { + await clickElementCenter(btn2); + await resetMouse(); } beforeEach(async function() { - resetMouse(); - fixtureCleanup(); const container = await fixture(html`
- - +
@@ -182,47 +254,39 @@ describe('', function() { btn2 = container.querySelector('#btn-2')!; }); - it('starts closed', expectClose); + it('starts closed', expectA11ySnapshot(snapshots.closed)); describe('clicking the trigger', function() { - beforeEach(async function() { - await element.updateComplete; - await clickElementCenter(btn1); - await element.updateComplete; - }); - it('shows the popover', expectOpen); + beforeEach(updateComplete); + beforeEach(clickButton1); + beforeEach(updateComplete); + it('shows the popover', expectA11ySnapshot(snapshots.opened)); }); describe('then setting the trigger to the sibling button', function() { + beforeEach(updateComplete); + // set trigger attr to the id of the second button beforeEach(async function() { - await element.updateComplete; - // Update trigger element element.setAttribute('trigger', 'btn-2'); - await element.updateComplete; }); + beforeEach(updateComplete); describe('clicking the first button', function() { - beforeEach(async function() { - await element.updateComplete; - await clickElementCenter(btn1); - await element.updateComplete; - }); - it('remains closed', expectClose); + beforeEach(updateComplete); + beforeEach(clickButton1); + beforeEach(updateComplete); + it('remains closed', expectA11ySnapshot(snapshots.closed)); }); describe('clicking the sibling button', function() { - beforeEach(async function() { - await element.updateComplete; - await clickElementCenter(btn2); - await element.updateComplete; - }); - it('shows the popup', expectOpen); + beforeEach(updateComplete); + beforeEach(clickButton2); + beforeEach(updateComplete); + it('shows the popup', expectA11ySnapshot(snapshots.opened)); }); }); describe('then pressing the Enter key', function() { - beforeEach(async function() { - // Close the popover - await element.updateComplete; - await sendKeys({ press: 'Enter' }); - await element.updateComplete; - }); - it('closes the popover', expectClose); + beforeEach(updateComplete); + // Close the popover + beforeEach(press('Enter')); + beforeEach(updateComplete); + it('closes the popover', expectA11ySnapshot(snapshots.closed)); }); }); }); From 69619e387c252efbaf560c9694541ec94b219856 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 20 Aug 2023 12:19:23 +0300 Subject: [PATCH 42/44] test: refactor --- elements/pf-popover/test/pf-popover.spec.ts | 32 --------------------- 1 file changed, 32 deletions(-) diff --git a/elements/pf-popover/test/pf-popover.spec.ts b/elements/pf-popover/test/pf-popover.spec.ts index 91ed38445d..d55dbc369a 100644 --- a/elements/pf-popover/test/pf-popover.spec.ts +++ b/elements/pf-popover/test/pf-popover.spec.ts @@ -67,38 +67,6 @@ describe('', function() { afterEach(fixtureCleanup); describe('simply instantiating', function() { - /** Setup the a11y tree snapshot expected results for this suite */ - const snapshots = { - opened: [ - { - name: 'Toggle popover', - role: 'button', - }, - { - name: 'Close popover', - role: 'button', - }, - { - name: 'Popover heading', - role: 'heading', - }, - { - name: 'Popovers are triggered by click rather than hover.', - role: 'text', - }, - { - name: 'Popover footer', - role: 'text', - }, - ], - closed: [ - { - name: 'Toggle popover', - role: 'button', - } - ], - }; - beforeEach(setupSimpleInstance); it('should upgrade', async function() { const klass = customElements.get('pf-popover'); From 4e4e32530e44b2a13948cefe9d512e3a0d4016a8 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 20 Aug 2023 13:50:43 +0300 Subject: [PATCH 43/44] chore: fix netlify deploy command --- .github/workflows/preview.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 13df7a4aeb..64543539cf 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -30,7 +30,12 @@ jobs: env: NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - run: npx netlify-cli deploy --alias=deploy-preview-${{github.event.number}} --dir=_site + NETLIFY_DEPLOY_ALIAS: deploy-preview-${{github.event.number}} + run: > + npx netlify-cli deploy + --dir _site + --filter @patternfly/elements + --alias $NETLIFY_DEPLOY_ALIAS - name: Post Previews uses: actions/github-script@v6 From f49d0cfa92dd88292560ab709ea21381a6a274e3 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Sun, 20 Aug 2023 14:03:29 +0300 Subject: [PATCH 44/44] refactor(progress): remove unused variable --- elements/pf-progress/pf-progress.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/elements/pf-progress/pf-progress.ts b/elements/pf-progress/pf-progress.ts index c50759c612..a8dc28e021 100644 --- a/elements/pf-progress/pf-progress.ts +++ b/elements/pf-progress/pf-progress.ts @@ -105,10 +105,15 @@ export class PfProgress extends LitElement { /** Represents the value of the progress bar */ @property({ reflect: true, type: Number }) value = 0; - /** Title above the progress bar */ + /** Description (title) above the progress bar */ @property() description?: string; - @property({ type: Boolean, reflect: true, attribute: 'description-truncated' }) descriptionTruncated = false; + /** Indicate whether to truncate the string description (title) */ + @property({ + type: Boolean, + reflect: true, + attribute: 'description-truncated', + }) descriptionTruncated = false; /** Maximum value for the progress bar */ @property({ type: Number, reflect: true }) max = 100; @@ -157,10 +162,6 @@ export class PfProgress extends LitElement { const pct = this.#calculatedPercentage; const width = `${pct}%`; - const descriptionTemplate = (description ?? '') && html` - - `; - return html`
+ ${!descriptionTruncated ? '' : html`