diff --git a/.changeset/forty-ties-crash.md b/.changeset/forty-ties-crash.md new file mode 100644 index 0000000000..1e46cebaa8 --- /dev/null +++ b/.changeset/forty-ties-crash.md @@ -0,0 +1,20 @@ +--- +"@patternfly/elements": major +--- + +✨ Added `` replacing ``. Badge now follows +PatternFly v6 design specs. + +```html +7 +``` + +** Breaking Changes from v5 ** + +- Renamed tag from `` to `` +- ✨ Added `disabled` attribute +- ✨ Added v6 design tokens and `color-scheme` support via `light-dark()` +- CSS custom properties renamed from `--pf-v5-c-badge--*` to `--pf-v6-c-badge--*` +- `threshold` comparison changed from < to <= (now shows + when number equals +threshold) +- `number` and `threshold` no longer reflect to attributes diff --git a/elements/pf-v5-badge/README.md b/elements/pf-v5-badge/README.md deleted file mode 100644 index 41650198ac..0000000000 --- a/elements/pf-v5-badge/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# PatternFly Elements Badge - -The `` component provides a way to have small numerical descriptors for -for for for UI elements. To provide context to your badge, it is highly -encouraged that you also include an `aria-label` attribute in your markup. - -Read more about Badge in the [PatternFly Elements Badge documentation](https://patternflyelements.org/components/badge) - -## 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-v5-badge/pf-v5-badge.js'; -``` - -## Usage - -```html -
- 2 -
-``` - -Please refer to the [specification](https://www.w3.org/TR/wai-aria/#aria-label) for additional details. - -With the `threshold` attribute: - -```html -
- 1 - 17 - 900 -
-``` - -With two state options for the `state` attribute: - -```html -
- 10 - 20 -
-``` - diff --git a/elements/pf-v5-badge/demo/index.html b/elements/pf-v5-badge/demo/index.html deleted file mode 100644 index 0976ef0f30..0000000000 --- a/elements/pf-v5-badge/demo/index.html +++ /dev/null @@ -1,12 +0,0 @@ -
- 613 -
- - - diff --git a/elements/pf-v5-badge/demo/read.html b/elements/pf-v5-badge/demo/read.html deleted file mode 100644 index d8f5029bcc..0000000000 --- a/elements/pf-v5-badge/demo/read.html +++ /dev/null @@ -1,15 +0,0 @@ -
- 7 - 24 - 240 - 999 -
- - - diff --git a/elements/pf-v5-badge/demo/threshold.html b/elements/pf-v5-badge/demo/threshold.html deleted file mode 100644 index 2132e3679a..0000000000 --- a/elements/pf-v5-badge/demo/threshold.html +++ /dev/null @@ -1,16 +0,0 @@ -
- 400 - 900 -

In this demo, the threshold is set to 500. - It should add '+' sign if the value exceeds the threshold. - It shouldn't add a '+' sign if the value doesn't exceed the threshold

-
- - - diff --git a/elements/pf-v5-badge/demo/unread.html b/elements/pf-v5-badge/demo/unread.html deleted file mode 100644 index 826b244593..0000000000 --- a/elements/pf-v5-badge/demo/unread.html +++ /dev/null @@ -1,15 +0,0 @@ -
- 7 - 24 - 240 - 999 -
- - - diff --git a/elements/pf-v5-badge/docs/CHANGELOG.old.md b/elements/pf-v5-badge/docs/CHANGELOG.old.md deleted file mode 100644 index e3d18c1936..0000000000 --- a/elements/pf-v5-badge/docs/CHANGELOG.old.md +++ /dev/null @@ -1,62 +0,0 @@ -# @patternfly/pfe-badge - -## 2.0.0-next.4 - -### Patch Changes - -- 5bc0a5ad: Made `state` property on `BaseBadge` abstract. - -## 2.0.0-next.3 - -### Major Changes - -- 686c01e2: Rewrote `` to more closely implement the PatternFly v4 spec. This includes component API changes, but HTML implementation remains the same. - - ```html - 7 - ``` - - ```html - 7 - ``` - - #### Updates - - - Options for the `state` attribute have changed to `read` and `unread`. - - `pfe` Sass variables were replaced by `--pf-*` css variables. - -## 2.0.0-next.2 - -### Patch Changes - -- bfad8b4b: Updates dependencies -- Updated dependencies [bfad8b4b] - - @patternfly/pfe-core@2.0.0-next.8 - -## 2.0.0-next.1 - -### Patch Changes - -- 447b2d75: Remove `esbuild` export condition, as this anyways was a runtime error -- Updated dependencies [447b2d75] - - @patternfly/pfe-core@2.0.0-next.3 - -## 2.0.0-next.0 - -### Major Changes - -- e4a76fb2: ## 🔥 Migrate to Lit - - This release migrates `` to LitElement. - - ### Breaking Changes - - - Initial render is now [asynchronous](https://lit.dev/docs/components/lifecycle/#reactive-update-cycle). - If your code assumes that shadow DOM is ready once the element is constructed, update it to `await element.updateComplete`; - - See [docs](https://patternflyelements.org/components/badge/) for more info - -### Patch Changes - -- Updated dependencies [e8788c72] - - @patternfly/pfe-core@2.0.0-next.0 diff --git a/elements/pf-v5-badge/docs/pf-v5-badge.md b/elements/pf-v5-badge/docs/pf-v5-badge.md deleted file mode 100644 index 02d5080fdc..0000000000 --- a/elements/pf-v5-badge/docs/pf-v5-badge.md +++ /dev/null @@ -1,43 +0,0 @@ -{% renderInstallation %} {% endrenderInstallation %} - -{% renderOverview %} - 17 - 900 - 10 -{% endrenderOverview %} - -{% band header="Usage" %} - To provide context to your badge, it is highly encouraged that you also include an `aria-label` attribute in your markup. - - ### Default - {% htmlexample %} - 2 - {% endhtmlexample %} - - ### With a threshold - This adds a "+" next to the number once the threshold value has been passed. - - {% htmlexample %} - 20 - {% endhtmlexample %} - - ### With a state - This adds a background color to the badge based on the state. - - {% htmlexample %} - 10 - 20 - {% endhtmlexample %} -{% endband %} - -{% renderSlots %}{% endrenderSlots %} - -{% renderAttributes %}{% endrenderAttributes %} - -{% renderMethods %}{% endrenderMethods %} - -{% renderEvents %}{% endrenderEvents %} - -{% renderCssCustomProperties %}{% endrenderCssCustomProperties %} - -{% renderCssParts %}{% endrenderCssParts %} diff --git a/elements/pf-v5-badge/docs/screenshot.png b/elements/pf-v5-badge/docs/screenshot.png deleted file mode 100644 index 0d28220ba3..0000000000 Binary files a/elements/pf-v5-badge/docs/screenshot.png and /dev/null differ diff --git a/elements/pf-v5-badge/pf-v5-badge.css b/elements/pf-v5-badge/pf-v5-badge.css deleted file mode 100644 index 732ed346ca..0000000000 --- a/elements/pf-v5-badge/pf-v5-badge.css +++ /dev/null @@ -1,51 +0,0 @@ -:host { - position: relative; - white-space: nowrap; - text-align: center; - display: inline-block; - /** Border radius for badge */ - border-radius: var(--pf-v5-c-badge--BorderRadius, - var(--pf-global--BorderRadius--lg, 180em)); - /** Minimum width for badge */ - min-width: var(--pf-v5-c-badge--MinWidth, - var(--pf-global--spacer--xl, 2rem)); - /** Left padding for badge */ - padding-left: var(--pf-v5-c-badge--PaddingLeft, - var(--pf-global--spacer--sm, 0.5rem)); - /** Right padding for badge */ - padding-right: var(--pf-v5-c-badge--PaddingRight, - var(--pf-global--spacer--sm, 0.5rem)); - /** Font size for badge */ - font-size: var(--pf-v5-c-badge--FontSize, - var(--pf-v5-theme--font-size, 0.75em)); - /** Font weight for badge */ - font-weight: var(--pf-v5-c-badge--FontWeight, - var(--pf-v5-theme--font-weight--bold, 700)); - /** Line height for badge */ - line-height: var(--pf-v5-c-badge--LineHeight, - var(--pf-global--LineHeight--md, 1.5)); - /** Color for badge */ - color: var(--pf-v5-c-badge--Color, - var(--pf-global--palette--black-900, #151515)); - /** Background color for badge */ - background-color: var(--pf-v5-c-badge--BackgroundColor, - var(--pf-global--palette--black-200, #f0f0f0)); -} - -:host([state="read"]) { - /** Color for read badge */ - --pf-v5-c-badge--Color: var(--pf-v5-c-badge--m-read--Color, - var(--pf-global--palette--black-900, #151515)); - /** Background color for read badge */ - --pf-v5-c-badge--BackgroundColor: var(--pf-v5-c-badge--m-read--BackgroundColor, - var(--pf-global--palette--black-200, #f0f0f0)); -} - -:host([state="unread"]) { - /** Color for unread badge */ - --pf-v5-c-badge--Color: var(--pf-v5-c-badge--m-unread--Color, - var(--pf-global--palette--white, #fff)); - /** Background color for unread badge */ - --pf-v5-c-badge--BackgroundColor: var(--pf-v5-c-badge--m-unread--BackgroundColor, - var(--pf-global--palette--blue-400, #06c)); -} diff --git a/elements/pf-v5-badge/pf-v5-badge.ts b/elements/pf-v5-badge/pf-v5-badge.ts deleted file mode 100644 index b2fd42a183..0000000000 --- a/elements/pf-v5-badge/pf-v5-badge.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { LitElement, html, type TemplateResult } from 'lit'; -import { customElement } from 'lit/decorators/custom-element.js'; -import { property } from 'lit/decorators/property.js'; - -import styles from './pf-v5-badge.css'; - -/** - * A **badge** is used to annotate other information like a label or an object name. - * @alias Badge - */ - - -@customElement('pf-v5-badge') -export class PfV5Badge extends LitElement { - static readonly styles: CSSStyleSheet[] = [styles]; - - /** - * Denotes the state-of-affairs this badge represents - * Options include read and unread - */ - @property({ reflect: true }) state?: 'unread' | 'read'; - - /** - * Sets a numeric value for a badge. - * - * You can pair it with `threshold` attribute to add a `+` sign - * if the number exceeds the threshold value. - */ - @property({ reflect: true, type: Number }) number?: number; - - /** - * Sets a threshold for the numeric value and adds `+` sign if - * the numeric value exceeds the threshold value. - */ - @property({ reflect: true, type: Number }) threshold?: number; - - override render(): TemplateResult<1> { - const { threshold, number, textContent } = this; - const displayText = - (threshold && number && (threshold < number)) ? `${threshold.toString()}+` - : (number != null) ? number.toString() - : textContent ?? ''; - return html` - ${displayText} - `; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'pf-v5-badge': PfV5Badge; - } -} diff --git a/elements/pf-v5-badge/test/pf-badge.e2e.ts b/elements/pf-v5-badge/test/pf-badge.e2e.ts deleted file mode 100644 index cbf4e4d311..0000000000 --- a/elements/pf-v5-badge/test/pf-badge.e2e.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { test } from '@playwright/test'; -import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; -import { SSRPage } from '@patternfly/pfe-tools/test/playwright/SSRPage.js'; - -const tagName = 'pf-v5-badge'; - -test.describe(tagName, () => { - test('snapshot', async ({ page }) => { - const componentPage = new PfeDemoPage(page, tagName); - await componentPage.navigate(); - await componentPage.snapshot(); - }); - - test('ssr', async ({ browser }) => { - const fixture = new SSRPage({ - tagName, - browser, - demoDir: new URL('../demo/', import.meta.url), - importSpecifiers: [ - `@patternfly/elements/${tagName}/${tagName}.js`, - ], - }); - await fixture.snapshots(); - }); -}); diff --git a/elements/pf-v5-badge/test/pf-badge.spec.ts b/elements/pf-v5-badge/test/pf-badge.spec.ts deleted file mode 100644 index 5eb0726cb2..0000000000 --- a/elements/pf-v5-badge/test/pf-badge.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { expect, html, nextFrame } from '@open-wc/testing'; -import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; -import { hexToRgb, getColor } from '@patternfly/pfe-tools/test/hex-to-rgb.js'; -import { PfV5Badge } from '@patternfly/elements/pf-v5-badge/pf-v5-badge.js'; - -// Background colors for the various states -const states = { - default: '#f0f0f0', - read: '#f0f0f0', - unread: '#0066cc', -}; - -const element = html`10`; - -describe('', function() { - it('imperatively instantiates', function() { - expect(document.createElement('pf-v5-badge')).to.be.an.instanceof(PfV5Badge); - }); - - it('should upgrade', async function() { - const el = await createFixture(element); - expect(el, 'pf-v5-badge should be an instance of PfV5Badge') - .to.be.an - .instanceOf(customElements.get('pf-v5-badge')) - .and - .to.be.an.instanceof(PfV5Badge); - }); - - it('should display text equivalent to the number attribute', async function() { - const el = await createFixture(html`10`); - await nextFrame(); - expect(el.shadowRoot!.querySelector('span')!.textContent).to.equal('100'); - }); - - it('should add \'+\' sign if the value exceeds the threshold', async function() { - const el = await createFixture(html`900`); - await nextFrame(); - expect(el.shadowRoot!.querySelector('span')!.textContent).to.equal('100+'); - }); - - it('shouldn\'t add a \'+\' sign if the value doesn\'t exceed the threshold', async function() { - const el = await createFixture(html`900`); - await el.updateComplete; - expect(el.textContent).to.equal('900'); - expect(el.shadowRoot!.querySelector('span')!.textContent).to.equal('900'); - }); - - // This is the one that created an error: - Object.entries(states).forEach(([state, color]) => { - it(`should have a background color of '${color}' when state is ${state}`, async function() { - const el = await createFixture(element); - - if (state !== 'default') { - el.setAttribute('state', state); - } - - const [r, g, b] = getColor(el, 'background-color'); - expect([r, g, b]).to.deep.equal(hexToRgb(color)); - }); - }); -}); diff --git a/elements/pf-v5-select/pf-v5-select.ts b/elements/pf-v5-select/pf-v5-select.ts index eda637b4c6..b7fafc5559 100644 --- a/elements/pf-v5-select/pf-v5-select.ts +++ b/elements/pf-v5-select/pf-v5-select.ts @@ -216,7 +216,7 @@ export class PfV5Select extends LitElement { ${this.#buttonLabel}${!hasBadge ? '' : html` - ${selectedOptions.length} + ${selectedOptions.length} `}
+``` + +### Read badge with threshold + +```html + +``` + +### Badge with slotted content + +```html +New +``` + +## Divergences from React `Badge` + +### Not implemented + +| React prop | Notes | +| --- | --- | +| `screenReaderText` | No built-in screen reader text span. Authors should provide their own visually-hidden text adjacent to the badge. | + +### Changed API + +| React prop | Web component | Difference | +| --- | --- | --- | +| `isRead` | `state` attribute | Boolean replaced with `'read' \| 'unread'` enum. Omitting `state` gives neutral styling (no read/unread indication). | + +### Added + +| Web component API | Notes | +| --- | --- | +| `number` property | Numeric value displayed in the badge. | +| `threshold` property | When `number` exceeds this value, displays `{threshold}+` instead. | +| `--pf-v6-c-badge--MinWidth` | Minimum width of the badge. | +| `--pf-v6-c-badge--PaddingInlineStart` | Inline start padding. | +| `--pf-v6-c-badge--PaddingInlineEnd` | Inline end padding. | +| `--pf-v6-c-badge--FontSize` | Font size of the badge text. | +| `--pf-v6-c-badge--FontWeight` | Font weight of the badge text. | +| `--pf-v6-c-badge--Color` | Text color of the badge. | +| `--pf-v6-c-badge--BackgroundColor` | Background color of the badge. | +| `--pf-v6-c-badge--BorderRadius` | Border radius of the badge. | +| `--pf-v6-c-badge--BorderWidth` | Border width of the badge. | +| `--pf-v6-c-badge--BorderColor` | Border color of the badge. | diff --git a/elements/pf-v6-badge/demo/disabled.html b/elements/pf-v6-badge/demo/disabled.html new file mode 100644 index 0000000000..3e57ccf9e2 --- /dev/null +++ b/elements/pf-v6-badge/demo/disabled.html @@ -0,0 +1,12 @@ +--- +name: Disabled +description: Disabled badges indicate that the associated content or action is currently unavailable. +--- +7 +24 +240 +999+ + + diff --git a/elements/pf-v6-badge/demo/index.html b/elements/pf-v6-badge/demo/index.html new file mode 100644 index 0000000000..418d93581a --- /dev/null +++ b/elements/pf-v6-badge/demo/index.html @@ -0,0 +1,9 @@ +--- +name: Basic +description: A basic badge displays a numeric value. +--- +7 + + diff --git a/elements/pf-v6-badge/demo/read.html b/elements/pf-v6-badge/demo/read.html new file mode 100644 index 0000000000..b0239ac479 --- /dev/null +++ b/elements/pf-v6-badge/demo/read.html @@ -0,0 +1,12 @@ +--- +name: Read +description: Read badges display a numeric value with read state styling, indicating the content has been viewed. +--- +7 +24 +240 +999+ + + diff --git a/elements/pf-v6-badge/demo/threshold.html b/elements/pf-v6-badge/demo/threshold.html new file mode 100644 index 0000000000..b27ea00fca --- /dev/null +++ b/elements/pf-v6-badge/demo/threshold.html @@ -0,0 +1,10 @@ +--- +name: Threshold +description: A threshold appends a "+" when the numeric value exceeds a set maximum. +--- +400 +900 + + diff --git a/elements/pf-v6-badge/demo/unread.html b/elements/pf-v6-badge/demo/unread.html new file mode 100644 index 0000000000..7e16b908e2 --- /dev/null +++ b/elements/pf-v6-badge/demo/unread.html @@ -0,0 +1,12 @@ +--- +name: Unread +description: Unread badges use a bold, branded style to indicate content that has not yet been viewed. +--- +7 +24 +240 +999+ + + diff --git a/elements/pf-v6-badge/pf-v6-badge.css b/elements/pf-v6-badge/pf-v6-badge.css new file mode 100644 index 0000000000..5acc5dad8b --- /dev/null +++ b/elements/pf-v6-badge/pf-v6-badge.css @@ -0,0 +1,95 @@ +:host { + position: relative; + display: inline-block; + min-width: + /** Minimum width of the badge */ + var(--pf-v6-c-badge--MinWidth, + var(--pf-t--global--spacer--xl, 2rem)); + padding-inline-start: + /** Inline start padding */ + var(--pf-v6-c-badge--PaddingInlineStart, + var(--pf-t--global--spacer--sm, 0.5rem)); + padding-inline-end: + /** Inline end padding */ + var(--pf-v6-c-badge--PaddingInlineEnd, + var(--pf-t--global--spacer--sm, 0.5rem)); + font-size: + /** Font size of the badge text */ + var(--pf-v6-c-badge--FontSize, + var(--pf-t--global--font--size--body--sm, 0.75rem)); + font-weight: + /** Font weight of the badge text */ + var(--pf-v6-c-badge--FontWeight, + var(--pf-t--global--font--weight--body--bold, 700)); + color: + /** Text color of the badge */ + var(--pf-v6-c-badge--Color, + var(--pf-t--global--text--color--nonstatus--on-gray--default, #151515)); + text-align: center; + white-space: nowrap; + background-color: + /** Background color of the badge */ + var(--pf-v6-c-badge--BackgroundColor, + var(--pf-t--global--color--nonstatus--gray--default, #f0f0f0)); + border-radius: + /** Border radius of the badge */ + var(--pf-v6-c-badge--BorderRadius, + var(--pf-t--global--border--radius--pill, 180em)); +} + +:host::after { + position: absolute; + inset: 0; + pointer-events: none; + content: ""; + border: + /** Border width of the badge */ + var(--pf-v6-c-badge--BorderWidth, + var(--pf-t--global--border--width--regular, 1px)) + solid + /** Border color of the badge */ + var(--pf-v6-c-badge--BorderColor, transparent); + border-radius: inherit; +} + +:host([state="read"]) { + --pf-v6-c-badge--Color: + /** Text color in read state */ + var(--pf-v6-c-badge--m-read--Color, + var(--pf-t--global--text--color--nonstatus--on-gray--default, #151515)); + --pf-v6-c-badge--BackgroundColor: + /** Background color in read state */ + var(--pf-v6-c-badge--m-read--BackgroundColor, + var(--pf-t--global--color--nonstatus--gray--default, #f0f0f0)); + --pf-v6-c-badge--BorderColor: + /** Border color in read state */ + var(--pf-v6-c-badge--m-read--BorderColor, + var(--pf-t--global--border--color--high-contrast, #151515)); +} + +:host([state="unread"]) { + --pf-v6-c-badge--Color: + /** Text color in unread state */ + var(--pf-v6-c-badge--m-unread--Color, + var(--pf-t--global--text--color--on-brand--default, #fff)); + --pf-v6-c-badge--BackgroundColor: + /** Background color in unread state */ + var(--pf-v6-c-badge--m-unread--BackgroundColor, + var(--pf-t--global--color--brand--default, #06c)); +} + +:host([disabled]) { + --pf-v6-c-badge--Color: + /** Text color when disabled */ + var(--pf-v6-c-badge--m-disabled--Color, + var(--pf-t--global--text--color--on-disabled, #6a6e73)); + --pf-v6-c-badge--BackgroundColor: + /** Background color when disabled */ + var(--pf-v6-c-badge--m-disabled--BackgroundColor, + var(--pf-t--global--background--color--disabled--default, #d2d2d2)); + --pf-v6-c-badge--BorderColor: + /** Border color when disabled */ + var(--pf-v6-c-badge--m-disabled--BorderColor, + var(--pf-t--global--border--color--disabled, #d2d2d2)); + pointer-events: none; +} diff --git a/elements/pf-v6-badge/pf-v6-badge.ts b/elements/pf-v6-badge/pf-v6-badge.ts new file mode 100644 index 0000000000..34742a9d2c --- /dev/null +++ b/elements/pf-v6-badge/pf-v6-badge.ts @@ -0,0 +1,53 @@ +import { LitElement, html, type TemplateResult } from 'lit'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { property } from 'lit/decorators/property.js'; + +import styles from './pf-v6-badge.css'; + +export type BadgeState = 'unread' | 'read'; + +/** + * A **badge** is used to annotate other information like a label or an object name. + * @summary Displays a numeric value as an annotation + */ +@customElement('pf-v6-badge') +export class PfV6Badge extends LitElement { + static readonly styles: CSSStyleSheet[] = [styles]; + + /** + * Denotes the state-of-affairs this badge represents. + */ + @property({ reflect: true }) state?: BadgeState; + + /** + * Sets a numeric value for a badge. + * + * You can pair it with `threshold` attribute to add a `+` sign + * if the number exceeds the threshold value. + */ + @property({ type: Number }) number?: number; + + /** + * Sets a threshold for the numeric value and adds `+` sign if + * the numeric value exceeds the threshold value. + */ + @property({ type: Number }) threshold?: number; + + /** Disables the badge */ + @property({ type: Boolean, reflect: true }) disabled = false; + + override render(): TemplateResult { + const { threshold, number } = this; + const displayText = + (threshold && number && (threshold <= number)) ? `${threshold.toString()}+` + : (number != null) ? number.toString() + : ''; + return html`${!displayText ? html`` : displayText}`; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'pf-v6-badge': PfV6Badge; + } +} diff --git a/elements/pf-v6-badge/test/pf-v6-badge.spec.ts b/elements/pf-v6-badge/test/pf-v6-badge.spec.ts new file mode 100644 index 0000000000..ad2dee0e5b --- /dev/null +++ b/elements/pf-v6-badge/test/pf-v6-badge.spec.ts @@ -0,0 +1,181 @@ +import { expect, html } from '@open-wc/testing'; +import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; +import { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; +import { getColor, hexToRgb } from '@patternfly/pfe-tools/test/hex-to-rgb.js'; +import { PfV6Badge } from '@patternfly/elements/pf-v6-badge/pf-v6-badge.js'; + +describe('', function() { + it('imperatively instantiates', function() { + expect(document.createElement('pf-v6-badge')).to.be.an.instanceof(PfV6Badge); + }); + + it('should upgrade', async function() { + const el = await createFixture(html`10`); + expect(el) + .to.be.an.instanceOf(customElements.get('pf-v6-badge')) + .and + .to.be.an.instanceOf(PfV6Badge); + }); + + describe('with number attribute', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 100 + `); + await element.updateComplete; + }); + + it('should have the number property set', function() { + expect(element.number).to.equal(100); + }); + + it('should be visible in the accessibility tree', async function() { + const snapshot = await a11ySnapshot(); + expect(snapshot.children?.length).to.be.greaterThan(0); + const badgeNode = snapshot.children?.find( + (child: { name?: string }) => child.name?.includes('100') + ); + expect(badgeNode).to.exist; + }); + }); + + describe('with number exceeding threshold', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 900 + `); + await element.updateComplete; + }); + + it('should display threshold with "+" in the accessibility tree', async function() { + const snapshot = await a11ySnapshot(); + const badgeNode = snapshot.children?.find( + (child: { name?: string }) => child.name?.includes('100+') + ); + expect(badgeNode).to.exist; + }); + }); + + describe('with number below threshold', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 50 + `); + await element.updateComplete; + }); + + it('should display the number without "+" in the accessibility tree', async function() { + const snapshot = await a11ySnapshot(); + const badgeNode = snapshot.children?.find( + (child: { name?: string }) => + child.name?.includes('50') && !child.name?.includes('+') + ); + expect(badgeNode).to.exist; + }); + }); + + describe('without state attribute', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 10 + `); + await element.updateComplete; + }); + + it('should display default background color', function() { + const [r, g, b] = getColor(element, 'background-color'); + expect([r, g, b]).to.deep.equal(hexToRgb('#f0f0f0')); + }); + }); + + describe('with state="read"', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 10 + `); + await element.updateComplete; + }); + + it('should display read background color', function() { + const [r, g, b] = getColor(element, 'background-color'); + expect([r, g, b]).to.deep.equal(hexToRgb('#f0f0f0')); + }); + }); + + describe('with state="unread"', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 10 + `); + await element.updateComplete; + }); + + it('should display unread background color', function() { + const [r, g, b] = getColor(element, 'background-color'); + expect([r, g, b]).to.deep.equal(hexToRgb('#0066cc')); + }); + + it('should display unread text color', function() { + const [r, g, b] = getColor(element, 'color'); + expect([r, g, b]).to.deep.equal(hexToRgb('#ffffff')); + }); + }); + + describe('with disabled attribute', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + 10 + `); + await element.updateComplete; + }); + + it('should display disabled background color', function() { + const [r, g, b] = getColor(element, 'background-color'); + expect([r, g, b]).to.deep.equal(hexToRgb('#d2d2d2')); + }); + + it('should have pointer-events: none', function() { + const styles = getComputedStyle(element); + expect(styles.pointerEvents).to.equal('none'); + }); + }); + + describe('accessibility', function() { + it('should contain text in the accessibility tree', async function() { + await createFixture(html` + 10 + `); + const snapshot = await a11ySnapshot(); + expect(snapshot.children?.length).to.be.greaterThan(0); + }); + }); + + describe('slot content', function() { + let element: PfV6Badge; + + beforeEach(async function() { + element = await createFixture(html` + Custom Text + `); + await element.updateComplete; + }); + + it('should display slotted text content when no number is set', function() { + expect(element.textContent?.trim()).to.equal('Custom Text'); + }); + }); +});