From 3baa4987bb684790087ff03e41d34f48c86edfce Mon Sep 17 00:00:00 2001 From: Benny Powers <web@bennypowers.com> Date: Thu, 19 Oct 2023 11:37:11 +0300 Subject: [PATCH 1/7] fix(label)!: remove BaseLabel Closes #2620 --- .changeset/remove-base-label.md | 4 ++ elements/package.json | 1 - elements/pf-label/BaseLabel.css | 44 ---------------- elements/pf-label/BaseLabel.ts | 53 ------------------- elements/pf-label/pf-label.css | 41 +++++++++++++-- elements/pf-label/pf-label.ts | 93 +++++++++++++++++---------------- 6 files changed, 90 insertions(+), 146 deletions(-) create mode 100644 .changeset/remove-base-label.md delete mode 100644 elements/pf-label/BaseLabel.css delete mode 100644 elements/pf-label/BaseLabel.ts diff --git a/.changeset/remove-base-label.md b/.changeset/remove-base-label.md new file mode 100644 index 0000000000..bc79ff2729 --- /dev/null +++ b/.changeset/remove-base-label.md @@ -0,0 +1,4 @@ +--- +"@patternfly/elements": major +--- +`<pf-label>`: Removed `BaseLabel` class. Reimplement (recommended) or extend `PfLabel`. diff --git a/elements/package.json b/elements/package.json index 0cd47fe88f..192ad19080 100644 --- a/elements/package.json +++ b/elements/package.json @@ -35,7 +35,6 @@ "./pf-jump-links/pf-jump-links-item.js": "./pf-jump-links/pf-jump-links-item.js", "./pf-jump-links/pf-jump-links-list.js": "./pf-jump-links/pf-jump-links-list.js", "./pf-jump-links/pf-jump-links.js": "./pf-jump-links/pf-jump-links.js", - "./pf-label/BaseLabel.js": "./pf-label/BaseLabel.js", "./pf-label/pf-label.js": "./pf-label/pf-label.js", "./pf-modal/pf-modal.js": "./pf-modal/pf-modal.js", "./pf-panel/pf-panel.js": "./pf-panel/pf-panel.js", diff --git a/elements/pf-label/BaseLabel.css b/elements/pf-label/BaseLabel.css deleted file mode 100644 index 178d4ed79a..0000000000 --- a/elements/pf-label/BaseLabel.css +++ /dev/null @@ -1,44 +0,0 @@ -:host { - position: relative; - white-space: nowrap; - border: 0; -} - -pf-icon, ::slotted(pf-icon) { - color: currentColor; -} - -:host, -#container { - display: inline-flex; - align-items: center; - vertical-align: middle; -} - -#container { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - border-width: 0; -} - -#container::before { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - pointer-events: none; - content: ""; -} - -[part=icon] { - display: none; - pointer-events: none; -} - -.hasIcon [part=icon] { - display: inline-flex; - width: 1em; -} - diff --git a/elements/pf-label/BaseLabel.ts b/elements/pf-label/BaseLabel.ts deleted file mode 100644 index a3f524c6cb..0000000000 --- a/elements/pf-label/BaseLabel.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { LitElement, html } from 'lit'; -import { classMap } from 'lit/directives/class-map.js'; - -import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; - -import styles from './BaseLabel.css'; - -/** - * Base label class -*/ -export abstract class BaseLabel extends LitElement { - static readonly styles = [styles]; - - abstract variant?: string; - - abstract color?: string; - - abstract icon?: string; - - /** Represents the state of the anonymous and icon slots */ - protected slots = new SlotController(this, null, 'icon'); - - override render() { - const { variant, color, icon } = this; - const hasIcon = !!icon || this.slots.hasSlotted('icon'); - return html` - <span id="container" - class=${classMap({ hasIcon, [variant ?? '']: !!variant, [color ?? '']: !!color })}> - <slot name="icon" part="icon">${this.renderDefaultIcon?.()}</slot> - <slot id="text"></slot> - ${this.renderSuffix?.() ?? ''} - </span> - `; - } - - /** - * Fallback content for the icon slot. When the `icon` attribute is set, it - * should render an icon corresponding to the value. - * - * @example ```html - * <pf-icon icon=${this.icon}></pf-icon> - * ``` - */ - protected abstract renderDefaultIcon?(): unknown; - - /** - * Optional override to render content after the anonymous slot. - * @example ```html - * <button id="close-button">X</button> - * ``` - */ - protected abstract renderSuffix?(): unknown; -} diff --git a/elements/pf-label/pf-label.css b/elements/pf-label/pf-label.css index 8705c80cda..9ceb276661 100644 --- a/elements/pf-label/pf-label.css +++ b/elements/pf-label/pf-label.css @@ -1,10 +1,25 @@ -#pf-container { - display: contents; +:host { + position: relative; + white-space: nowrap; + border: 0; } +pf-icon, ::slotted(pf-icon) { + color: currentColor; +} + +:host, #container { - --pf-global--icon--FontSize--sm: 14px; + display: inline-flex; + align-items: center; + vertical-align: middle; +} +#container { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + border-width: 0; padding-top: var(--pf-c-label--PaddingTop, var(--pf-global--spacer--xs, 0.25rem)); padding-left: var(--pf-c-label--PaddingLeft, var(--pf-global--spacer--sm, 0.5rem)); padding-bottom: var(--pf-c-label--PaddingBottom, var(--pf-global--spacer--xs, 0.25rem)); @@ -15,13 +30,32 @@ border-radius: var(--pf-c-label--BorderRadius, 30em); max-width: var(--pf-c-label__content--MaxWidth, 100%); color: var(--pf-c-label__content--Color, var(--pf-global--Color--100, #151515)); + + --pf-global--icon--FontSize--sm: 14px; } #container::before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + pointer-events: none; + content: ""; border-radius: var(--pf-c-label--BorderRadius, 30em); border: var(--pf-c-label__content--before--BorderWidth, 1px) solid var(--pf-c-label__content--before--BorderColor, var(--pf-global--palette--black-300, #d2d2d2)); } +[part=icon] { + display: none; + pointer-events: none; +} + +.hasIcon [part=icon] { + display: inline-flex; + width: 1em; +} + .compact { --pf-c-label--PaddingTop: var(--pf-c-label--m-compact--PaddingTop, 0); --pf-c-label--PaddingRight: var(--pf-c-label--m-compact--PaddingRight, var(--pf-global--spacer--sm, 0.5rem)); @@ -30,7 +64,6 @@ --pf-global--icon--FontSize--sm: 12px; } - .blue { --pf-c-label__content--Color: var(--pf-c-label--m-blue__content--Color, var(--pf-global--info-color--200, #002952)); --pf-c-label--BackgroundColor: var(--pf-c-label--m-blue--BackgroundColor, var(--pf-global--palette--blue-50, #e7f1fa)); diff --git a/elements/pf-label/pf-label.ts b/elements/pf-label/pf-label.ts index fa5309f3ee..be6627a713 100644 --- a/elements/pf-label/pf-label.ts +++ b/elements/pf-label/pf-label.ts @@ -1,31 +1,19 @@ -import { html } from 'lit'; +import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { classMap } from 'lit/directives/class-map.js'; -import { ComposedEvent } from '@patternfly/pfe-core'; - -import { BaseLabel } from './BaseLabel.js'; +import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; import '@patternfly/elements/pf-button/pf-button.js'; import styles from './pf-label.css'; -export type LabelVariant = ( - | 'filled' - | 'outline' -); - -export type LabelColor = ( - | 'blue' - | 'cyan' - | 'green' - | 'orange' - | 'purple' - | 'red' - | 'grey' - | 'gold' -) +export class LabelCloseEvent extends Event { + constructor() { + super('close', { bubbles: true }); + } +} /** * The **label** component allows users to add specific element captions for user @@ -33,7 +21,7 @@ export type LabelColor = ( * * @summary Allows users to display meta data in a stylized form. * - * @fires close - when a removable label's close button is clicked + * @fires {LabelCloseEvent} close - when a removable label's close button is clicked * * @cssprop {<length>} --pf-c-label--FontSize {@default `0.875em`} * @@ -112,22 +100,22 @@ export type LabelColor = ( * @cssprop {<length>} --pf-c-label--m-compact--PaddingLeft {@default `0.5rem`} */ @customElement('pf-label') -export class PfLabel extends BaseLabel { - static readonly styles = [...BaseLabel.styles, styles]; +export class PfLabel extends LitElement { + static readonly styles = [styles]; - static readonly shadowRootOptions: ShadowRootInit = { ...BaseLabel.shadowRootOptions, delegatesFocus: true }; + static readonly shadowRootOptions: ShadowRootInit = { ...LitElement.shadowRootOptions, delegatesFocus: true }; /** * Changes the style of the label. * - Filled: Colored background with colored border. * - Outline: White background with colored border. */ - @property() variant: LabelVariant = 'filled'; + @property() variant: 'filled' | 'outline' = 'filled'; /** * Changes the color of the label */ - @property() color: LabelColor = 'grey'; + @property() color: 'blue' | 'cyan' | 'green' | 'orange' | 'purple' | 'red' | 'grey' | 'gold' = 'grey'; /** Shorthand for the `icon` slot, the value is icon name */ @property() icon?: string; @@ -144,34 +132,51 @@ export class PfLabel extends BaseLabel { /** Text label for a removable label's close button */ @property({ attribute: 'close-button-label' }) closeButtonLabel?: string; + /** Represents the state of the anonymous and icon slots */ + #slots = new SlotController(this, null, 'icon'); + override render() { const { compact, truncated } = this; + const { variant, color, icon } = this; + const hasIcon = !!icon || this.#slots.hasSlotted('icon'); return html` - <span id="pf-container" class="${classMap({ compact, truncated })}">${super.render()}</span> - `; - } - - protected override renderDefaultIcon() { - return !this.icon ? '' : html` - <pf-icon icon="${this.icon}" size="sm"></pf-icon> + <span id="container" + class="${classMap({ + hasIcon, + compact, + truncated, + [variant ?? '']: !!variant, + [color ?? '']: !!color })}"> + <slot name="icon" part="icon"> + <pf-icon ?hidden="${!icon}" + size="sm" + .icon="${this.icon || undefined as unknown as string}"></pf-icon> + </slot> + <slot id="text"></slot> + <span part="close-button" ?hidden=${!this.removable}> + <pf-button plain + @click="${this.#onClickClose}" + label="${this.closeButtonLabel ?? 'remove'}"> + <svg viewBox="0 0 352 512"> + <path d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"/> + </svg> + </pf-button> + </span> + </span> `; } - protected override renderSuffix() { - return !this.removable ? '' : html` - <span part="close-button" ?hidden=${!this.removable}> - <pf-button plain - @click="${() => this.dispatchEvent(new ComposedEvent('close'))}" - label="${this.closeButtonLabel ?? 'remove'}"> - <svg viewBox="0 0 352 512"> - <path d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"/> - </svg> - </pf-button> - </span> - `; + #onClickClose() { + if (this.removable && this.dispatchEvent(new LabelCloseEvent())) { + this.remove(); + } } } +export type LabelVariant = PfLabel['variant']; + +export type LabelColor = PfLabel['color']; + declare global { interface HTMLElementTagNameMap { 'pf-label': PfLabel; From 16630a73c587997652c9a05a9fdc57acb36c9afe Mon Sep 17 00:00:00 2001 From: Benny Powers <web@bennypowers.com> Date: Thu, 19 Oct 2023 11:44:42 +0300 Subject: [PATCH 2/7] feat(label): self-remove on close --- .changeset/label-close-remove.md | 17 +++++++++++++++++ elements/pf-label/pf-label.ts | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 .changeset/label-close-remove.md diff --git a/.changeset/label-close-remove.md b/.changeset/label-close-remove.md new file mode 100644 index 0000000000..063b1d7797 --- /dev/null +++ b/.changeset/label-close-remove.md @@ -0,0 +1,17 @@ +--- +"@patternfly/elements": major +--- +`<pf-label>`: when clicking close button, `close` event is fired. +Now, if that event is not cancelled, the label will remove itself from the document. + +To restore previous behaviour: + +```js +import { LabelCloseEvent } from '@patternfly/elements/pf-label/pf-label.js'; +label.addEventListener('close', function(event) { + if (event instanceof LabelCloseEvent) { + event.preventDefault(); + return false; + } +}); +``` diff --git a/elements/pf-label/pf-label.ts b/elements/pf-label/pf-label.ts index be6627a713..a16162a17d 100644 --- a/elements/pf-label/pf-label.ts +++ b/elements/pf-label/pf-label.ts @@ -11,7 +11,7 @@ import styles from './pf-label.css'; export class LabelCloseEvent extends Event { constructor() { - super('close', { bubbles: true }); + super('close', { bubbles: true, cancelable: true }); } } From f4b507beb61407eb2ef5d42b15eb4a066ce1b9af Mon Sep 17 00:00:00 2001 From: Benny Powers <web@bennypowers.com> Date: Thu, 19 Oct 2023 11:48:52 +0300 Subject: [PATCH 3/7] test(label): update tests --- elements/pf-label/test/pf-label.spec.ts | 44 +++++++++++++++---------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/elements/pf-label/test/pf-label.spec.ts b/elements/pf-label/test/pf-label.spec.ts index a21006dce7..5705208855 100644 --- a/elements/pf-label/test/pf-label.spec.ts +++ b/elements/pf-label/test/pf-label.spec.ts @@ -22,14 +22,6 @@ const exampleWithOutlineAttribute = html` <pf-label variant="outline">Default Outline</pf-label> `; -const exampleWithIconAttribute = html` - <pf-label icon="rh-icon-virtual-storage-stack">Default Icon</pf-label> -`; - -const exampleWithIconAttributeEmpty = html` - <pf-label icon="">Default</pf-label> -`; - const exampleWithCompactAttribute = html` <pf-label compact>Default Compact</pf-label> `; @@ -102,18 +94,34 @@ describe('<pf-label>', function() { expect(beforeStyles.getPropertyValue('border-color')).to.equal('rgb(210, 210, 210)'); }); - it('should render a pf-icon if the icon attribute is present and valid', async function() { - const el = await createFixture<PfLabel>(exampleWithIconAttribute); - await el.updateComplete; - const icon = el.shadowRoot!.querySelector('pf-icon')!; - expect(icon.icon).to.equal(el.icon); + describe('with valid icon attribute', function() { + let element: PfLabel; + beforeEach(async function() { + element = await createFixture<PfLabel>(html` + <pf-label icon="rh-icon-virtual-storage-stack">Default Icon</pf-label> + `); + element.updateComplete; + }); + it('should render a pf-icon', async function() { + const icon = element.shadowRoot!.querySelector('pf-icon')!; + expect(icon.hidden).to.be.false; + expect(icon.icon).to.equal(element.icon); + }); }); - it('should not render a pf-icon if the icon attribute is present but empty', async function() { - const el = await createFixture<PfLabel>(exampleWithIconAttributeEmpty); - await el.updateComplete; - const icon = el.shadowRoot!.querySelector('pf-icon')!; - expect(icon).to.be.equal(null); + describe('with empty icon attribute', function() { + let element: PfLabel; + beforeEach(async function() { + element = await createFixture<PfLabel>(html` + <pf-label icon="">Default</pf-label> + `); + element.updateComplete; + }); + it('should not render a pf-icon', async function() { + const icon = element.shadowRoot!.querySelector('pf-icon')!; + expect(icon.hidden).to.be.true; + expect(icon.icon).to.be.undefined; + }); }); it('should display compact version if the attribute is-compact is present', async function() { From ee60430e864ba5c5ce542a3d2619e064eda8dd99 Mon Sep 17 00:00:00 2001 From: Steven Spriggs <steven.spriggs@gmail.com> Date: Wed, 1 Nov 2023 10:35:33 -0400 Subject: [PATCH 4/7] fix(label): correct font-size unit, include missing pf global var --- elements/pf-label/pf-label.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elements/pf-label/pf-label.css b/elements/pf-label/pf-label.css index 9ceb276661..40f770bdb5 100644 --- a/elements/pf-label/pf-label.css +++ b/elements/pf-label/pf-label.css @@ -24,7 +24,7 @@ pf-icon, ::slotted(pf-icon) { padding-left: var(--pf-c-label--PaddingLeft, var(--pf-global--spacer--sm, 0.5rem)); padding-bottom: var(--pf-c-label--PaddingBottom, var(--pf-global--spacer--xs, 0.25rem)); padding-right: var(--pf-c-label--PaddingRight, var(--pf-global--spacer--sm, 0.5rem)); - font-size: var(--pf-c-label--FontSize, 0.875em); + font-size: var(--pf-c-label--FontSize, var(--pf-global--FontSize--sm, 0.875rem)); color: var(--pf-c-label--Color, var(--pf-global--Color--100, #151515)); background-color: var(--pf-c-label--BackgroundColor, var(--pf-global--palette--black-150, #f5f5f5)); border-radius: var(--pf-c-label--BorderRadius, 30em); From 3e299002b5d490cfd547c1e9dbb4ce2624cbd2cc Mon Sep 17 00:00:00 2001 From: Steven Spriggs <steven.spriggs@gmail.com> Date: Tue, 14 Nov 2023 12:10:58 -0500 Subject: [PATCH 5/7] docs(label): fix accesibility demo --- elements/pf-label/docs/pf-label.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/elements/pf-label/docs/pf-label.md b/elements/pf-label/docs/pf-label.md index 4466257d6d..34c7ae8423 100644 --- a/elements/pf-label/docs/pf-label.md +++ b/elements/pf-label/docs/pf-label.md @@ -31,6 +31,17 @@ </div> {% htmlexample %} + <style> + .visually-hidden-class { + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; + } + </style> <pf-label color="red"> Red <span class="visually-hidden-class">Warning</span> </pf-label> From 40d5569fabdeb81eac068c49a0480d72e3032b22 Mon Sep 17 00:00:00 2001 From: Steven Spriggs <steven.spriggs@gmail.com> Date: Tue, 14 Nov 2023 12:20:18 -0500 Subject: [PATCH 6/7] fix(label): removes the removal of element and only triggers close event --- elements/pf-label/pf-label.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/elements/pf-label/pf-label.ts b/elements/pf-label/pf-label.ts index a16162a17d..37d5a0d54b 100644 --- a/elements/pf-label/pf-label.ts +++ b/elements/pf-label/pf-label.ts @@ -167,9 +167,10 @@ export class PfLabel extends LitElement { } #onClickClose() { - if (this.removable && this.dispatchEvent(new LabelCloseEvent())) { - this.remove(); + if (this.removable) { + return; } + this.dispatchEvent(new LabelCloseEvent()); } } From 536273bd068d8216755378d91c5f2b62d9bc7461 Mon Sep 17 00:00:00 2001 From: Steven Spriggs <steven.spriggs@gmail.com> Date: Tue, 14 Nov 2023 12:21:34 -0500 Subject: [PATCH 7/7] fix(label): undo last commit, see the example in the changeset --- elements/pf-label/pf-label.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/elements/pf-label/pf-label.ts b/elements/pf-label/pf-label.ts index 37d5a0d54b..a16162a17d 100644 --- a/elements/pf-label/pf-label.ts +++ b/elements/pf-label/pf-label.ts @@ -167,10 +167,9 @@ export class PfLabel extends LitElement { } #onClickClose() { - if (this.removable) { - return; + if (this.removable && this.dispatchEvent(new LabelCloseEvent())) { + this.remove(); } - this.dispatchEvent(new LabelCloseEvent()); } }