From 942045c23044b72f6892fe4b17d32ade147311d2 Mon Sep 17 00:00:00 2001 From: ArathyKumar Date: Tue, 4 Aug 2026 22:07:29 +0530 Subject: [PATCH 01/31] chore(button): created pf-v6-button component --- elements/pf-v6-button/README.md | 75 ++ elements/pf-v6-button/demo/block.html | 18 + .../pf-v6-button/demo/call-to-action.html | 38 + .../pf-v6-button/demo/disabled-focusable.html | 29 + elements/pf-v6-button/demo/disabled.html | 63 + elements/pf-v6-button/demo/favorite.html | 40 + elements/pf-v6-button/demo/hamburger.html | 25 + elements/pf-v6-button/demo/index.html | 9 + .../pf-v6-button/demo/inline-span-link.html | 14 + elements/pf-v6-button/demo/links.html | 55 + .../pf-v6-button/demo/plain-no-padding.html | 26 + elements/pf-v6-button/demo/progress.html | 49 + elements/pf-v6-button/demo/settings.html | 30 + elements/pf-v6-button/demo/small.html | 28 + elements/pf-v6-button/demo/stateful.html | 65 ++ elements/pf-v6-button/demo/types.html | 38 + .../pf-v6-button/demo/variant-examples.html | 142 +++ elements/pf-v6-button/demo/with-count.html | 33 + elements/pf-v6-button/docs/pf-v6-button.md | 44 + elements/pf-v6-button/docs/screenshot.png | Bin 0 -> 29209 bytes elements/pf-v6-button/pf-v6-button.css | 1038 +++++++++++++++++ elements/pf-v6-button/pf-v6-button.ts | 520 +++++++++ .../pf-v6-button/test/pf-v6-button.spec.ts | 308 +++++ 23 files changed, 2687 insertions(+) create mode 100644 elements/pf-v6-button/README.md create mode 100644 elements/pf-v6-button/demo/block.html create mode 100644 elements/pf-v6-button/demo/call-to-action.html create mode 100644 elements/pf-v6-button/demo/disabled-focusable.html create mode 100644 elements/pf-v6-button/demo/disabled.html create mode 100644 elements/pf-v6-button/demo/favorite.html create mode 100644 elements/pf-v6-button/demo/hamburger.html create mode 100644 elements/pf-v6-button/demo/index.html create mode 100644 elements/pf-v6-button/demo/inline-span-link.html create mode 100644 elements/pf-v6-button/demo/links.html create mode 100644 elements/pf-v6-button/demo/plain-no-padding.html create mode 100644 elements/pf-v6-button/demo/progress.html create mode 100644 elements/pf-v6-button/demo/settings.html create mode 100644 elements/pf-v6-button/demo/small.html create mode 100644 elements/pf-v6-button/demo/stateful.html create mode 100644 elements/pf-v6-button/demo/types.html create mode 100644 elements/pf-v6-button/demo/variant-examples.html create mode 100644 elements/pf-v6-button/demo/with-count.html create mode 100644 elements/pf-v6-button/docs/pf-v6-button.md create mode 100644 elements/pf-v6-button/docs/screenshot.png create mode 100644 elements/pf-v6-button/pf-v6-button.css create mode 100644 elements/pf-v6-button/pf-v6-button.ts create mode 100644 elements/pf-v6-button/test/pf-v6-button.spec.ts diff --git a/elements/pf-v6-button/README.md b/elements/pf-v6-button/README.md new file mode 100644 index 0000000000..a643b0bb81 --- /dev/null +++ b/elements/pf-v6-button/README.md @@ -0,0 +1,75 @@ +# Button + +A button communicates and triggers user actions when clicked or selected. + +## Usage + +### Basic button + +```html +Primary +Secondary +``` + +### Icon button + +```html + + + +``` + +### Form submit + +```html +
+ Save + Reset +
+``` + +## Divergences from React `Button` + +### Not implemented + +| React prop | Notes | +| ------------------------------------------ | --------------------------------------------------------------------------------------------------------- | +| `component` | Web components cannot change their host tag. Use `href` for anchors, or wrap the button in semantic HTML. | +| `className` | Not needed with shadow DOM. | +| `ouiaId` / `ouiaSafe` | OUIA helpers are React-specific. | +| `inoperableEvents` | Aria-disabled blocks `click` activation; custom event lists are not exposed. | +| `spinnerAriaLabelledBy` | Use `loading-label` or the spinner's `accessible-label`. | +| `isCircle` / `isDocked` / `isTextExpanded` | Beta React APIs; omitted until design stabilizes. | +| `innerRef` | Use a normal element reference to the host. | + +### Changed API + +| React prop | Web component | Difference | +| ------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------ | +| `isDisabled` | `disabled` | Dropped `is-` prefix. | +| `isAriaDisabled` | `disabled-focusable` | Keeps the button focusable while blocking activation; sets `aria-disabled` via ElementInternals. | +| `isLoading` | `loading` | Dropped `is-` prefix. | +| `isBlock` | `block` | Dropped `is-` prefix. | +| `isInline` | `inline` | Dropped `is-` prefix. | +| `isDanger` | `danger` | Dropped `is-` prefix. Applies to `secondary` and `link` variants. | +| `isClicked` | `clicked` | Dropped `is-` prefix. | +| `isFavorite` / `isFavorited` | `favorite` / `favorited` | Dropped `is-` prefix. | +| `isSettings` | `settings` | Dropped `is-` prefix. | +| `isHamburger` / `isExpanded` | `hamburger` / `expanded` | Dropped `is-` prefix. | +| `hasNoPadding` | `no-padding` | Dash-case boolean attribute. | +| `aria-label` | `accessible-label` | Custom attribute; applied via ElementInternals. | +| `icon` | `slot="icon"` or `icon` / `icon-set` | Prefer slotted icons. Optional shorthand renders ``. | +| `countOptions` | `slot="count"` | Slot a `` instead of a options object. | +| `spinnerAriaLabel` / `spinnerAriaValueText` | `loading-label` | Reactive attribute/property for the spinner accessible name. | +| `size="default"` | omit `size` | Default size is the absence of the attribute. | +| `component="a"` + `href` | `href` / `target` | Renders an inner anchor when `variant="link"` and `href` are set. | + +### Added + +| Web component API | Notes | +| --------------------------------------------- | -------------------------------------------------------------------------------------- | +| Form association (`formAssociated`) | Host participates in forms like a native button; supports `type`, `name`, and `value`. | +| `href` / `target` | Progressive-enhancement link rendering for `variant="link"`. | +| `slot="icon"` / `slot="count"` | Composition slots for icons and count badges. | +| `icon` / `icon-set` | Optional shorthand that renders `` in the icon slot. | +| CSS parts `icon`, `text`, `count`, `progress` | Limited styling hooks for shadow internals. | diff --git a/elements/pf-v6-button/demo/block.html b/elements/pf-v6-button/demo/block.html new file mode 100644 index 0000000000..939fa2b1e3 --- /dev/null +++ b/elements/pf-v6-button/demo/block.html @@ -0,0 +1,18 @@ +--- +name: Block level buttons +description: Block level buttons span the full width of their parent when the block attribute is set. +--- + +
+ Block level button +
+ + + + diff --git a/elements/pf-v6-button/demo/call-to-action.html b/elements/pf-v6-button/demo/call-to-action.html new file mode 100644 index 0000000000..f0403b910e --- /dev/null +++ b/elements/pf-v6-button/demo/call-to-action.html @@ -0,0 +1,38 @@ +--- +name: Call to action +description: Primary, secondary, tertiary, and link buttons can use size="lg" for call-to-action styling. +--- + +
+ Call to action + Call to action + Call to action + + Call to action + + +
+ + + + diff --git a/elements/pf-v6-button/demo/disabled-focusable.html b/elements/pf-v6-button/demo/disabled-focusable.html new file mode 100644 index 0000000000..bfbbf7f641 --- /dev/null +++ b/elements/pf-v6-button/demo/disabled-focusable.html @@ -0,0 +1,29 @@ +--- +name: Aria-disabled examples +description: Disabled-focusable buttons stay focusable while blocking activation. Use them when a disabled control still needs a tooltip or other focus treatment. +--- + +
+ Primary + Secondary + Link + Link as anchor +
+ + + + diff --git a/elements/pf-v6-button/demo/disabled.html b/elements/pf-v6-button/demo/disabled.html new file mode 100644 index 0000000000..2a99f559c7 --- /dev/null +++ b/elements/pf-v6-button/demo/disabled.html @@ -0,0 +1,63 @@ +--- +name: Disabled buttons +description: Disable any button variant with the disabled attribute when the action is unavailable. +--- + +
+ Primary + Secondary + Danger secondary + Tertiary + Danger + Warning +
+ +
+ + + Link + + Inline link + + + + Control +
+ + + + diff --git a/elements/pf-v6-button/demo/favorite.html b/elements/pf-v6-button/demo/favorite.html new file mode 100644 index 0000000000..de3041b1b5 --- /dev/null +++ b/elements/pf-v6-button/demo/favorite.html @@ -0,0 +1,40 @@ +--- +name: Favorite +description: Favorite buttons use the favorite attribute with variant="plain". Toggle favorited to update the filled star state. +--- + +
+ + +
+ + + + diff --git a/elements/pf-v6-button/demo/hamburger.html b/elements/pf-v6-button/demo/hamburger.html new file mode 100644 index 0000000000..99469aea9c --- /dev/null +++ b/elements/pf-v6-button/demo/hamburger.html @@ -0,0 +1,25 @@ +--- +name: Hamburger +description: Hamburger buttons use the hamburger attribute. Set expanded and hamburger-variant to animate between expand and collapse. +--- + +
+ +
+ + diff --git a/elements/pf-v6-button/demo/index.html b/elements/pf-v6-button/demo/index.html new file mode 100644 index 0000000000..e73d3877f4 --- /dev/null +++ b/elements/pf-v6-button/demo/index.html @@ -0,0 +1,9 @@ +--- +name: Basic +description: A button triggers an action when activated. +--- +Primary + + diff --git a/elements/pf-v6-button/demo/inline-span-link.html b/elements/pf-v6-button/demo/inline-span-link.html new file mode 100644 index 0000000000..9b886eb6a6 --- /dev/null +++ b/elements/pf-v6-button/demo/inline-span-link.html @@ -0,0 +1,14 @@ +--- +name: Inline link +description: Inline links use variant="link" with the inline attribute so they wrap with surrounding text. +--- + +

+ This is a + inline link button + in a sentence of text. +

+ + diff --git a/elements/pf-v6-button/demo/links.html b/elements/pf-v6-button/demo/links.html new file mode 100644 index 0000000000..81ef63f3ed --- /dev/null +++ b/elements/pf-v6-button/demo/links.html @@ -0,0 +1,55 @@ +--- +name: Links as buttons +description: Buttons that navigate elsewhere can use href with primary, secondary, tertiary, or link variants. +--- + +
+ Primary link + Secondary link + Tertiary link + + Link to PatternFly + + +
+ + + + diff --git a/elements/pf-v6-button/demo/plain-no-padding.html b/elements/pf-v6-button/demo/plain-no-padding.html new file mode 100644 index 0000000000..34ce30fefb --- /dev/null +++ b/elements/pf-v6-button/demo/plain-no-padding.html @@ -0,0 +1,26 @@ +--- +name: Plain with no padding +description: Use no-padding with variant="plain" to place an icon button inline with text. +--- + +

+ Edit this value + + + +

+ + diff --git a/elements/pf-v6-button/demo/progress.html b/elements/pf-v6-button/demo/progress.html new file mode 100644 index 0000000000..7866a9a922 --- /dev/null +++ b/elements/pf-v6-button/demo/progress.html @@ -0,0 +1,49 @@ +--- +name: Progress indicators +description: Set loading to show a progress spinner after the user starts an action. +--- + +
+ Click to start loading + Click to start loading + + + +
+ + + + diff --git a/elements/pf-v6-button/demo/settings.html b/elements/pf-v6-button/demo/settings.html new file mode 100644 index 0000000000..ff0ed9c548 --- /dev/null +++ b/elements/pf-v6-button/demo/settings.html @@ -0,0 +1,30 @@ +--- +name: Settings +description: Settings buttons use the settings attribute on plain or control variants and animate the gear icon on hover and focus. +--- + +
+ + +
+ + + + diff --git a/elements/pf-v6-button/demo/small.html b/elements/pf-v6-button/demo/small.html new file mode 100644 index 0000000000..5ab9f8d17a --- /dev/null +++ b/elements/pf-v6-button/demo/small.html @@ -0,0 +1,28 @@ +--- +name: Small buttons +description: Primary, secondary, tertiary, danger, and warning buttons can use size="sm" to fit tight spaces. +--- + +
+ Primary + Secondary + Danger secondary + Tertiary + Danger + Warning +
+ + + + diff --git a/elements/pf-v6-button/demo/stateful.html b/elements/pf-v6-button/demo/stateful.html new file mode 100644 index 0000000000..2ecccac755 --- /dev/null +++ b/elements/pf-v6-button/demo/stateful.html @@ -0,0 +1,65 @@ +--- +name: Stateful +description: Stateful buttons communicate notification state with variant="stateful" and state set to read, unread, or attention. +--- + +
+ + + Read + + + + Unread + + + + Attention + +
+ + + + diff --git a/elements/pf-v6-button/demo/types.html b/elements/pf-v6-button/demo/types.html new file mode 100644 index 0000000000..79aea764a0 --- /dev/null +++ b/elements/pf-v6-button/demo/types.html @@ -0,0 +1,38 @@ +--- +name: Button types +description: Use type to control form behavior. Omit type or use submit to submit, reset to reset, and button for a non-submitting control. +--- + +
+ +
+ Submit + Reset + Button +
+

+
+ + + + diff --git a/elements/pf-v6-button/demo/variant-examples.html b/elements/pf-v6-button/demo/variant-examples.html new file mode 100644 index 0000000000..9ce55d487c --- /dev/null +++ b/elements/pf-v6-button/demo/variant-examples.html @@ -0,0 +1,142 @@ +--- +name: Variant examples +description: PatternFly supports several button styling variants for different scenarios. Assign a variant with the variant attribute. +--- + +
+ Primary + Secondary + Danger secondary + Tertiary + Danger + Warning +
+ +
+ + + Link + + + Link + + + Inline link + Danger link + + + +
+ +
+ Control + + + +
+ +
+ + + Stateful read + + + + Stateful unread + + + + Stateful attention + +
+ + + + diff --git a/elements/pf-v6-button/demo/with-count.html b/elements/pf-v6-button/demo/with-count.html new file mode 100644 index 0000000000..509b9a354e --- /dev/null +++ b/elements/pf-v6-button/demo/with-count.html @@ -0,0 +1,33 @@ +--- +name: Button with count +description: Slot a badge into count to show a numeric value beside the button label. +--- + +
+ + Issues + 7 + + + Issues + 7 + + + Issues + 7 + +
+ + + + diff --git a/elements/pf-v6-button/docs/pf-v6-button.md b/elements/pf-v6-button/docs/pf-v6-button.md new file mode 100644 index 0000000000..553e381e59 --- /dev/null +++ b/elements/pf-v6-button/docs/pf-v6-button.md @@ -0,0 +1,44 @@ +{% renderOverview %} + A button communicates and triggers user actions when clicked or selected. + + Primary + Secondary +{% endrenderOverview %} + +{% band header="Usage" %} + ### Variants + {% htmlexample %} + Primary + Secondary + Tertiary + Danger + Warning + Link + {% endhtmlexample %} + + ### Disabled + {% htmlexample %} + Disabled + Disabled focusable + {% endhtmlexample %} + + ### Form submit + {% htmlexample %} +
+ Save + Reset +
+ {% endhtmlexample %} +{% endband %} + +{% renderSlots %}{% endrenderSlots %} + +{% renderAttributes %}{% endrenderAttributes %} + +{% renderMethods %}{% endrenderMethods %} + +{% renderEvents %}{% endrenderEvents %} + +{% renderCssCustomProperties %}{% endrenderCssCustomProperties %} + +{% renderCssParts %}{% endrenderCssParts %} diff --git a/elements/pf-v6-button/docs/screenshot.png b/elements/pf-v6-button/docs/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..9ac8d8fdb62a751dfb40232a226c5cf67a4b336b GIT binary patch literal 29209 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 WV-b26hxzCAXr#sE#R^0Wy#5FEl&>KG literal 0 HcmV?d00001 diff --git a/elements/pf-v6-button/pf-v6-button.css b/elements/pf-v6-button/pf-v6-button.css new file mode 100644 index 0000000000..d2de54df3a --- /dev/null +++ b/elements/pf-v6-button/pf-v6-button.css @@ -0,0 +1,1038 @@ +*, +*::before, +*::after { + box-sizing: border-box; +} + +:where(button) { + margin: 0; + font-family: inherit; + font-size: 100%; + line-height: var(--pf-t--global--font--line-height--body, 1.5); + color: var(--pf-t--global--text--color--regular, #151515); + cursor: pointer; +} + +:host { + color-scheme: light dark; + + + /* Base button variables */ + --pf-v6-c-button--Display: inline-flex; + --pf-v6-c-button--AlignItems: baseline; + --pf-v6-c-button--JustifyContent: center; + --pf-v6-c-button--Gap: var(--pf-t--global--spacer--gap--text-to-element--default, 0.5rem); + --pf-v6-c-button--MinWidth: calc(1em * var(--pf-v6-c-button--LineHeight) + var(--pf-v6-c-button--PaddingBlockStart) + var(--pf-v6-c-button--PaddingBlockEnd)); + --pf-v6-c-button--PaddingBlockStart: var(--pf-t--global--spacer--control--vertical--default, 0.5rem); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--default, 1.5rem); + --pf-v6-c-button--PaddingBlockEnd: var(--pf-t--global--spacer--control--vertical--default, 0.5rem); + --pf-v6-c-button--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--default, 1.5rem); + --pf-v6-c-button--Color: var(--pf-t--global--text--color--regular, #151515); + --pf-v6-c-button--LineHeight: var(--pf-t--global--font--line-height--body, 1.5); + --pf-v6-c-button--FontWeight: var(--pf-t--global--font--weight--body--default, 400); + --pf-v6-c-button--FontSize: var(--pf-t--global--font--size--body--default, 0.875rem); + --pf-v6-c-button--BackgroundColor: transparent; + --pf-v6-c-button--BorderColor: transparent; + --pf-v6-c-button--BorderWidth: var(--pf-t--global--border--width--action--default, 1px); + --pf-v6-c-button--BorderRadius: var(--pf-t--global--border--radius--pill, 999px); + --pf-v6-c-button--TextDecorationLine: none; + --pf-v6-c-button--TextDecorationStyle: none; + --pf-v6-c-button--TextDecorationColor: currentcolor; + --pf-v6-c-button--TransitionDelay: 0s; + --pf-v6-c-button--TransitionDuration: var(--pf-t--global--motion--duration--fade--default); + --pf-v6-c-button--TransitionTimingFunction: var(--pf-t--global--motion--timing-function--accelerate); + --pf-v6-c-button--TransitionProperty: color, background, border-color; + --pf-v6-c-button--ScaleX: 1; + --pf-v6-c-button--ScaleY: 1; + --pf-v6-c-button--border--offset: 0; + + /* Hover */ + --pf-v6-c-button--hover--BackgroundColor: transparent; + --pf-v6-c-button--hover--BorderColor: transparent; + --pf-v6-c-button--hover--BorderWidth: var(--pf-t--global--border--width--action--hover); + --pf-v6-c-button--hover--TextDecorationLine: none; + --pf-v6-c-button--hover--TextDecorationStyle: none; + --pf-v6-c-button--hover--TextDecorationColor: currentcolor; + --pf-v6-c-button--hover--ScaleX: 1; + --pf-v6-c-button--hover--ScaleY: 1; + + /* Clicked */ + --pf-v6-c-button--m-clicked--BackgroundColor: transparent; + --pf-v6-c-button--m-clicked--BorderColor: transparent; + --pf-v6-c-button--m-clicked--BorderWidth: var(--pf-t--global--border--width--action--clicked); + + /* Primary */ + --pf-v6-c-button--m-primary--Color: var(--pf-t--global--text--color--on-brand--default, #ffffff); + --pf-v6-c-button--m-primary--BackgroundColor: var(--pf-t--global--color--brand--default, #0066cc); + --pf-v6-c-button--m-primary__icon--Color: var(--pf-t--global--icon--color--on-brand--default, #ffffff); + --pf-v6-c-button--m-primary--hover--Color: var(--pf-t--global--text--color--on-brand--hover, #ffffff); + --pf-v6-c-button--m-primary--hover--BackgroundColor: var(--pf-t--global--color--brand--hover, #004d99); + --pf-v6-c-button--m-primary--hover__icon--Color: var(--pf-t--global--icon--color--on-brand--hover, #ffffff); + --pf-v6-c-button--m-primary--m-clicked--Color: var(--pf-t--global--text--color--on-brand--clicked, #ffffff); + --pf-v6-c-button--m-primary--m-clicked--BackgroundColor: var(--pf-t--global--color--brand--clicked, #004d99); + --pf-v6-c-button--m-primary--m-clicked__icon--Color: var(--pf-t--global--icon--color--on-brand--clicked, #ffffff); + + /* Secondary */ + --pf-v6-c-button--m-secondary--Color: var(--pf-t--global--text--color--brand--default, #0066cc); + --pf-v6-c-button--m-secondary--BorderColor: var(--pf-t--global--border--color--brand--default, #0066cc); + --pf-v6-c-button--m-secondary--TransitionDuration: var(--pf-t--global--motion--duration--fade--short); + --pf-v6-c-button--m-secondary__icon--Color: var(--pf-t--global--icon--color--brand--default, #0066cc); + --pf-v6-c-button--m-secondary--hover--Color: var(--pf-t--global--text--color--brand--hover, #004d99); + --pf-v6-c-button--m-secondary--hover--BorderColor: var(--pf-t--global--border--color--brand--hover, #004d99); + --pf-v6-c-button--m-secondary--hover__icon--Color: var(--pf-t--global--icon--color--brand--hover, #004d99); + --pf-v6-c-button--m-secondary--m-clicked--Color: var(--pf-t--global--text--color--brand--clicked, #004d99); + --pf-v6-c-button--m-secondary--m-clicked--BorderColor: var(--pf-t--global--border--color--brand--clicked, #004d99); + --pf-v6-c-button--m-secondary--m-clicked__icon--Color: var(--pf-t--global--icon--color--brand--clicked, #004d99); + --pf-v6-c-button--m-secondary--m-danger--Color: var(--pf-t--global--text--color--status--danger--default, #b1380b); + --pf-v6-c-button--m-secondary--m-danger--BorderColor: var(--pf-t--global--border--color--status--danger--default, #b1380b); + --pf-v6-c-button--m-secondary--m-danger__icon--Color: var(--pf-t--global--icon--color--status--danger--default, #b1380b); + --pf-v6-c-button--m-secondary--m-danger--hover--Color: var(--pf-t--global--text--color--status--danger--hover, #731f00); + --pf-v6-c-button--m-secondary--m-danger--hover--BorderColor: var(--pf-t--global--border--color--status--danger--hover, #731f00); + --pf-v6-c-button--m-secondary--m-danger--hover__icon--Color: var(--pf-t--global--icon--color--status--danger--hover, #731f00); + --pf-v6-c-button--m-secondary--m-danger--m-clicked--Color: var(--pf-t--global--text--color--status--danger--clicked, #731f00); + --pf-v6-c-button--m-secondary--m-danger--m-clicked--BorderColor: var(--pf-t--global--border--color--status--danger--clicked, #731f00); + --pf-v6-c-button--m-secondary--m-danger--m-clicked__icon--Color: var(--pf-t--global--icon--color--status--danger--clicked, #731f00); + + /* Tertiary */ + --pf-v6-c-button--m-tertiary--Color: var(--pf-t--global--text--color--brand--default, #0066cc); + --pf-v6-c-button--m-tertiary--BorderColor: var(--pf-t--global--border--color--default); + --pf-v6-c-button--m-tertiary--TransitionDuration: var(--pf-t--global--motion--duration--fade--short); + --pf-v6-c-button--m-tertiary__icon--Color: var(--pf-t--global--icon--color--brand--default, #0066cc); + --pf-v6-c-button--m-tertiary--hover--Color: var(--pf-t--global--text--color--brand--hover, #004d99); + --pf-v6-c-button--m-tertiary--hover--BorderColor: var(--pf-t--global--border--color--hover); + --pf-v6-c-button--m-tertiary--hover__icon--Color: var(--pf-t--global--icon--color--brand--hover, #004d99); + --pf-v6-c-button--m-tertiary--m-clicked--Color: var(--pf-t--global--text--color--brand--clicked, #004d99); + --pf-v6-c-button--m-tertiary--m-clicked--BorderColor: var(--pf-t--global--border--color--clicked); + --pf-v6-c-button--m-tertiary--m-clicked__icon--Color: var(--pf-t--global--icon--color--brand--clicked, #004d99); + + /* Link */ + --pf-v6-c-button--m-link--BorderRadius: var(--pf-t--global--border--radius--small, 6px); + --pf-v6-c-button--m-link--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--plain--default, 0.5rem); + --pf-v6-c-button--m-link--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--plain--default, 0.5rem); + --pf-v6-c-button--m-link--Color: var(--pf-t--global--text--color--brand--default, #0066cc); + --pf-v6-c-button--m-link--BackgroundColor: var(--pf-t--global--background--color--action--plain--default, rgb(255 255 255 / 0%)); + --pf-v6-c-button--m-link__icon--Color: var(--pf-t--global--icon--color--brand--default, #0066cc); + --pf-v6-c-button--m-link--hover--Color: var(--pf-t--global--text--color--brand--hover, #004d99); + --pf-v6-c-button--m-link--hover--BackgroundColor: var(--pf-t--global--background--color--action--plain--hover, rgb(0 0 0 / 8%)); + --pf-v6-c-button--m-link--hover__icon--Color: var(--pf-t--global--text--color--brand--hover, #004d99); + --pf-v6-c-button--m-link--m-clicked--Color: var(--pf-t--global--text--color--brand--clicked, #004d99); + --pf-v6-c-button--m-link--m-clicked--BackgroundColor: var(--pf-t--global--background--color--action--plain--clicked, rgb(0 0 0 / 16%)); + --pf-v6-c-button--m-link--m-clicked__icon--Color: var(--pf-t--global--text--color--brand--clicked, #004d99); + --pf-v6-c-button--m-link--m-small--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--plain--compact, 0.25rem); + --pf-v6-c-button--m-link--m-small--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--plain--compact, 0.25rem); + --pf-v6-c-button--m-link--BorderWidth: var(--pf-t--global--border--width--action--plain--default, 0px); + --pf-v6-c-button--m-link--m-clicked--BorderWidth: var(--pf-t--global--border--width--action--plain--clicked, 0px); + --pf-v6-c-button--m-link--hover--BorderWidth: var(--pf-t--global--border--width--action--plain--hover, 0px); + --pf-v6-c-button--m-link--BorderColor: var(--pf-t--global--border--color--high-contrast, rgb(255 255 255 / 0%)); + --pf-v6-c-button--m-link--m-clicked--BorderColor: var(--pf-t--global--border--color--high-contrast, rgb(255 255 255 / 0%)); + --pf-v6-c-button--m-link--hover--BorderColor: var(--pf-t--global--border--color--high-contrast, rgb(255 255 255 / 0%)); + + /* Link danger */ + --pf-v6-c-button--m-link--m-danger--Color: var(--pf-t--global--text--color--status--danger--default, #b1380b); + --pf-v6-c-button--m-link--m-danger--BackgroundColor: var(--pf-t--global--background--color--action--plain--default, rgb(255 255 255 / 0%)); + --pf-v6-c-button--m-link--m-danger__icon--Color: var(--pf-t--global--text--color--status--danger--default, #b1380b); + --pf-v6-c-button--m-link--m-danger--hover--Color: var(--pf-t--global--text--color--status--danger--hover, #731f00); + --pf-v6-c-button--m-link--m-danger--hover--BackgroundColor: var(--pf-t--global--background--color--action--plain--hover, rgb(0 0 0 / 8%)); + --pf-v6-c-button--m-link--m-danger--hover__icon--Color: var(--pf-t--global--text--color--status--danger--hover, #731f00); + --pf-v6-c-button--m-link--m-danger--m-clicked--Color: var(--pf-t--global--text--color--status--danger--clicked, #731f00); + --pf-v6-c-button--m-link--m-danger--m-clicked--BackgroundColor: var(--pf-t--global--background--color--action--plain--clicked, rgb(0 0 0 / 16%)); + --pf-v6-c-button--m-link--m-danger--m-clicked__icon--Color: var(--pf-t--global--text--color--status--danger--clicked, #731f00); + + /* Link inline */ + --pf-v6-c-button--m-link--m-inline--Display: inline-flex; + --pf-v6-c-button--m-link--m-inline--JustifyContent: flex-start; + --pf-v6-c-button--m-link--m-inline--FontSize: initial; + --pf-v6-c-button--m-link--m-inline--LineHeight: initial; + --pf-v6-c-button--m-link--m-inline--FontWeight: initial; + --pf-v6-c-button--m-link--m-inline--PaddingBlockStart: 0; + --pf-v6-c-button--m-link--m-inline--PaddingInlineEnd: 0; + --pf-v6-c-button--m-link--m-inline--PaddingBlockEnd: 0; + --pf-v6-c-button--m-link--m-inline--PaddingInlineStart: 0; + --pf-v6-c-button--m-link--m-inline--TextDecorationLine: var(--pf-t--global--text-decoration--link--line--default); + --pf-v6-c-button--m-link--m-inline--TextDecorationStyle: var(--pf-t--global--text-decoration--link--style--default); + --pf-v6-c-button--m-link--m-inline--hover--TextDecorationLine: var(--pf-t--global--text-decoration--link--line--hover); + --pf-v6-c-button--m-link--m-inline--hover--TextDecorationStyle: var(--pf-t--global--text-decoration--link--style--hover); + --pf-v6-c-button--m-link--m-inline__progress--InsetInlineStart: var(--pf-t--global--spacer--xs, 0.25rem); + --pf-v6-c-button--m-link--m-inline--m-in-progress--PaddingInlineStart: calc(var(--pf-v6-c-button--m-link--m-inline__progress--InsetInlineStart) + 1rem + var(--pf-t--global--spacer--sm, 0.5rem)); + --pf-v6-c-button--m-link--m-inline--disabled--Color: var(--pf-t--global--text--color--disabled); + --pf-v6-c-button--m-link--m-inline--disabled__icon--Color: var(--pf-t--global--icon--color--disabled); + --pf-v6-c-button--span--m-link--m-inline--Display: inline; + --pf-v6-c-button--span--m-link--m-inline__icon--m-start--MarginInlineEnd: var(--pf-t--global--spacer--gap--text-to-element--default, 0.5rem); + --pf-v6-c-button--span--m-link--m-inline__icon--m-end--MarginInlineStart: var(--pf-t--global--spacer--gap--text-to-element--default, 0.5rem); + --pf-v6-c-button--m-link--m-inline--Color: var(--pf-t--global--text--color--brand--default, #0066cc); + --pf-v6-c-button--m-link--m-inline__icon--Color: var(--pf-t--global--icon--color--brand--default, #0066cc); + --pf-v6-c-button--m-link--m-inline--TextDecorationColor: currentcolor; + --pf-v6-c-button--m-link--m-inline--hover--Color: var(--pf-t--global--text--color--brand--hover, #004d99); + --pf-v6-c-button--m-link--m-inline--hover__icon--Color: var(--pf-t--global--icon--color--brand--hover, #004d99); + --pf-v6-c-button--m-link--m-inline--hover--TextDecorationColor: currentcolor; + + /* Plain */ + --pf-v6-c-button--m-plain--BorderRadius: var(--pf-t--global--border--radius--small, 6px); + --pf-v6-c-button--m-plain--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--plain--default, 0.5rem); + --pf-v6-c-button--m-plain--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--plain--default, 0.5rem); + --pf-v6-c-button--m-plain--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-plain__icon--Color: var(--pf-t--global--text--color--regular, #151515); + --pf-v6-c-button--m-plain--BackgroundColor: var(--pf-t--global--background--color--action--plain--default, rgb(255 255 255 / 0%)); + --pf-v6-c-button--m-plain--hover--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-plain--hover--BackgroundColor: var(--pf-t--global--background--color--action--plain--hover, rgb(0 0 0 / 8%)); + --pf-v6-c-button--m-plain--m-clicked--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-plain--m-clicked--BackgroundColor: var(--pf-t--global--background--color--action--plain--clicked, rgb(0 0 0 / 16%)); + --pf-v6-c-button--m-plain--disabled--Color: var(--pf-t--global--text--color--disabled); + --pf-v6-c-button--m-plain--disabled__icon--Color: var(--pf-t--global--icon--color--disabled); + --pf-v6-c-button--m-plain--disabled--BackgroundColor: transparent; + --pf-v6-c-button--m-plain--m-small--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--plain--compact, 0.25rem); + --pf-v6-c-button--m-plain--m-small--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--plain--compact, 0.25rem); + --pf-v6-c-button--m-plain--BorderWidth: var(--pf-t--global--border--width--action--plain--default, 0px); + --pf-v6-c-button--m-plain--m-clicked--BorderWidth: var(--pf-t--global--border--width--action--plain--clicked, 0px); + --pf-v6-c-button--m-plain--hover--BorderWidth: var(--pf-t--global--border--width--action--plain--hover, 0px); + --pf-v6-c-button--m-plain--BorderColor: transparent; + --pf-v6-c-button--m-plain--m-clicked--BorderColor: var(--pf-t--global--border--color--high-contrast, rgb(255 255 255 / 0%)); + --pf-v6-c-button--m-plain--hover--BorderColor: var(--pf-t--global--border--color--high-contrast, rgb(255 255 255 / 0%)); + + /* Plain no padding */ + --pf-v6-c-button--m-plain--m-no-padding--MinWidth: auto; + --pf-v6-c-button--m-plain--m-no-padding--PaddingBlockStart: 0; + --pf-v6-c-button--m-plain--m-no-padding--PaddingInlineEnd: 0; + --pf-v6-c-button--m-plain--m-no-padding--PaddingBlockEnd: 0; + --pf-v6-c-button--m-plain--m-no-padding--PaddingInlineStart: 0; + --pf-v6-c-button--m-plain--m-no-padding--m-small--PaddingInlineStart: 0; + --pf-v6-c-button--m-plain--m-no-padding--m-small--PaddingInlineEnd: 0; + --pf-v6-c-button--m-plain--m-no-padding__icon--Color: var(--pf-t--global--icon--color--subtle); + --pf-v6-c-button--m-plain--m-no-padding--BackgroundColor: transparent; + --pf-v6-c-button--m-plain--m-no-padding--hover__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-plain--m-no-padding--hover--BackgroundColor: transparent; + --pf-v6-c-button--m-plain--m-no-padding--m-clicked--BackgroundColor: transparent; + --pf-v6-c-button--m-plain--m-no-padding--border--offset: -0.125rem; + + /* Control */ + --pf-v6-c-button--m-control--BorderRadius: var(--pf-t--global--border--radius--small, 6px); + --pf-v6-c-button--m-control--PaddingInlineStart: var(--pf-t--global--spacer--control--horizontal--default); + --pf-v6-c-button--m-control--PaddingInlineEnd: var(--pf-t--global--spacer--control--horizontal--default); + --pf-v6-c-button--m-control--Color: var(--pf-t--global--text--color--regular, #151515); + --pf-v6-c-button--m-control--BackgroundColor: var(--pf-t--global--background--color--control--default, #ffffff); + --pf-v6-c-button--m-control--BorderColor: var(--pf-t--global--border--color--default); + --pf-v6-c-button--m-control--BorderWidth: var(--pf-t--global--border--width--control--default, 1px); + --pf-v6-c-button--m-control__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-control--hover--Color: var(--pf-t--global--text--color--regular, #151515); + --pf-v6-c-button--m-control--hover--BackgroundColor: var(--pf-t--global--background--color--control--default, #ffffff); + --pf-v6-c-button--m-control--hover--BorderColor: var(--pf-t--global--border--color--hover); + --pf-v6-c-button--m-control--hover--BorderWidth: var(--pf-t--global--border--width--control--hover, 2px); + --pf-v6-c-button--m-control--hover__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-control--m-clicked--Color: var(--pf-t--global--text--color--regular, #151515); + --pf-v6-c-button--m-control--m-clicked--BackgroundColor: var(--pf-t--global--background--color--control--default, #ffffff); + --pf-v6-c-button--m-control--m-clicked--BorderColor: var(--pf-t--global--border--color--clicked); + --pf-v6-c-button--m-control--m-clicked--BorderWidth: var(--pf-t--global--border--width--control--clicked, 2px); + --pf-v6-c-button--m-control--m-clicked__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-control--m-small--PaddingInlineEnd: var(--pf-t--global--spacer--control--horizontal--compact); + --pf-v6-c-button--m-control--m-small--PaddingInlineStart: var(--pf-t--global--spacer--control--horizontal--compact); + + /* Stateful */ + --pf-v6-c-button--m-stateful--BorderRadius: var(--pf-t--global--border--radius--small, 6px); + --pf-v6-c-button--m-stateful--PaddingInlineStart: var(--pf-t--global--spacer--control--horizontal--default); + --pf-v6-c-button--m-stateful--PaddingInlineEnd: var(--pf-t--global--spacer--control--horizontal--default); + --pf-v6-c-button--m-stateful--m-small--PaddingInlineEnd: var(--pf-t--global--spacer--control--horizontal--compact); + --pf-v6-c-button--m-stateful--m-small--PaddingInlineStart: var(--pf-t--global--spacer--control--horizontal--compact); + + /* Read */ + --pf-v6-c-button--m-read--BackgroundColor: var(--pf-t--global--background--color--control--default, #ffffff); + --pf-v6-c-button--m-read--BorderColor: var(--pf-t--global--border--color--default); + --pf-v6-c-button--m-read--hover--BackgroundColor: var(--pf-t--global--background--color--control--default, #ffffff); + --pf-v6-c-button--m-read--hover--BorderColor: var(--pf-t--global--border--color--hover); + --pf-v6-c-button--m-read--m-clicked--BackgroundColor: var(--pf-t--global--background--color--control--default, #ffffff); + --pf-v6-c-button--m-read--m-clicked--BorderColor: var(--pf-t--global--border--color--clicked); + + /* Unread */ + --pf-v6-c-button--m-unread--Color: var(--pf-t--global--text--color--status--unread--on-default--default); + --pf-v6-c-button--m-unread--BackgroundColor: var(--pf-t--global--color--status--unread--default, #0066cc); + --pf-v6-c-button--m-unread__icon--Color: var(--pf-t--global--icon--color--status--unread--on-default--default); + --pf-v6-c-button--m-unread--hover--Color: var(--pf-t--global--text--color--status--unread--on-default--hover); + --pf-v6-c-button--m-unread--hover--BackgroundColor: var(--pf-t--global--color--status--unread--hover, #004d99); + --pf-v6-c-button--m-unread--hover__icon--Color: var(--pf-t--global--icon--color--status--unread--on-default--hover); + --pf-v6-c-button--m-unread--m-clicked--Color: var(--pf-t--global--text--color--status--unread--on-default--clicked); + --pf-v6-c-button--m-unread--m-clicked--BackgroundColor: var(--pf-t--global--color--status--unread--clicked, #004d99); + --pf-v6-c-button--m-unread--m-clicked__icon--Color: var(--pf-t--global--icon--color--status--unread--on-default--clicked); + + /* Attention */ + --pf-v6-c-button--m-attention--Color: var(--pf-t--global--text--color--status--unread--on-attention--default); + --pf-v6-c-button--m-attention--BackgroundColor: var(--pf-t--global--color--status--unread--attention--default); + --pf-v6-c-button--m-attention__icon--Color: var(--pf-t--global--icon--color--status--unread--on-attention--default); + --pf-v6-c-button--m-attention--hover--Color: var(--pf-t--global--text--color--status--unread--on-attention--hover); + --pf-v6-c-button--m-attention--hover--BackgroundColor: var(--pf-t--global--color--status--unread--attention--hover); + --pf-v6-c-button--m-attention--hover__icon--Color: var(--pf-t--global--icon--color--status--unread--on-attention--hover); + --pf-v6-c-button--m-attention--m-clicked--Color: var(--pf-t--global--text--color--status--unread--on-attention--clicked); + --pf-v6-c-button--m-attention--m-clicked--BackgroundColor: var(--pf-t--global--color--status--unread--attention--clicked); + --pf-v6-c-button--m-attention--m-clicked__icon--Color: var(--pf-t--global--icon--color--status--unread--on-attention--clicked); + + /* Warning */ + --pf-v6-c-button--m-warning--Color: var(--pf-t--global--text--color--status--on-warning--default, #151515); + --pf-v6-c-button--m-warning--BackgroundColor: var(--pf-t--global--color--status--warning--default, #ffcc17); + --pf-v6-c-button--m-warning__icon--Color: var(--pf-t--global--icon--color--status--on-warning--default, #151515); + --pf-v6-c-button--m-warning--hover--Color: var(--pf-t--global--text--color--status--on-warning--hover, #151515); + --pf-v6-c-button--m-warning--hover--BackgroundColor: var(--pf-t--global--color--status--warning--hover, #dca614); + --pf-v6-c-button--m-warning--hover__icon--Color: var(--pf-t--global--icon--color--status--on-warning--hover, #151515); + --pf-v6-c-button--m-warning--m-clicked--Color: var(--pf-t--global--text--color--status--on-warning--clicked, #151515); + --pf-v6-c-button--m-warning--m-clicked--BackgroundColor: var(--pf-t--global--color--status--warning--clicked, #dca614); + --pf-v6-c-button--m-warning--m-clicked__icon--Color: var(--pf-t--global--icon--color--status--on-warning--clicked, #151515); + + /* Danger */ + --pf-v6-c-button--m-danger--Color: var(--pf-t--global--text--color--status--on-danger--default, #ffffff); + --pf-v6-c-button--m-danger--BackgroundColor: var(--pf-t--global--color--status--danger--default, #b1380b); + --pf-v6-c-button--m-danger__icon--Color: var(--pf-t--global--icon--color--status--on-danger--default, #ffffff); + --pf-v6-c-button--m-danger--hover--Color: var(--pf-t--global--text--color--status--on-danger--hover, #ffffff); + --pf-v6-c-button--m-danger--hover--BackgroundColor: var(--pf-t--global--color--status--danger--hover, #731f00); + --pf-v6-c-button--m-danger--hover__icon--Color: var(--pf-t--global--icon--color--status--on-danger--hover, #ffffff); + --pf-v6-c-button--m-danger--m-clicked--Color: var(--pf-t--global--text--color--status--on-danger--clicked, #ffffff); + --pf-v6-c-button--m-danger--m-clicked--BackgroundColor: var(--pf-t--global--color--status--danger--clicked, #731f00); + --pf-v6-c-button--m-danger--m-clicked__icon--Color: var(--pf-t--global--icon--color--status--on-danger--clicked, #ffffff); + + /* Display lg (CTA) */ + --pf-v6-c-button--m-display-lg--PaddingBlockStart: var(--pf-t--global--spacer--control--vertical--spacious); + --pf-v6-c-button--m-display-lg--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--spacious, 2rem); + --pf-v6-c-button--m-display-lg--PaddingBlockEnd: var(--pf-t--global--spacer--control--vertical--spacious); + --pf-v6-c-button--m-display-lg--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--spacious, 2rem); + --pf-v6-c-button--m-display-lg--FontWeight: var(--pf-t--global--font--weight--body--bold); + --pf-v6-c-button--m-link--m-display-lg--FontSize: var(--pf-t--global--font--size--body--lg); + + /* Small */ + --pf-v6-c-button--m-small--PaddingBlockStart: var(--pf-t--global--spacer--control--vertical--compact); + --pf-v6-c-button--m-small--PaddingInlineEnd: var(--pf-t--global--spacer--action--horizontal--compact, 1rem); + --pf-v6-c-button--m-small--PaddingBlockEnd: var(--pf-t--global--spacer--control--vertical--compact); + --pf-v6-c-button--m-small--PaddingInlineStart: var(--pf-t--global--spacer--action--horizontal--compact, 1rem); + + /* Disabled */ + --pf-v6-c-button--disabled--Color: var(--pf-t--global--text--color--on-disabled, #6a6e73); + --pf-v6-c-button--disabled--BackgroundColor: var(--pf-t--global--background--color--disabled--default, #d2d2d2); + --pf-v6-c-button--disabled--TextDecorationColor: currentcolor; + --pf-v6-c-button--disabled--BorderColor: transparent; + --pf-v6-c-button--disabled__icon--Color: var(--pf-t--global--icon--color--on-disabled, #6a6e73); + + /* Icon */ + --pf-v6-c-button__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--hover__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-t--global--icon--color--regular, #151515); + --pf-v6-c-button__icon--MarginInlineStart: 0; + --pf-v6-c-button__icon--MarginInlineEnd: 0; + --pf-v6-c-button__icon--m-start--MarginInlineEnd: 0; + --pf-v6-c-button__icon--m-end--MarginInlineStart: 0; + --pf-v6-c-button--m-notify__icon--AnimationDuration--notify: var(--pf-t--global--motion--duration--3xl); + --pf-v6-c-button--m-notify__icon--AnimationTimingFunction--notify: var(--pf-t--global--motion--timing-function--default); + --pf-v6-c-button__icon--TransitionDelay: 0s; + --pf-v6-c-button__icon--TransitionTimingFunction: auto; + --pf-v6-c-button__icon--TransitionDuration: 0s; + --pf-v6-c-button__icon--TransitionProperty: none; + --pf-v6-c-button__icon--Rotate: 0deg; + --pf-v6-c-button--hover__icon--TransitionTimingFunction: auto; + --pf-v6-c-button--hover__icon--TransitionDuration: 0s; + --pf-v6-c-button--hover__icon--TransitionProperty: none; + --pf-v6-c-button--hover__icon--Rotate: 0deg; + --pf-v6-c-button__icon--ScaleX: 1; + --pf-v6-c-button__icon--ScaleY: 1; + --pf-v6-c-button--hover__icon--ScaleX: 1; + --pf-v6-c-button--hover__icon--ScaleY: 1; + + /* Favorite button */ + --pf-v6-c-button--m-favorite__icon--TransitionDuration: var(--pf-t--global--motion--duration--icon--default); + --pf-v6-c-button--m-favorite__icon--TransitionTimingFunction: var(--pf-t--global--motion--timing-function--default); + --pf-v6-c-button--m-favorited__icon--Color: var(--pf-t--global--color--favorite--default); + --pf-v6-c-button--m-favorited--hover__icon--Color: var(--pf-t--global--color--favorite--hover); + --pf-v6-c-button--m-favorited__icon--AnimationDuration: var(--pf-t--global--motion--duration--icon--long); + --pf-v6-c-button--m-favorited__icon--AnimationTimingFunction: var(--pf-t--global--motion--timing-function--default); + --pf-v6-c-button__icon--favorite--Opacity: 1; + --pf-v6-c-button__icon--favorited--Opacity: 0; + --pf-v6-c-button--m-favorited__icon--favorite--Opacity: 0; + --pf-v6-c-button--m-favorited__icon--favorited--Opacity: 1; + --pf-v6-c-button__icon--favorite--TransitionDuration: var(--pf-t--global--motion--duration--icon--default); + + /* Progress */ + --pf-v6-c-button__progress--width: calc(var(--pf-t--global--icon--size--lg) + var(--pf-t--global--spacer--sm, 0.5rem)); + --pf-v6-c-button__progress--Opacity: 0; + --pf-v6-c-button__progress--TranslateY: -50%; + --pf-v6-c-button__progress--TranslateX: 0; + --pf-v6-c-button__progress--InsetBlockStart: 50%; + --pf-v6-c-button__progress--InsetInlineStart: var(--pf-t--global--spacer--control--horizontal--default); + --pf-v6-c-button--m-progress--PaddingInlineEnd: calc(var(--pf-t--global--spacer--control--horizontal--default) + var(--pf-v6-c-button__progress--width) / 2); + --pf-v6-c-button--m-progress--PaddingInlineStart: calc(var(--pf-t--global--spacer--control--horizontal--default) + var(--pf-v6-c-button__progress--width) / 2); + --pf-v6-c-button--m-in-progress--PaddingInlineEnd: var(--pf-t--global--spacer--control--horizontal--default); + --pf-v6-c-button--m-in-progress--PaddingInlineStart: calc(var(--pf-t--global--spacer--control--horizontal--default) + var(--pf-v6-c-button__progress--width)); + --pf-v6-c-button--m-in-progress--m-plain--Color: var(--pf-t--global--icon--color--brand--default, #0066cc); + --pf-v6-c-button--m-in-progress--m-plain__progress--InsetInlineStart: 50%; + --pf-v6-c-button--m-in-progress--m-plain__progress--TranslateX: -50%; + + /* Settings */ + --pf-v6-c-button--m-settings__icon--TransitionDuration: var(--pf-t--global--motion--duration--icon--long); + --pf-v6-c-button--m-settings__icon--TransitionTimingFunction: var(--pf-t--global--motion--timing-function--accelerate); + --pf-v6-c-button--m-settings--hover__icon--TransitionDuration: var(--pf-t--global--motion--duration--icon--long); + --pf-v6-c-button--m-settings--hover__icon--TransitionTimingFunction: var(--pf-t--global--motion--timing-function--decelerate); + --pf-v6-c-button--m-settings--hover__icon--Rotate: 60deg; + + /* Count */ + --pf-v6-c-button--m-primary__c-badge--BorderColor: var(--pf-t--global--border--color--alt); + + /* Block */ + --pf-v6-c-button--m-block--Display: flex; + --pf-v6-c-button--m-block--Width: 100%; + + /* Hamburger */ + --pf-v6-c-button--hamburger-icon--TransitionTimingFunction: var(--pf-t--global--motion--timing-function--decelerate); + --pf-v6-c-button--hamburger-icon--TransitionDuration: var(--pf-t--global--motion--duration--md); + --pf-v6-c-button--hamburger-icon--top--path--base: path("M1,1 L9,1"); + --pf-v6-c-button--hamburger-icon--middle--path--base: path("M1,5 L9,5"); + --pf-v6-c-button--hamburger-icon--arrow--path--base: path("M1,5 L1,5 L1,5"); + --pf-v6-c-button--hamburger-icon--bottom--path--base: path("M9,9 L1,9"); + --pf-v6-c-button--hamburger-icon--top--path: var(--pf-v6-c-button--hamburger-icon--top--path--base); + --pf-v6-c-button--hamburger-icon--middle--path: var(--pf-v6-c-button--hamburger-icon--middle--path--base); + --pf-v6-c-button--hamburger-icon--arrow--path: var(--pf-v6-c-button--hamburger-icon--arrow--path--base); + --pf-v6-c-button--hamburger-icon--bottom--path: var(--pf-v6-c-button--hamburger-icon--bottom--path--base); + --pf-v6-c-button--hamburger-icon--top--collapse--path: path("M5,1 L9,1"); + --pf-v6-c-button--hamburger-icon--arrow--collapse--path: path("M3,7 L1,5 L3,3"); + --pf-v6-c-button--hamburger-icon--bottom--collapse--path: path("M9,9 L5,9"); + --pf-v6-c-button--m-hamburger__icon--m-expand--ScaleX: -1; + + display: inline-block; + font-family: var(--pf-t--global--font--family--body, "Red Hat Text", RedHatText, Helvetica, Arial, sans-serif); + vertical-align: middle; + max-width: 100%; + cursor: pointer; + outline: none; +} + +#button { + --pf-v6-c-button__progress--Color: var(--pf-v6-c-button__icon--Color); + + position: relative; + inset: auto; + transform: none; + display: var(--pf-v6-c-button--Display, inline-flex); + gap: var(--pf-v6-c-button--Gap, var(--pf-t--global--spacer--gap--text-to-element--default, 0.5rem)); + align-items: var(--pf-v6-c-button--AlignItems, baseline); + justify-content: var(--pf-v6-c-button--JustifyContent, center); + min-width: var(--pf-v6-c-button--MinWidth); + padding-block-start: var(--pf-v6-c-button--PaddingBlockStart, var(--pf-t--global--spacer--control--vertical--default, 0.5rem)); + padding-block-end: var(--pf-v6-c-button--PaddingBlockEnd, var(--pf-t--global--spacer--control--vertical--default, 0.5rem)); + padding-inline-start: var(--pf-v6-c-button--PaddingInlineStart, var(--pf-t--global--spacer--action--horizontal--default, 1.5rem)); + padding-inline-end: var(--pf-v6-c-button--PaddingInlineEnd, var(--pf-t--global--spacer--action--horizontal--default, 1.5rem)); + font-family: inherit; + font-size: var(--pf-v6-c-button--FontSize, inherit); + font-weight: var(--pf-v6-c-button--FontWeight, inherit); + line-height: var(--pf-v6-c-button--LineHeight, inherit); + color: var(--pf-v6-c-button--Color, var(--pf-t--global--text--color--regular, #151515)); + text-align: center; + text-decoration-line: var(--pf-v6-c-button--TextDecorationLine); + text-decoration-style: var(--pf-v6-c-button--TextDecorationStyle); + text-decoration-color: var(--pf-v6-c-button--TextDecorationColor); + white-space: nowrap; + cursor: pointer; + user-select: none; + background-color: var(--pf-v6-c-button--BackgroundColor, transparent); + background-image: radial-gradient(circle, transparent 1%, color-mix(in srgb, currentcolor 15%, transparent) 2%); + background-position: center; + background-size: 15000% 15000%; + border: 0; + border-start-start-radius: var(--pf-v6-c-button--BorderStartStartRadius, var(--pf-v6-c-button--BorderRadius)); + border-start-end-radius: var(--pf-v6-c-button--BorderStartEndRadius, var(--pf-v6-c-button--BorderRadius)); + border-end-start-radius: var(--pf-v6-c-button--BorderEndStartRadius, var(--pf-v6-c-button--BorderRadius)); + border-end-end-radius: var(--pf-v6-c-button--BorderEndEndRadius, var(--pf-v6-c-button--BorderRadius)); + transition-delay: var(--pf-v6-c-button--TransitionDelay); + transition-timing-function: var(--pf-v6-c-button--TransitionTimingFunction); + transition-duration: var(--pf-v6-c-button--TransitionDuration); + transition-property: var(--pf-v6-c-button--TransitionProperty); + scale: var(--pf-v6-c-button--ScaleX) var(--pf-v6-c-button--ScaleY); + + &::after { + position: absolute; + inset: var(--pf-v6-c-button--border--offset); + pointer-events: none; + content: ""; + border: var(--pf-v6-c-button--BorderWidth) solid; + border-color: var(--pf-v6-c-button--BorderColor); + border-radius: inherit; + transition: inherit; + } + + /* Primary variant */ + &.primary { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-primary--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-primary--BackgroundColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-primary__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-primary--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-primary--hover--BackgroundColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-primary--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-primary--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-primary--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-primary--m-clicked__icon--Color); + } + + /* Secondary variant */ + &.secondary { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-secondary--Color); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-secondary--BorderColor); + --pf-v6-c-button--TransitionDuration: var(--pf-v6-c-button--m-secondary--TransitionDuration); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-secondary__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-secondary--hover--Color); + --pf-v6-c-button--hover--BorderColor: var(--pf-v6-c-button--m-secondary--hover--BorderColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-secondary--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-secondary--m-clicked--Color); + --pf-v6-c-button--m-clicked--BorderColor: var(--pf-v6-c-button--m-secondary--m-clicked--BorderColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-secondary--m-clicked__icon--Color); + --pf-v6-c-button--m-danger--Color: var(--pf-v6-c-button--m-secondary--m-danger--Color); + --pf-v6-c-button--m-danger__icon--Color: var(--pf-v6-c-button--m-secondary--m-danger__icon--Color); + --pf-v6-c-button--m-danger--hover--Color: var(--pf-v6-c-button--m-secondary--m-danger--hover--Color); + --pf-v6-c-button--m-danger--hover__icon--Color: var(--pf-v6-c-button--m-secondary--m-danger--hover__icon--Color); + --pf-v6-c-button--m-danger--m-clicked--Color: var(--pf-v6-c-button--m-secondary--m-danger--m-clicked--Color); + --pf-v6-c-button--m-danger--m-clicked__icon--Color: var(--pf-v6-c-button--m-secondary--m-danger--m-clicked__icon--Color); + + &.danger { + --pf-v6-c-button--m-secondary--BorderColor: var(--pf-v6-c-button--m-secondary--m-danger--BorderColor); + --pf-v6-c-button--m-secondary--hover--BorderColor: var(--pf-v6-c-button--m-secondary--m-danger--hover--BorderColor); + --pf-v6-c-button--m-secondary--m-clicked--BorderColor: var(--pf-v6-c-button--m-secondary--m-danger--m-clicked--BorderColor); + --pf-v6-c-button--m-danger--BackgroundColor: transparent; + --pf-v6-c-button--m-danger--hover--BackgroundColor: transparent; + --pf-v6-c-button--m-danger--m-clicked--BackgroundColor: transparent; + } + } + + /* Tertiary variant */ + &.tertiary { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-tertiary--Color); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-tertiary--BorderColor); + --pf-v6-c-button--TransitionDuration: var(--pf-v6-c-button--m-tertiary--TransitionDuration); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-tertiary__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-tertiary--hover--Color); + --pf-v6-c-button--hover--BorderColor: var(--pf-v6-c-button--m-tertiary--hover--BorderColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-tertiary--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-tertiary--m-clicked--Color); + --pf-v6-c-button--m-clicked--BorderColor: var(--pf-v6-c-button--m-tertiary--m-clicked--BorderColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-tertiary--m-clicked__icon--Color); + } + + /* Link variant */ + &.link { + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-link--PaddingInlineEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-link--PaddingInlineStart); + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-link--Color); + --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--m-link--BorderWidth); + --pf-v6-c-button--hover--BorderColor: var(--pf-v6-c-button--m-link--hover--BorderColor); + --pf-v6-c-button--hover--BorderWidth: var(--pf-v6-c-button--m-link--hover--BorderWidth); + --pf-v6-c-button--m-clicked--BorderColor: var(--pf-v6-c-button--m-link--m-clicked--BorderColor); + --pf-v6-c-button--m-clicked--BorderWidth: var(--pf-v6-c-button--m-link--m-clicked--BorderWidth); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-link--BorderColor); + --pf-v6-c-button--BorderRadius: var(--pf-v6-c-button--m-link--BorderRadius); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-link--BackgroundColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-link__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-link--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-link--hover--BackgroundColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-link--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-link--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-link--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-link--m-clicked__icon--Color); + --pf-v6-c-button--m-small--PaddingInlineEnd: var(--pf-v6-c-button--m-link--m-small--PaddingInlineEnd); + --pf-v6-c-button--m-small--PaddingInlineStart: var(--pf-v6-c-button--m-link--m-small--PaddingInlineStart); + + &.inline { + /* Override display and icon margins for span-like behavior */ + --pf-v6-c-button--m-link--m-inline--Display: var(--pf-v6-c-button--span--m-link--m-inline--Display); + --pf-v6-c-button__icon--m-start--MarginInlineEnd: var(--pf-v6-c-button--span--m-link--m-inline__icon--m-start--MarginInlineEnd); + --pf-v6-c-button__icon--m-end--MarginInlineStart: var(--pf-v6-c-button--span--m-link--m-inline__icon--m-end--MarginInlineStart); + --pf-v6-c-button--Display: var(--pf-v6-c-button--m-link--m-inline--Display); + --pf-v6-c-button--JustifyContent: var(--pf-v6-c-button--m-link--m-inline--JustifyContent); + --pf-v6-c-button--FontSize: var(--pf-v6-c-button--m-link--m-inline--FontSize); + --pf-v6-c-button--LineHeight: var(--pf-v6-c-button--m-link--m-inline--LineHeight); + --pf-v6-c-button--FontWeight: var(--pf-v6-c-button--m-link--m-inline--FontWeight); + --pf-v6-c-button--PaddingBlockStart: var(--pf-v6-c-button--m-link--m-inline--PaddingBlockStart); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-link--m-inline--PaddingInlineEnd); + --pf-v6-c-button--PaddingBlockEnd: var(--pf-v6-c-button--m-link--m-inline--PaddingBlockEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-link--m-inline--PaddingInlineStart); + --pf-v6-c-button--BackgroundColor: transparent; + --pf-v6-c-button__progress--InsetInlineStart: var(--pf-v6-c-button--m-link--m-inline__progress--InsetInlineStart); + --pf-v6-c-button--TextDecorationLine: var(--pf-v6-c-button--m-link--m-inline--TextDecorationLine); + --pf-v6-c-button--TextDecorationStyle: var(--pf-v6-c-button--m-link--m-inline--TextDecorationStyle); + --pf-v6-c-button--hover--TextDecorationLine: var(--pf-v6-c-button--m-link--m-inline--hover--TextDecorationLine); + --pf-v6-c-button--hover--TextDecorationStyle: var(--pf-v6-c-button--m-link--m-inline--hover--TextDecorationStyle); + --pf-v6-c-button--hover--BackgroundColor: transparent; + --pf-v6-c-button--m-clicked--BackgroundColor: transparent; + --pf-v6-c-button--disabled--BackgroundColor: transparent; + --pf-v6-c-button--disabled--Color: var(--pf-v6-c-button--m-link--m-inline--disabled--Color); + --pf-v6-c-button--disabled__icon--Color: var(--pf-v6-c-button--m-link--m-inline--disabled__icon--Color); + --pf-v6-c-button--m-link--Color: var(--pf-v6-c-button--m-link--m-inline--Color); + --pf-v6-c-button--m-link__icon--Color: var(--pf-v6-c-button--m-link--m-inline__icon--Color); + --pf-v6-c-button--TextDecorationColor: var(--pf-v6-c-button--m-link--m-inline--TextDecorationColor); + --pf-v6-c-button--hover--TextDecorationColor: var(--pf-v6-c-button--m-link--m-inline--hover--TextDecorationColor); + --pf-v6-c-button--m-link--hover--Color: var(--pf-v6-c-button--m-link--m-inline--hover--Color); + --pf-v6-c-button--m-link--hover__icon--Color: var(--pf-v6-c-button--m-link--m-inline--hover__icon--Color); + --pf-v6-c-button--BorderWidth: 0; + --pf-v6-c-button--hover--BorderWidth: 0; + --pf-v6-c-button--m-clicked--BorderWidth: 0; + + text-align: start; + white-space: normal; + background: transparent; + outline-offset: var(--pf-t--global--focus-ring--position--offset, 0.125rem); + } + + &.danger { + --pf-v6-c-button--m-danger--Color: var(--pf-v6-c-button--m-link--m-danger--Color); + --pf-v6-c-button--m-danger--BackgroundColor: var(--pf-v6-c-button--m-link--m-danger--BackgroundColor); + --pf-v6-c-button--m-danger__icon--Color: var(--pf-v6-c-button--m-link--m-danger__icon--Color); + --pf-v6-c-button--m-danger--hover--Color: var(--pf-v6-c-button--m-link--m-danger--hover--Color); + --pf-v6-c-button--m-danger--hover--BackgroundColor: var(--pf-v6-c-button--m-link--m-danger--hover--BackgroundColor); + --pf-v6-c-button--m-danger--hover__icon--Color: var(--pf-v6-c-button--m-link--m-danger--hover__icon--Color); + --pf-v6-c-button--m-danger--m-clicked--Color: var(--pf-v6-c-button--m-link--m-danger--m-clicked--Color); + --pf-v6-c-button--m-danger--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-link--m-danger--m-clicked--BackgroundColor); + --pf-v6-c-button--m-danger--m-clicked__icon--Color: var(--pf-v6-c-button--m-link--m-danger--m-clicked__icon--Color); + } + + &.display-lg { + --pf-v6-c-button--FontSize: var(--pf-v6-c-button--m-link--m-display-lg--FontSize); + } + } + + /* Warning variant */ + &.warning { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-warning--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-warning--BackgroundColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-warning__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-warning--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-warning--hover--BackgroundColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-warning--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-warning--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-warning--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-warning--m-clicked__icon--Color); + } + + /* Danger variant (note: also used as modifier for secondary/link) */ + &.danger { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-danger--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-danger--BackgroundColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-danger__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-danger--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-danger--hover--BackgroundColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-danger--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-danger--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-danger--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-danger--m-clicked__icon--Color); + } + + /* Control variant */ + &.control { + --pf-v6-c-button--BorderRadius: var(--pf-v6-c-button--m-control--BorderRadius); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-control--PaddingInlineStart); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-control--PaddingInlineEnd); + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-control--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-control--BackgroundColor); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-control--BorderColor); + --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--m-control--BorderWidth); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-control__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-control--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-control--hover--BackgroundColor); + --pf-v6-c-button--hover--BorderColor: var(--pf-v6-c-button--m-control--hover--BorderColor); + --pf-v6-c-button--hover--BorderWidth: var(--pf-v6-c-button--m-control--hover--BorderWidth); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-control--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-control--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-control--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked--BorderColor: var(--pf-v6-c-button--m-control--m-clicked--BorderColor); + --pf-v6-c-button--m-clicked--BorderWidth: var(--pf-v6-c-button--m-control--m-clicked--BorderWidth); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-control--m-clicked__icon--Color); + --pf-v6-c-button--m-small--PaddingInlineEnd: var(--pf-v6-c-button--m-control--m-small--PaddingInlineEnd); + --pf-v6-c-button--m-small--PaddingInlineStart: var(--pf-v6-c-button--m-control--m-small--PaddingInlineStart); + } + + /* Stateful variant */ + &.stateful { + --pf-v6-c-button--BorderRadius: var(--pf-v6-c-button--m-stateful--BorderRadius); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-stateful--PaddingInlineStart); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-stateful--PaddingInlineEnd); + --pf-v6-c-button--m-small--PaddingInlineEnd: var(--pf-v6-c-button--m-stateful--m-small--PaddingInlineEnd); + --pf-v6-c-button--m-small--PaddingInlineStart: var(--pf-v6-c-button--m-stateful--m-small--PaddingInlineStart); + } + + /* Read state */ + &.read { + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-read--BackgroundColor); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-read--BorderColor); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-read--hover--BackgroundColor); + --pf-v6-c-button--hover--BorderColor: var(--pf-v6-c-button--m-read--hover--BorderColor); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-read--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked--BorderColor: var(--pf-v6-c-button--m-read--m-clicked--BorderColor); + } + + /* Unread state */ + &.unread { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-unread--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-unread--BackgroundColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-unread__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-unread--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-unread--hover--BackgroundColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-unread--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-unread--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-unread--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-unread--m-clicked__icon--Color); + } + + /* Attention state */ + &.attention { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-attention--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-attention--BackgroundColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-attention__icon--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-attention--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-attention--hover--BackgroundColor); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-attention--hover__icon--Color); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-attention--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-attention--m-clicked--BackgroundColor); + --pf-v6-c-button--m-clicked__icon--Color: var(--pf-v6-c-button--m-attention--m-clicked__icon--Color); + } + + /* Plain variant */ + &.plain { + --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--m-plain--BorderWidth); + --pf-v6-c-button--hover--BorderColor: var(--pf-v6-c-button--m-plain--hover--BorderColor); + --pf-v6-c-button--hover--BorderWidth: var(--pf-v6-c-button--m-plain--hover--BorderWidth); + --pf-v6-c-button--m-clicked--BorderColor: var(--pf-v6-c-button--m-plain--m-clicked--BorderColor); + --pf-v6-c-button--m-clicked--BorderWidth: var(--pf-v6-c-button--m-plain--m-clicked--BorderWidth); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-plain--BorderColor); + --pf-v6-c-button--BorderRadius: var(--pf-v6-c-button--m-plain--BorderRadius); + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-plain--Color); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-plain__icon--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-plain--BackgroundColor); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-plain--PaddingInlineEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-plain--PaddingInlineStart); + --pf-v6-c-button__progress--Color: var(--pf-v6-c-button--m-in-progress--m-plain--Color); + --pf-v6-c-button--hover--Color: var(--pf-v6-c-button--m-plain--hover--Color); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-plain--hover--BackgroundColor); + --pf-v6-c-button--m-clicked--Color: var(--pf-v6-c-button--m-plain--m-clicked--Color); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-plain--m-clicked--BackgroundColor); + --pf-v6-c-button--disabled--Color: var(--pf-v6-c-button--m-plain--disabled--Color); + --pf-v6-c-button--disabled__icon--Color: var(--pf-v6-c-button--m-plain--disabled__icon--Color); + --pf-v6-c-button--disabled--BackgroundColor: var(--pf-v6-c-button--m-plain--disabled--BackgroundColor); + --pf-v6-c-button--m-small--PaddingInlineEnd: var(--pf-v6-c-button--m-plain--m-small--PaddingInlineEnd); + --pf-v6-c-button--m-small--PaddingInlineStart: var(--pf-v6-c-button--m-plain--m-small--PaddingInlineStart); + + &.no-padding { + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-plain--m-no-padding__icon--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-plain--m-no-padding--BackgroundColor); + --pf-v6-c-button--hover--BackgroundColor: var(--pf-v6-c-button--m-plain--m-no-padding--hover--BackgroundColor); + --pf-v6-c-button--m-clicked--BackgroundColor: var(--pf-v6-c-button--m-plain--m-no-padding--m-clicked--BackgroundColor); + --pf-v6-c-button--PaddingBlockStart: var(--pf-v6-c-button--m-plain--m-no-padding--PaddingBlockStart); + --pf-v6-c-button--PaddingBlockEnd: var(--pf-v6-c-button--m-plain--m-no-padding--PaddingBlockEnd); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-plain--m-no-padding--PaddingInlineEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-plain--m-no-padding--PaddingInlineStart); + --pf-v6-c-button--m-small--PaddingInlineEnd: var(--pf-v6-c-button--m-plain--m-no-padding--m-small--PaddingInlineEnd); + --pf-v6-c-button--m-small--PaddingInlineStart: var(--pf-v6-c-button--m-plain--m-no-padding--m-small--PaddingInlineStart); + --pf-v6-c-button--border--offset: var(--pf-v6-c-button--m-plain--m-no-padding--border--offset); + + min-width: var(--pf-v6-c-button--m-plain--m-no-padding--MinWidth); + background: var(--pf-v6-c-button--BackgroundColor); + } + } + + /* Block modifier */ + &.block { + --pf-v6-c-button--Display: var(--pf-v6-c-button--m-block--Display); + + width: var(--pf-v6-c-button--m-block--Width); + } + + /* Small size */ + &.small { + --pf-v6-c-button--PaddingBlockStart: var(--pf-v6-c-button--m-small--PaddingBlockStart); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-small--PaddingInlineEnd); + --pf-v6-c-button--PaddingBlockEnd: var(--pf-v6-c-button--m-small--PaddingBlockEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-small--PaddingInlineStart); + } + + /* Display lg size - padding only, font size set per-variant (e.g., .link.display-lg) */ + &.display-lg { + --pf-v6-c-button--PaddingBlockStart: var(--pf-v6-c-button--m-display-lg--PaddingBlockStart); + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-display-lg--PaddingInlineEnd); + --pf-v6-c-button--PaddingBlockEnd: var(--pf-v6-c-button--m-display-lg--PaddingBlockEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-display-lg--PaddingInlineStart); + } + + /* Favorite button */ + &.favorite .icon { + display: grid; + transition-timing-function: var(--pf-v6-c-button--m-favorite__icon--TransitionTimingFunction); + transition-duration: var(--pf-v6-c-button--m-favorite__icon--TransitionDuration); + transition-property: color; + } + + /* Favorited state */ + &.favorited { + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-favorited__icon--Color); + --pf-v6-c-button--m-plain--m-no-padding__icon--Color: var(--pf-v6-c-button--m-favorited__icon--Color); + --pf-v6-c-button--hover__icon--Color: var(--pf-v6-c-button--m-favorited--hover__icon--Color); + --pf-v6-c-button--m-plain--m-no-padding--hover__icon--Color: var(--pf-v6-c-button--m-favorited--hover__icon--Color); + --pf-v6-c-button__icon--favorite--Opacity: var(--pf-v6-c-button--m-favorited__icon--favorite--Opacity); + --pf-v6-c-button__icon--favorited--Opacity: var(--pf-v6-c-button--m-favorited__icon--favorited--Opacity); + } + + /* Favorited animation */ + &.favorited .icon { + animation-name: pf-v6-button-icon-favorited; + animation-duration: var(--pf-v6-c-button--m-favorited__icon--AnimationDuration); + animation-timing-function: var(--pf-v6-c-button--m-favorited__icon--AnimationTimingFunction); + } + + /* Settings button */ + &.settings { + --pf-v6-c-button__icon--TransitionProperty: rotate; + --pf-v6-c-button__icon--TransitionDuration: var(--pf-v6-c-button--m-settings__icon--TransitionDuration); + --pf-v6-c-button__icon--TransitionTimingFunction: var(--pf-v6-c-button--m-settings__icon--TransitionTimingFunction); + --pf-v6-c-button--hover__icon--TransitionProperty: rotate; + --pf-v6-c-button--hover__icon--TransitionDuration: var(--pf-v6-c-button--m-settings--hover__icon--TransitionDuration); + --pf-v6-c-button--hover__icon--TransitionTimingFunction: var(--pf-v6-c-button--m-settings--hover__icon--TransitionTimingFunction); + --pf-v6-c-button--hover__icon--Rotate: var(--pf-v6-c-button--m-settings--hover__icon--Rotate); + } + + /* Hamburger button */ + &.hamburger { + --pf-v6-c-button__icon--TransitionDelay: var(--pf-v6-c-button--hamburger-icon--TransitionDuration); + --pf-v6-c-button__icon--TransitionDuration: 0s; + --pf-v6-c-button__icon--TransitionProperty: scale; + --pf-v6-c-button--hover__icon--TransitionDelay: var(--pf-v6-c-button--hamburger-icon--TransitionDuration); + --pf-v6-c-button--hover__icon--TransitionDuration: 0s; + --pf-v6-c-button--hover__icon--TransitionProperty: scale; + + &.expand { + --pf-v6-c-button--hamburger-icon--top--path: var(--pf-v6-c-button--hamburger-icon--top--collapse--path); + --pf-v6-c-button--hamburger-icon--arrow--path: var(--pf-v6-c-button--hamburger-icon--arrow--collapse--path); + --pf-v6-c-button--hamburger-icon--bottom--path: var(--pf-v6-c-button--hamburger-icon--bottom--collapse--path); + --pf-v6-c-button__icon--ScaleX: var(--pf-v6-c-button--m-hamburger__icon--m-expand--ScaleX); + --pf-v6-c-button--hover__icon--ScaleX: var(--pf-v6-c-button--m-hamburger__icon--m-expand--ScaleX); + } + + &.collapse { + --pf-v6-c-button--hamburger-icon--top--path: var(--pf-v6-c-button--hamburger-icon--top--collapse--path); + --pf-v6-c-button--hamburger-icon--arrow--path: var(--pf-v6-c-button--hamburger-icon--arrow--collapse--path); + --pf-v6-c-button--hamburger-icon--bottom--path: var(--pf-v6-c-button--hamburger-icon--bottom--collapse--path); + --pf-v6-c-button__icon--ScaleX: 1; + --pf-v6-c-button--hover__icon--ScaleX: 1; + } + } + + /* Hover states */ + &:hover { + --pf-v6-c-button--Color: var(--pf-v6-c-button--hover--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--hover--BackgroundColor); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--hover--BorderColor); + --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--hover--BorderWidth); + --pf-v6-c-button--ScaleX: var(--pf-v6-c-button--hover--ScaleX); + --pf-v6-c-button--ScaleY: var(--pf-v6-c-button--hover--ScaleY); + --pf-v6-c-button--m-plain--m-no-padding__icon--Color: var(--pf-v6-c-button--m-plain--m-no-padding--hover__icon--Color); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--hover__icon--Color); + --pf-v6-c-button__icon--TransitionTimingFunction: var(--pf-v6-c-button--hover__icon--TransitionTimingFunction); + --pf-v6-c-button__icon--TransitionDuration: var(--pf-v6-c-button--hover__icon--TransitionDuration); + --pf-v6-c-button__icon--TransitionProperty: var(--pf-v6-c-button--hover__icon--TransitionProperty); + --pf-v6-c-button__icon--Rotate: var(--pf-v6-c-button--hover__icon--Rotate); + --pf-v6-c-button__icon--ScaleX: var(--pf-v6-c-button--hover__icon--ScaleX); + --pf-v6-c-button__icon--ScaleY: var(--pf-v6-c-button--hover__icon--ScaleY); + + text-decoration-line: var(--pf-v6-c-button--hover--TextDecorationLine); + text-decoration-style: var(--pf-v6-c-button--hover--TextDecorationStyle); + text-decoration-color: var(--pf-v6-c-button--hover--TextDecorationColor); + outline-offset: var(--pf-t--global--focus-ring--position--offset, 0.125rem); + } + + /* Active & clicked states */ + &:active, + &.clicked { + --pf-v6-c-button--Color: var(--pf-v6-c-button--m-clicked--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--m-clicked--BackgroundColor); + --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--m-clicked--BorderWidth); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-clicked--BorderColor); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--m-clicked__icon--Color); + } + + &:active { + background-size: 100% 100%; + transition-duration: 0s; + } + + /* Disabled states */ + &:disabled, + &.disabled { + pointer-events: none; + } + + &:disabled, + &.disabled, + &.aria-disabled { + color: var(--pf-v6-c-button--disabled--Color); + text-decoration-color: var(--pf-v6-c-button--disabled--TextDecorationColor); + background: var(--pf-v6-c-button--disabled--BackgroundColor); + + &::after { + border-color: transparent; + } + + & .icon { + color: var(--pf-v6-c-button--disabled__icon--Color); + } + } + + &.aria-disabled { + --pf-v6-c-button--m-link--m-inline--hover--TextDecorationLine: var(--pf-v6-c-button--TextDecorationLine); + --pf-v6-c-button--m-link--m-inline--hover--TextDecorationStyle: var(--pf-v6-c-button--TextDecorationStyle); + + cursor: default; + } + + /* Progress states */ + &.progress { + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-progress--PaddingInlineEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-progress--PaddingInlineStart); + } + + &.in-progress { + --pf-v6-c-button--m-link--m-inline--PaddingInlineStart: var(--pf-v6-c-button--m-link--m-inline--m-in-progress--PaddingInlineStart); + + &:not(.plain) { + --pf-v6-c-button--PaddingInlineEnd: var(--pf-v6-c-button--m-in-progress--PaddingInlineEnd); + --pf-v6-c-button--PaddingInlineStart: var(--pf-v6-c-button--m-in-progress--PaddingInlineStart); + } + + &.plain { + --pf-v6-c-button__progress--InsetInlineStart: var(--pf-v6-c-button--m-in-progress--m-plain__progress--InsetInlineStart); + --pf-v6-c-button__progress--TranslateX: var(--pf-v6-c-button--m-in-progress--m-plain__progress--TranslateX); + + & > :not(.progress) { + opacity: 0; + } + } + } +} + +.icon { + margin-inline-start: var(--pf-v6-c-button__icon--MarginInlineStart); + margin-inline-end: var(--pf-v6-c-button__icon--MarginInlineEnd); + color: var(--pf-v6-c-button__icon--Color); + transition-delay: var(--pf-v6-c-button__icon--TransitionDelay); + transition-timing-function: var(--pf-v6-c-button__icon--TransitionTimingFunction); + transition-duration: var(--pf-v6-c-button__icon--TransitionDuration); + transition-property: var(--pf-v6-c-button__icon--TransitionProperty); + rotate: var(--pf-v6-c-button__icon--Rotate); + scale: var(--pf-v6-c-button__icon--ScaleX) var(--pf-v6-c-button__icon--ScaleY); + + &.icon-start { + --pf-v6-c-button__icon--MarginInlineEnd: var(--pf-v6-c-button__icon--m-start--MarginInlineEnd); + } + + &.icon-end { + --pf-v6-c-button__icon--MarginInlineStart: var(--pf-v6-c-button__icon--m-end--MarginInlineStart); + } +} + +.icon-favorite, +.icon-favorited { + grid-area: 1 / 1 / 1 / 1; + transition-duration: var(--pf-v6-c-button__icon--favorite--TransitionDuration); + transition-property: opacity; +} + +.icon-favorite { + opacity: var(--pf-v6-c-button__icon--favorite--Opacity); +} + +.icon-favorited { + opacity: var(--pf-v6-c-button__icon--favorited--Opacity); +} + +.progress { + position: absolute; + inset-block-start: var(--pf-v6-c-button__progress--InsetBlockStart); + inset-inline-start: var(--pf-v6-c-button__progress--InsetInlineStart); + line-height: 1; + color: var(--pf-v6-c-button__progress--Color); + transform: translate(var(--pf-v6-c-button__progress--TranslateX), var(--pf-v6-c-button__progress--TranslateY)); +} + +.text { + text-decoration: inherit; +} + +.count { + display: inline-flex; + align-items: center; +} + +.hamburger-icon { + path { + fill: none; + stroke: currentcolor; + stroke-linecap: round; + stroke-linejoin: round; + transition: d var(--pf-v6-c-button--hamburger-icon--TransitionDuration) var(--pf-v6-c-button--hamburger-icon--TransitionTimingFunction); + } +} + +.hamburger-icon-top { + d: var(--pf-v6-c-button--hamburger-icon--top--path); +} + +.hamburger-icon-middle { + d: var(--pf-v6-c-button--hamburger-icon--middle--path); +} + +.hamburger-icon-arrow { + d: var(--pf-v6-c-button--hamburger-icon--arrow--path); +} + +.hamburger-icon-bottom { + d: var(--pf-v6-c-button--hamburger-icon--bottom--path); +} + +@keyframes pf-v6-button-icon-favorited { + 50% { + scale: 1.5; + } +} + +/* Slotted badge styles - apply CSS variables to light DOM badges */ +#button.primary ::slotted(pf-v6-badge:not([state="read"])) { + --pf-v6-c-badge--BorderColor: var(--pf-v6-c-button--m-primary__c-badge--BorderColor); +} + +:host(:focus) #button, +:host(:focus-visible) #button { + --pf-v6-c-button--Color: var(--pf-v6-c-button--hover--Color); + --pf-v6-c-button--BackgroundColor: var(--pf-v6-c-button--hover--BackgroundColor); + --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--hover--BorderColor); + --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--hover--BorderWidth); + --pf-v6-c-button--ScaleX: var(--pf-v6-c-button--hover--ScaleX); + --pf-v6-c-button--ScaleY: var(--pf-v6-c-button--hover--ScaleY); + --pf-v6-c-button--m-plain--m-no-padding__icon--Color: var(--pf-v6-c-button--m-plain--m-no-padding--hover__icon--Color); + --pf-v6-c-button__icon--Color: var(--pf-v6-c-button--hover__icon--Color); + --pf-v6-c-button__icon--TransitionTimingFunction: var(--pf-v6-c-button--hover__icon--TransitionTimingFunction); + --pf-v6-c-button__icon--TransitionDuration: var(--pf-v6-c-button--hover__icon--TransitionDuration); + --pf-v6-c-button__icon--TransitionProperty: var(--pf-v6-c-button--hover__icon--TransitionProperty); + --pf-v6-c-button__icon--Rotate: var(--pf-v6-c-button--hover__icon--Rotate); + --pf-v6-c-button__icon--ScaleX: var(--pf-v6-c-button--hover__icon--ScaleX); + --pf-v6-c-button__icon--ScaleY: var(--pf-v6-c-button--hover__icon--ScaleY); + + text-decoration-line: var(--pf-v6-c-button--hover--TextDecorationLine); + text-decoration-style: var(--pf-v6-c-button--hover--TextDecorationStyle); + text-decoration-color: var(--pf-v6-c-button--hover--TextDecorationColor); + outline-offset: var(--pf-t--global--focus-ring--position--offset, 0.125rem); +} + +:host([disabled]), +:host([disabled-focusable]) { + cursor: not-allowed; +} + +:host([disabled]) { + pointer-events: none; +} + +:host([hidden]), +[hidden] { + display: none !important; +} + +:host([block]) { + display: flex; + width: 100%; +} + +:host([inline]) { + display: inline; +} diff --git a/elements/pf-v6-button/pf-v6-button.ts b/elements/pf-v6-button/pf-v6-button.ts new file mode 100644 index 0000000000..8ccbca9112 --- /dev/null +++ b/elements/pf-v6-button/pf-v6-button.ts @@ -0,0 +1,520 @@ +import { + LitElement, + html, + isServer, + type PropertyValues, + type TemplateResult, +} 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 { ifDefined } from 'lit/directives/if-defined.js'; + +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; +import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; + +import '@patternfly/elements/pf-v5-icon/pf-v5-icon.js'; +import '@patternfly/elements/pf-v6-spinner/pf-v6-spinner.js'; + +import styles from './pf-v6-button.css'; + +export type ButtonVariant = + | 'primary' + | 'secondary' + | 'tertiary' + | 'danger' + | 'warning' + | 'link' + | 'plain' + | 'control' + | 'stateful'; + +export type ButtonSize = 'sm' | 'lg'; + +export type ButtonState = 'read' | 'unread' | 'attention'; + +export type ButtonType = 'button' | 'submit' | 'reset'; + +export type ButtonIconPosition = 'start' | 'end'; + +export type ButtonHamburgerVariant = 'expand' | 'collapse'; + +/** + * A **button** communicates and triggers user actions when clicked or selected. + * Use buttons for actions such as submitting a form, canceling a process, or + * navigating to another page. Icon-only buttons MUST provide an `accessible-label`. + * + * @summary Triggers an action when activated + * + * @slot - Button label text + * @slot icon - Icon displayed at the start or end of the button + * @slot count - Count badge displayed after the label + * + * @cssprop {} --pf-v6-c-button--BackgroundColor - Button background color + * @cssprop {} --pf-v6-c-button--Color - Button text color + * @cssprop {} --pf-v6-c-button--PaddingInlineStart - Inline-start padding + * @cssprop {} --pf-v6-c-button--PaddingInlineEnd - Inline-end padding + * @cssprop {} --pf-v6-c-button--FontSize - Button font size + * @cssprop {} --pf-v6-c-button--BorderRadius - Button border radius + * + * @csspart icon - Container for the icon slot and built-in icons + * @csspart text - Container for the default slot label + * @csspart count - Container for the count slot + * @csspart progress - Container for the loading spinner + */ +@customElement('pf-v6-button') +export class PfV6Button extends LitElement { + static readonly formAssociated = true; + + static readonly styles: CSSStyleSheet[] = [styles]; + + /** + * Visual style of the button. + * - Primary: most important call to action; limit to one per page + * - Secondary: general actions that need less emphasis + * - Tertiary: classic button format with still less emphasis + * - Danger: potentially destructive or hard-to-undo actions + * - Warning: important setting changes that are not destructive + * - Link: low-emphasis actions or navigation + * - Plain: icon-labeled actions with no chrome + * - Control: for pairing with other controls in an input group + * - Stateful: notification state (`read`, `unread`, `attention`) + */ + @property({ reflect: true }) variant: ButtonVariant = 'primary'; + + /** Size of the button. Omit for default size. */ + @property({ reflect: true }) size?: ButtonSize; + + /** Native form button type */ + @property({ reflect: true }) type?: ButtonType; + + /** State for the stateful variant. Defaults to unread when variant is stateful. */ + @property({ reflect: true }) state?: ButtonState; + + /** Form value for the button */ + @property() value?: string; + + /** Form element name for the button */ + @property() name?: string; + + /** Accessible name when the button has no visible text */ + @property({ attribute: 'accessible-label' }) accessibleLabel?: string; + + /** Disables the button and removes it from the tab order */ + @property({ reflect: true, type: Boolean }) disabled = false; + + /** + * Disables activation while keeping the button focusable. + * Use when a disabled button still needs a tooltip or other focus treatment. + */ + @property({ reflect: true, type: Boolean, attribute: 'disabled-focusable' }) + disabledFocusable = false; + + /** Shows a progress spinner and progress styling */ + @property({ reflect: true, type: Boolean }) loading = false; + + /** Accessible label for the loading spinner */ + @property({ attribute: 'loading-label' }) loadingLabel = 'Loading'; + + /** Spans the full width of the parent */ + @property({ reflect: true, type: Boolean }) block = false; + + /** Renders a link variant inline with surrounding text */ + @property({ reflect: true, type: Boolean }) inline = false; + + /** Applies danger styling to secondary or link variants */ + @property({ reflect: true, type: Boolean }) danger = false; + + /** Applies clicked styling */ + @property({ reflect: true, type: Boolean }) clicked = false; + + /** Renders as a favorite toggle; overrides the icon slot */ + @property({ reflect: true, type: Boolean }) favorite = false; + + /** Whether the favorite toggle is currently favorited */ + @property({ reflect: true, type: Boolean }) favorited = false; + + /** Renders as a settings button; overrides the icon slot */ + @property({ reflect: true, type: Boolean }) settings = false; + + /** Renders as a hamburger button; overrides the icon slot */ + @property({ reflect: true, type: Boolean }) hamburger = false; + + /** Required when `hamburger` is set; reflects expansion of controlled content */ + @property({ reflect: true, type: Boolean }) expanded?: boolean; + + /** Animates the hamburger icon toward expand or collapse */ + @property({ reflect: true, attribute: 'hamburger-variant' }) + hamburgerVariant?: ButtonHamburgerVariant; + + /** Removes padding from a plain variant for inline icon placement */ + @property({ reflect: true, type: Boolean, attribute: 'no-padding' }) + noPadding = false; + + /** Icon position relative to the label. Defaults to start. */ + @property({ reflect: true, attribute: 'icon-position' }) + iconPosition?: ButtonIconPosition; + + /** When set with `variant="link"`, renders as an anchor */ + @property({ reflect: true }) href?: string; + + /** Target for the link when `href` is set */ + @property({ reflect: true }) target?: string; + + /** Shorthand icon name for the icon slot */ + @property() icon?: string; + + /** Icon set for the `icon` property */ + @property({ attribute: 'icon-set' }) iconSet?: string; + + #internals = InternalsController.of(this); + + #slots = new SlotController(this, 'icon', 'count', null); + + get #disabled() { + return this.disabled || this.#internals.formDisabled; + } + + get #operable() { + return !(this.#disabled || this.disabledFocusable); + } + + override connectedCallback(): void { + super.connectedCallback(); + if (!isServer) { + this.addEventListener('click', this.#onClick); + this.addEventListener('keydown', this.#onKeydown); + } + } + + override disconnectedCallback(): void { + super.disconnectedCallback(); + this.removeEventListener('click', this.#onClick); + this.removeEventListener('keydown', this.#onKeydown); + } + + protected override willUpdate(): void { + const isLink = this.variant === 'link' && !!this.href; + this.#internals.ariaLabel = this.accessibleLabel || null; + this.#internals.ariaDisabled = + this.#disabled || this.disabledFocusable ? 'true' : null; + this.#internals.ariaExpanded = + this.expanded === undefined ? null : String(this.expanded); + this.#internals.setFormValue( + this.name == null ? null : (this.value ?? ''), + ); + + if (isLink) { + this.removeAttribute('tabindex'); + this.#internals.role = 'none'; + } else { + this.#internals.role = 'button'; + if (this.#disabled) { + this.removeAttribute('tabindex'); + } else { + this.tabIndex = 0; + } + } + } + + protected override updated(changed: PropertyValues): void { + if (changed.has('hamburger') || changed.has('expanded')) { + if (this.hamburger && this.expanded === undefined) { + // eslint-disable-next-line no-console + console.error( + 'pf-v6-button: when hamburger is set, expanded must also be set. ' + + 'A hamburger button is expected to control expansion of other content.' + ); + } + } + + if ( + changed.has('settings') + || changed.has('hamburger') + || changed.has('favorite') + ) { + const iconOnly = this.settings || this.hamburger || this.favorite; + if (iconOnly && !this.accessibleLabel && !this.#hasTextContent()) { + // eslint-disable-next-line no-console + console.error( + 'pf-v6-button: provide visible text or accessible-label for settings, ' + + 'hamburger, and favorite buttons.' + ); + } + } + + if (changed.has('disabled')) { + this.#syncCountBadgeDisabled(); + } + } + + override render(): TemplateResult<1> { + const disabled = this.#disabled; + const hasIcon = this.#hasIcon(); + const hasCount = this.#slots.hasSlotted('count'); + const hasText = this.#hasTextContent(); + const iconAtEnd = this.iconPosition === 'end'; + const showDanger = + this.variant === 'danger' + || (this.danger + && (this.variant === 'secondary' || this.variant === 'link')); + + const classes = { + [this.variant]: true, + 'settings': this.settings, + 'hamburger': this.hamburger, + 'expand': this.hamburger && this.hamburgerVariant === 'expand', + 'collapse': this.hamburger && this.hamburgerVariant === 'collapse', + 'block': this.block, + disabled, + 'aria-disabled': this.disabledFocusable, + 'clicked': this.clicked, + 'inline': this.inline && this.variant === 'link', + 'favorite': this.favorite, + 'favorited': this.favorite && this.favorited, + 'danger': showDanger, + 'progress': this.loading && this.variant !== 'plain', + 'in-progress': this.loading, + 'no-padding': this.noPadding && this.variant === 'plain', + 'small': this.size === 'sm', + 'display-lg': this.size === 'lg', + ...(this.variant === 'stateful' ? + { [this.state ?? 'unread']: true } + : {}), + hasIcon, + 'loading': this.loading, + 'anchor': !!(this.variant === 'link' && this.href), + }; + + const icon = this.#renderIcon(hasText); + const text = hasText ? + html` + + + ` + : html``; + + const content = html` + ${this.loading ? + html` + + + + + ` + : null} + ${iconAtEnd ? html`${text}${icon}` : html`${icon}${text}`} + + + + + + `; + + if (this.variant === 'link' && this.href) { + return html` + ${content} + `; + } + + return html` +
${content}
+ `; + } + + async formDisabledCallback(): Promise { + await this.updateComplete; + this.requestUpdate(); + } + + #hasIcon(): boolean { + return ( + this.settings + || this.hamburger + || this.favorite + || this.loading + || !!this.icon + || this.#slots.hasSlotted('icon') + ); + } + + #hasTextContent(): boolean { + return this.#slots.hasSlotted(); + } + + #syncCountBadgeDisabled(): void { + if (isServer) { + return; + } + for (const badge of this.querySelectorAll('pf-v6-badge[slot="count"]')) { + if (this.disabled) { + badge.setAttribute('disabled', ''); + } else { + badge.removeAttribute('disabled'); + } + } + } + + #renderIcon(hasText: boolean): TemplateResult { + const hasIcon = this.#hasIcon(); + let iconContent: TemplateResult; + + if (this.favorite) { + iconContent = this.#renderFavoriteIcons(); + } else if (this.settings) { + iconContent = this.#renderSettingsIcon(); + } else if (this.hamburger) { + iconContent = this.#renderHamburgerIcon(); + } else { + // Always render the slot so SlotController can detect light-DOM icons. + iconContent = html` + + + + `; + } + + return html` + + ${iconContent} + `; + } + + #renderHamburgerIcon(): TemplateResult { + return html` + + `; + } + + #renderSettingsIcon(): TemplateResult { + return html` + + `; + } + + #renderFavoriteIcons(): TemplateResult { + return html` + + + + + + + `; + } + + #onClick = (event: Event): void => { + if (!this.#operable) { + event.preventDefault(); + event.stopImmediatePropagation(); + return; + } + if (this.variant === 'link' && this.href) { + return; + } + switch (this.type) { + case 'reset': + this.#internals.reset(); + break; + case 'button': + break; + default: + this.#internals.submit(); + } + }; + + #onKeydown = (event: KeyboardEvent): void => { + if (this.variant === 'link' && this.href) { + return; + } + switch (event.key) { + case ' ': + event.preventDefault(); + event.stopPropagation(); + this.dispatchEvent( + new MouseEvent('click', { + bubbles: true, + cancelable: true, + view: window, + }) + ); + break; + case 'Enter': + this.dispatchEvent( + new MouseEvent('click', { + bubbles: true, + cancelable: true, + view: window, + }) + ); + break; + } + }; +} + +declare global { + interface HTMLElementTagNameMap { + 'pf-v6-button': PfV6Button; + } +} diff --git a/elements/pf-v6-button/test/pf-v6-button.spec.ts b/elements/pf-v6-button/test/pf-v6-button.spec.ts new file mode 100644 index 0000000000..2de22b66bb --- /dev/null +++ b/elements/pf-v6-button/test/pf-v6-button.spec.ts @@ -0,0 +1,308 @@ +import type { A11yTreeSnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; +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 { sendKeys } from '@web/test-runner-commands'; +import { clickElementAtCenter } from '@patternfly/pfe-tools/test/utils.js'; + +import { PfV6Button } from '@patternfly/elements/pf-v6-button/pf-v6-button.js'; + +function press(key: string) { + return async function() { + await sendKeys({ press: key }); + }; +} + +describe('', function() { + it('imperatively instantiates', function() { + expect(document.createElement('pf-v6-button')).to.be.an.instanceof(PfV6Button); + }); + + it('should upgrade', async function() { + const el = await createFixture(html`Button`); + expect(el, 'pf-v6-button should be an instance of PfV6Button') + .to.be.an.instanceof(customElements.get('pf-v6-button')) + .and + .to.be.an.instanceof(PfV6Button); + }); + + describe('simply instantiating', function() { + let element: PfV6Button; + let snapshot: A11yTreeSnapshot; + + beforeEach(async function() { + element = await createFixture(html` + Save + `); + snapshot = await a11ySnapshot({ selector: 'pf-v6-button' }); + }); + + it('has button role', function() { + expect(snapshot.role).to.equal('button'); + }); + + it('exposes its label', function() { + expect(snapshot.name).to.equal('Save'); + }); + + it('defaults to the primary variant', function() { + expect(element.variant).to.equal('primary'); + }); + }); + + describe('with accessible-label', function() { + let snapshot: A11yTreeSnapshot; + + beforeEach(async function() { + await createFixture(html` + + `); + snapshot = await a11ySnapshot({ selector: 'pf-v6-button' }); + }); + + it('uses accessible-label as the accessible name', function() { + expect(snapshot.name).to.equal('Close'); + }); + }); + + describe('disabled', function() { + let element: PfV6Button; + let clicks: number; + let snapshot: A11yTreeSnapshot; + + beforeEach(async function() { + clicks = 0; + element = await createFixture(html` + Disabled + `); + element.addEventListener('click', function() { + clicks += 1; + }); + snapshot = await a11ySnapshot({ selector: 'pf-v6-button' }); + }); + + it('matches :disabled', function() { + expect(element.matches(':disabled')).to.be.true; + }); + + it('reflects disabled in the accessibility tree', function() { + expect(snapshot.disabled).to.be.true; + }); + + it('does not fire click handlers when activated', async function() { + element.focus(); + await sendKeys({ press: 'Enter' }); + expect(clicks).to.equal(0); + }); + }); + + describe('disabled-focusable', function() { + let element: PfV6Button; + let clicks: number; + let snapshot: A11yTreeSnapshot; + + beforeEach(async function() { + clicks = 0; + element = await createFixture(html` + Disabled focusable + `); + element.addEventListener('click', function() { + clicks += 1; + }); + snapshot = await a11ySnapshot({ selector: 'pf-v6-button' }); + }); + + it('remains in the accessibility tree as a button', function() { + expect(snapshot.role).to.equal('button'); + }); + + it('does not fire click handlers when activated', async function() { + element.focus(); + await sendKeys({ press: 'Enter' }); + expect(clicks).to.equal(0); + }); + }); + + describe('variants', function() { + for (const variant of [ + 'primary', + 'secondary', + 'tertiary', + 'danger', + 'warning', + 'link', + 'plain', + 'control', + 'stateful', + ] as const) { + it(`accepts the ${variant} variant`, async function() { + const element = await createFixture(html` + + `); + expect(element.variant).to.equal(variant); + }); + } + }); + + describe('loading', function() { + let element: PfV6Button; + + beforeEach(async function() { + element = await createFixture(html` + Loading + `); + }); + + it('reflects the loading attribute', function() { + expect(element.hasAttribute('loading')).to.be.true; + }); + + it('exposes loading-label', function() { + expect(element.loadingLabel).to.equal('Saving'); + }); + }); + + describe('link with href', function() { + let element: PfV6Button; + + beforeEach(async function() { + element = await createFixture(html` + Docs + `); + }); + + it('exposes href for link buttons', function() { + expect(element.href).to.equal('#destination'); + expect(element.variant).to.equal('link'); + }); + }); + + describe('form association', function() { + let form: HTMLFormElement; + let element: PfV6Button; + let submitData: FormData | null; + + beforeEach(async function() { + submitData = null; + form = await createFixture(html` +
+ Save +
+ `); + element = form.querySelector('pf-v6-button')!; + form.addEventListener('submit', function(event) { + event.preventDefault(); + submitData = new FormData(form); + }); + await element.updateComplete; + }); + + it('submits name and value', async function() { + await clickElementAtCenter(element); + expect(submitData).to.be.ok; + expect(submitData!.get('save')).to.equal('yes'); + }); + }); + + describe('in a fieldset', function() { + let element: PfV6Button; + let fieldset: HTMLFieldSetElement; + let form: HTMLFormElement; + let submitEvent: SubmitEvent; + + beforeEach(async function() { + form = await createFixture(html` +
+ +
+ OK +
+ +
+ `); + fieldset = form.querySelector('fieldset')!; + element = form.querySelector('pf-v6-button')!; + form.querySelector('input')?.focus(); + form.addEventListener('submit', function(event) { + event.preventDefault(); + submitEvent = event; + }); + await element.updateComplete; + }); + + afterEach(function() { + // @ts-expect-error: resetting fixture + submitEvent = undefined; + }); + + describe('clicking the button', function() { + beforeEach(async function() { + await clickElementAtCenter(element); + }); + it('submits the form', function() { + expect(submitEvent).to.be.ok; + }); + }); + + describe('tabbing through', function() { + beforeEach(press('Tab')); + it('does focus the button', function() { + expect(document.activeElement).to.be.an.instanceof(PfV6Button); + }); + + describe('pressing Space', function() { + beforeEach(press(' ')); + it('submits the form', function() { + expect(submitEvent).to.be.ok; + }); + }); + + describe('pressing Enter', function() { + beforeEach(press('Enter')); + it('submits the form', function() { + expect(submitEvent).to.be.ok; + }); + }); + }); + + describe('disabling the fieldset', function() { + beforeEach(async function() { + fieldset.disabled = true; + await element.updateComplete; + }); + it('disables the button', function() { + expect(element.matches(':disabled'), 'matches :disabled').to.be.true; + }); + describe('tabbing through', function() { + beforeEach(press('Tab')); + it('does not focus the button', function() { + expect(document.activeElement).to.not.be.an.instanceof(PfV6Button); + }); + }); + describe('then disabling the button', function() { + beforeEach(async function() { + element.disabled = true; + await element.updateComplete; + }); + describe('then enabling the button', function() { + beforeEach(async function() { + element.disabled = false; + await element.updateComplete; + }); + describe('then enabling the fieldset', function() { + beforeEach(async function() { + fieldset.disabled = false; + await element.updateComplete; + }); + describe('tabbing through', function() { + beforeEach(press('Tab')); + it('does focus the button', function() { + expect(document.activeElement).to.be.an.instanceof(PfV6Button); + }); + }); + }); + }); + }); + }); + }); +}); From f21ae790dd30377e9854c3ef126baac346ee4136 Mon Sep 17 00:00:00 2001 From: ArathyKumar Date: Wed, 5 Aug 2026 21:23:18 +0530 Subject: [PATCH 02/31] chore(button): added react variants --- .../controllers/internals-controller.ts | 33 +++- elements/pf-v6-button/README.md | 49 +++-- .../demo/css-custom-properties.html | 39 ++++ elements/pf-v6-button/demo/progress.html | 34 ++-- elements/pf-v6-button/demo/types.html | 10 +- elements/pf-v6-button/pf-v6-button.ts | 101 ++++++++-- .../pf-v6-button/test/pf-v6-button.spec.ts | 185 +++++++++++++++--- 7 files changed, 373 insertions(+), 78 deletions(-) create mode 100644 elements/pf-v6-button/demo/css-custom-properties.html diff --git a/core/pfe-core/controllers/internals-controller.ts b/core/pfe-core/controllers/internals-controller.ts index 90eddcb560..d5923deeeb 100644 --- a/core/pfe-core/controllers/internals-controller.ts +++ b/core/pfe-core/controllers/internals-controller.ts @@ -74,14 +74,20 @@ type InternalsHost = ReactiveControllerHost & HTMLElement; export class InternalsController implements ReactiveController, ARIAMixin { private static instances = new WeakMap(); - declare readonly form: ElementInternals['form']; - declare readonly shadowRoot: ElementInternals['shadowRoot']; - // https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/states declare readonly states: unknown; declare readonly willValidate: ElementInternals['willValidate']; declare readonly validationMessage: ElementInternals['validationMessage']; + /** Form associated with the host via ElementInternals (FACE). */ + get form(): ElementInternals['form'] { + return this.attachOrRetrieveInternals().form; + } + + get shadowRoot(): ElementInternals['shadowRoot'] { + return this.attachOrRetrieveInternals().shadowRoot; + } + public static getLabels(host: InternalsHost): Element[] { return Array.from(this.instances.get(host)?.internals.labels ?? []) as Element[]; } @@ -321,8 +327,25 @@ export class InternalsController implements ReactiveController, ARIAMixin { return this.internals.reportValidity(...args); } - submit(): void { - this.internals.form?.requestSubmit(); + /** + * Submit the associated form. + * @param submitter - optional submitter; ignored when the UA rejects non-button submitters + * (common for form-associated custom elements today) + */ + submit(submitter?: HTMLElement): void { + const { form } = this.internals; + if (!form) { + return; + } + if (submitter) { + try { + form.requestSubmit(submitter); + return; + } catch { + // FACE hosts are not yet accepted as submitters in all engines. + } + } + form.requestSubmit(); } reset(): void { diff --git a/elements/pf-v6-button/README.md b/elements/pf-v6-button/README.md index a643b0bb81..8ad0a84f7d 100644 --- a/elements/pf-v6-button/README.md +++ b/elements/pf-v6-button/README.md @@ -28,6 +28,28 @@ A button communicates and triggers user actions when clicked or selected. ``` +### Theming + +Override the same `--pf-v6-c-button--*` tokens as PatternFly CSS / React. For variant colors, prefer the `m-{variant}` tokens (variants assign those onto the shared surface tokens): + +```css +pf-v6-button { + --pf-v6-c-button--BorderRadius: 0.25rem; + --pf-v6-c-button--m-primary--BackgroundColor: navy; + --pf-v6-c-button--m-primary--Color: white; +} +``` + +Style shadow internals with parts: + +```css +pf-v6-button::part(button) { /* surface */ } +pf-v6-button::part(icon) { /* icon wrapper */ } +pf-v6-button::part(text) { /* label wrapper */ } +pf-v6-button::part(count) { /* count badge wrapper */ } +pf-v6-button::part(progress) { /* spinner wrapper */ } +``` + ## Divergences from React `Button` ### Not implemented @@ -35,12 +57,14 @@ A button communicates and triggers user actions when clicked or selected. | React prop | Notes | | ------------------------------------------ | --------------------------------------------------------------------------------------------------------- | | `component` | Web components cannot change their host tag. Use `href` for anchors, or wrap the button in semantic HTML. | -| `className` | Not needed with shadow DOM. | +| `className` | Not needed with shadow DOM; style the host or `::part(button)`. | | `ouiaId` / `ouiaSafe` | OUIA helpers are React-specific. | | `inoperableEvents` | Aria-disabled blocks `click` activation; custom event lists are not exposed. | | `spinnerAriaLabelledBy` | Use `loading-label` or the spinner's `accessible-label`. | | `isCircle` / `isDocked` / `isTextExpanded` | Beta React APIs; omitted until design stabilizes. | | `innerRef` | Use a normal element reference to the host. | +| `formaction` / `formenctype` / etc. | Not reliably supported on FACE submitters; use form-level attributes or a native submit control. | +| `SubmitEvent.submitter` | Engines may reject FACE hosts as `requestSubmit(submitter)`; form still submits and `name`/`value` participate via `setFormValue`. | ### Changed API @@ -48,28 +72,31 @@ A button communicates and triggers user actions when clicked or selected. | ------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------ | | `isDisabled` | `disabled` | Dropped `is-` prefix. | | `isAriaDisabled` | `disabled-focusable` | Keeps the button focusable while blocking activation; sets `aria-disabled` via ElementInternals. | -| `isLoading` | `loading` | Dropped `is-` prefix. | +| `isLoading` | `loading` | Tri-state preserved: omit / `null` (off), `loading` / `true` (spinner), `loading="false"` (reserved progress padding). | | `isBlock` | `block` | Dropped `is-` prefix. | | `isInline` | `inline` | Dropped `is-` prefix. | | `isDanger` | `danger` | Dropped `is-` prefix. Applies to `secondary` and `link` variants. | -| `isClicked` | `clicked` | Dropped `is-` prefix. | +| `isClicked` | `clicked` | Dropped `is-` prefix. (React renamed `isActive` → `isClicked`.) | | `isFavorite` / `isFavorited` | `favorite` / `favorited` | Dropped `is-` prefix. | | `isSettings` | `settings` | Dropped `is-` prefix. | | `isHamburger` / `isExpanded` | `hamburger` / `expanded` | Dropped `is-` prefix. | | `hasNoPadding` | `no-padding` | Dash-case boolean attribute. | | `aria-label` | `accessible-label` | Custom attribute; applied via ElementInternals. | | `icon` | `slot="icon"` or `icon` / `icon-set` | Prefer slotted icons. Optional shorthand renders ``. | -| `countOptions` | `slot="count"` | Slot a `` instead of a options object. | +| `iconPosition` | `icon-position` | `start` / `end`; accepts deprecated `left` / `right` aliases. | +| `countOptions` | `slot="count"` | Slot a `` instead of an options object. | | `spinnerAriaLabel` / `spinnerAriaValueText` | `loading-label` | Reactive attribute/property for the spinner accessible name. | | `size="default"` | omit `size` | Default size is the absence of the attribute. | | `component="a"` + `href` | `href` / `target` | Renders an inner anchor when `variant="link"` and `href` are set. | +| `type` default | omit / unset | Same as React: no form action until `type="submit"` or `type="reset"`. | ### Added -| Web component API | Notes | -| --------------------------------------------- | -------------------------------------------------------------------------------------- | -| Form association (`formAssociated`) | Host participates in forms like a native button; supports `type`, `name`, and `value`. | -| `href` / `target` | Progressive-enhancement link rendering for `variant="link"`. | -| `slot="icon"` / `slot="count"` | Composition slots for icons and count badges. | -| `icon` / `icon-set` | Optional shorthand that renders `` in the icon slot. | -| CSS parts `icon`, `text`, `count`, `progress` | Limited styling hooks for shadow internals. | +| Web component API | Notes | +| ------------------------------------------------------ | -------------------------------------------------------------------------------------- | +| Form association (`formAssociated`) | Host participates in forms like a native button; supports `type`, `name`, and `value`. | +| `href` / `target` | Progressive-enhancement link rendering for `variant="link"`. | +| `slot="icon"` / `slot="count"` | Composition slots for icons and count badges. | +| `icon` / `icon-set` | Optional shorthand that renders `` in the icon slot. | +| CSS parts `button`, `icon`, `text`, `count`, `progress` | Styling hooks for shadow internals. | +| `--pf-v6-c-button--*` custom properties | Same component tokens as PatternFly CSS / React styles. | diff --git a/elements/pf-v6-button/demo/css-custom-properties.html b/elements/pf-v6-button/demo/css-custom-properties.html new file mode 100644 index 0000000000..42810360a9 --- /dev/null +++ b/elements/pf-v6-button/demo/css-custom-properties.html @@ -0,0 +1,39 @@ +--- +name: CSS custom properties +description: Theme the button with the same --pf-v6-c-button--* custom properties as PatternFly CSS, and target shadow parts. +--- + +
+ Themed primary + Themed secondary +
+ + + + diff --git a/elements/pf-v6-button/demo/progress.html b/elements/pf-v6-button/demo/progress.html index 7866a9a922..3312e26b05 100644 --- a/elements/pf-v6-button/demo/progress.html +++ b/elements/pf-v6-button/demo/progress.html @@ -1,12 +1,12 @@ --- name: Progress indicators -description: Set loading to show a progress spinner after the user starts an action. +description: Set loading to show a progress spinner after the user starts an action. Use loading="false" to reserve progress padding without a spinner. ---
- Click to start loading - Click to start loadingClick to stop loading + Click to stop loading + Pause loading logs
diff --git a/elements/pf-v6-button/demo/types.html b/elements/pf-v6-button/demo/types.html index 79aea764a0..31deadf578 100644 --- a/elements/pf-v6-button/demo/types.html +++ b/elements/pf-v6-button/demo/types.html @@ -1,6 +1,6 @@ --- name: Button types -description: Use type to control form behavior. Omit type or use submit to submit, reset to reset, and button for a non-submitting control. +description: Use type to control form behavior. Default is button (no form action). Use submit or reset for form actions. ---
@@ -9,7 +9,7 @@
- Submit + Submit Reset Button
@@ -19,10 +19,10 @@ diff --git a/elements/pf-v5-button/demo/form-control.html b/elements/pf-v5-button/demo/form-control.html deleted file mode 100644 index ff1a09f053..0000000000 --- a/elements/pf-v5-button/demo/form-control.html +++ /dev/null @@ -1,58 +0,0 @@ - -

Nothing disabled

-
- Ok -
- - -
- -
-

fieldset disabled

-
- Ok -
- - -
- -
-

Button disabled

-
- Ok -
- - -
- -
-

Both disabled

-
- Ok -
- - -
- - - - diff --git a/elements/pf-v5-button/demo/index.html b/elements/pf-v5-button/demo/index.html deleted file mode 100644 index f80de9ecef..0000000000 --- a/elements/pf-v5-button/demo/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - Primary - - - - - - diff --git a/elements/pf-v5-button/demo/sizes.html b/elements/pf-v5-button/demo/sizes.html deleted file mode 100644 index 15e068d488..0000000000 --- a/elements/pf-v5-button/demo/sizes.html +++ /dev/null @@ -1,27 +0,0 @@ -
- Primary small - Secondary small - Danger secondary small - Tertiary small - Danger small - Warning small - - Primary large - Secondary large - Danger secondary large - Tertiary large - Danger large - Warning large -
- - - diff --git a/elements/pf-v5-button/demo/stateful.html b/elements/pf-v5-button/demo/stateful.html deleted file mode 100644 index c4d44c4683..0000000000 --- a/elements/pf-v5-button/demo/stateful.html +++ /dev/null @@ -1,50 +0,0 @@ -
-

Stateful buttons have a loading indicator

- Resume loading logs - - Click to start loading - - - - - -
- - - - diff --git a/elements/pf-v5-button/demo/user-role.html b/elements/pf-v5-button/demo/user-role.html deleted file mode 100644 index bc0d40bc20..0000000000 --- a/elements/pf-v5-button/demo/user-role.html +++ /dev/null @@ -1,70 +0,0 @@ - -

Button Role Example

-
- HTML - CSS - JS -
- -
- HTML is the foundational language of the web. -
- - - - - - - Note: the purpose of this demo is to show how custom - roles can be applied to <pf-v5-button>. - However, we recommend always using <pf-v5-tabs>, and avoiding custom - implementations of existing design system patterns - -
- - - - diff --git a/elements/pf-v5-button/demo/variants.html b/elements/pf-v5-button/demo/variants.html deleted file mode 100644 index 51ccccf3ed..0000000000 --- a/elements/pf-v5-button/demo/variants.html +++ /dev/null @@ -1,99 +0,0 @@ -
-

PatternFly supports several button styling variants to be used in different scenarios as needed. The following button variants can be assigned using the variant property.

- - Primary - Secondary - Danger Secondary - Tertiary - Danger - Warning - -

Disabled

- Primary - Secondary - Danger Secondary - Tertiary - Danger - Warning -
- -
-

Link variant

- Link - Link - Inline Link - Danger Link - -

Disabled

- Link - Link - Inline Link - Danger Link -
- -
-

Plain button

- - - - - - -

Disabled

- - - - - -
- -
-

Control variant

- Control - - - - - - -

Disabled

- Control - - - - - - -

- Note: when using <pf-v5-button> as an icon-button, - <pf-v5-button> must have the label attribute. -

-
- - - - diff --git a/elements/pf-v5-button/docs/CHANGELOG.old.md b/elements/pf-v5-button/docs/CHANGELOG.old.md deleted file mode 100644 index 458458e91f..0000000000 --- a/elements/pf-v5-button/docs/CHANGELOG.old.md +++ /dev/null @@ -1,148 +0,0 @@ -# @patternfly/pfe-button - -## 2.0.0-next.9 - -### Patch Changes - -- 0fe6c52db: Allowed button to be disabled by its form without sprouting a disabled attr -- b841afe40: ``: fixed loading state -- bbcfb687f: fixed icon layouts -- Updated dependencies [b841afe40] -- Updated dependencies [0fe6c52db] -- Updated dependencies [0fe6c52db] - - @patternfly/pfe-core@2.0.0-next.13 - -## 2.0.0-next.8 - -### Major Changes - -- 6b6e2617: Makes `` a form-associated custom element - - BREAKING CHANGE: - users should no longer slot a native ` - ``` - - After: - - ```html - Submit - ``` - -### Patch Changes - -- Updated dependencies [6b6e2617] - - @patternfly/pfe-core@2.0.0-next.12 - -## 2.0.0-next.7 - -### Patch Changes - -- 07ad1d3d: Updates use of `` -- Updated dependencies [ddf052bd] -- Updated dependencies [07ad1d3d] -- Updated dependencies [07ad1d3d] - - @patternfly/pfe-spinner@2.0.0-next.6 - - @patternfly/pfe-icon@2.0.0-next.5 - - @patternfly/pfe-core@2.0.0-next.10 - -## 2.0.0-next.6 - -### Patch Changes - -- eeebb45d: Replace `` with `` -- Updated dependencies [b7602c2c] -- Updated dependencies [166ecee1] - - @patternfly/pfe-spinner@2.0.0-next.5 - - @patternfly/pfe-core@2.0.0-next.9 - -## 2.0.0-next.5 - -### Patch Changes - -- bfad8b4b: Updates dependencies -- bfad8b4b: Add missing dependencies -- a423b010: fix typescript config and update dependencies -- Updated dependencies [bfad8b4b] -- Updated dependencies [a423b010] - - @patternfly/pfe-core@2.0.0-next.8 - - @patternfly/pfe-icon@2.0.0-next.4 - - @patternfly/pfe-progress-indicator@2.0.0-next.4 - -## 2.0.0-next.4 - -### Major Changes - -- a730678c: Several changes align `` to [PatternFly v4](https://patternfly.org/components/button). - - NEW: - `warning`, `link`, and `control` variants added. - `icon` and `loading` attributes added. - `plain`, `block`, `warning` and `loading` attributes added. - `icon` slot added. - - BREAKING CHANGES: - The `pfelement` attribute and `PFElement` class are **removed** from the `` element by default. - The `danger` variant is **removed** in favour of a new `danger` variant. - _All_ the `--pfe-*` css variables are **removed** in favour of their `--pf-*` equivalents. - - See the [docs](https://patternflyelements.org/components/button) for more info, - and the [demo](https://patternflyelements.org/components/button/demo) for usage examples. - -### Patch Changes - -- Updated dependencies [34ecd410] - - @patternfly/pfe-core@2.0.0-next.6 - -## 2.0.0-next.3 - -### Patch Changes - -- 6a2a0407: [View commit message here](https://gist.github.com/heyMP/200fc0b840690541475923facba393ab) -- Updated dependencies [6a2a0407] - - @patternfly/pfe-core@2.0.0-next.4 - -## 2.0.0-next.2 - -### 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.1 - -### Patch Changes - -- a56aa80b: chore: update package.json - -## 2.0.0-next.0 - -### Major Changes - -- af331f33: ## 🔥 Migrate to Lit - - This release migrates `` to LitElement. - - ### NEW: CSS Shadow Parts! - - - Adds the `container` CSS part to `` - - ### 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` - - Deprecates `pfe-button:click` event - use `click` - - Removes the internal shadow DOM button in favour of the slotted button - - Makes all styles on the slotted button `!important`. Use CSS Custom Properties to override - - See [docs](https://patternflyelements.org/components/button/) for more info - -### Patch Changes - -- Updated dependencies [e8788c72] - - @patternfly/pfe-core@2.0.0-next.0 diff --git a/elements/pf-v5-button/docs/pf-v5-button.md b/elements/pf-v5-button/docs/pf-v5-button.md deleted file mode 100644 index c217081eaf..0000000000 --- a/elements/pf-v5-button/docs/pf-v5-button.md +++ /dev/null @@ -1,137 +0,0 @@ - - - - -{% renderInstallation %} {% endrenderInstallation %} - -{% renderOverview %} - -
- -#### Default - Medium size - -Primary -Secondary -Danger Secondary -Tertiary -Danger -Warning -
- -{% endrenderOverview %} - -{% band header="Usage" %} - ### Link variant - {% htmlexample %} - - - Link - - Link - Inline Link - Danger Link - Link - Go to PatternFly - {% endhtmlexample %} - - ### Plain button - {% htmlexample %} - - - - - - {% endhtmlexample %} - - ### Control variant - {% htmlexample %} - Control - - - - - - {% endhtmlexample %} - - ### Size - {% htmlexample %} - Medium Button - Large Button - {% endhtmlexample %} - - ### Click listeners - - - HTML - - -```html - -Click me! -``` - - - Lit - - -```js -import { html, render } from 'lit'; -import '@patternfly/elements/pf-v5-button/pf-v5-button.js'; - -render(html` - - Click me! - -`, document.getElementById('container')); -``` - - - React - - -```jsx -import { Button } from '@patternfly/elements/react/pf-v5-button/pf-v5-button.js'; -export function Clicker() { - return ( - - ) -} -``` - - - - -{% endband %} - -{% renderSlots %}{% endrenderSlots %} - -{% renderAttributes %}{% endrenderAttributes %} - -{% renderMethods %}{% endrenderMethods %} - -{% renderEvents %}{% endrenderEvents %} - -{% renderCssCustomProperties %}{% endrenderCssCustomProperties %} diff --git a/elements/pf-v5-button/docs/screenshot.png b/elements/pf-v5-button/docs/screenshot.png deleted file mode 100644 index 6e1dfdd900003a41412818d363f6803d8f57b850..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24629 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 diff --git a/elements/pf-v5-button/pf-v5-button-icon.css b/elements/pf-v5-button/pf-v5-button-icon.css deleted file mode 100644 index d6519719d7..0000000000 --- a/elements/pf-v5-button/pf-v5-button-icon.css +++ /dev/null @@ -1,11 +0,0 @@ -/****************************** - * * - * ICON * - * * - ******************************/ - -.hasIcon { - gap: calc(2 * var(--pf-v5-c-button__icon--m-start--MarginLeft, - var(--pf-global--spacer--xs, 0.25rem))); -} - diff --git a/elements/pf-v5-button/pf-v5-button-tokens.css b/elements/pf-v5-button/pf-v5-button-tokens.css deleted file mode 100644 index c3332d148a..0000000000 --- a/elements/pf-v5-button/pf-v5-button-tokens.css +++ /dev/null @@ -1,211 +0,0 @@ -:host { - /** PaddingTop for the button */ - --pf-v5-c-button--PaddingTop: var(--pf-global--spacer--form-element, 0.375rem); - /** PaddingRight for the button */ - --pf-v5-c-button--PaddingRight: var(--pf-global--spacer--md, 1rem); - /** PaddingBottom for the button */ - --pf-v5-c-button--PaddingBottom: var(--pf-global--spacer--form-element, 0.375rem); - /** PaddingLeft for the button */ - --pf-v5-c-button--PaddingLeft: var(--pf-global--spacer--md, 1rem); - /** LineHeight for the button */ - --pf-v5-c-button--LineHeight: var(--pf-global--LineHeight--md, 1.5); - /** FontWeight for the button */ - --pf-v5-c-button--FontWeight: var(--pf-global--FontWeight--normal, 400); - /** FontSize for the button */ - --pf-v5-c-button--FontSize: var(--pf-global--FontSize--md, 1rem); - /** BackgroundColor for the button */ - --pf-v5-c-button--BackgroundColor: transparent; - /** BorderRadius for the button */ - --pf-v5-c-button--BorderRadius: var(--pf-global--BorderRadius--sm, 3px); - /** BorderRadius for the button after element */ - --pf-v5-c-button--after--BorderRadius: var(--pf-global--BorderRadius--sm, 3px); - /** BorderColor for the button after element */ - --pf-v5-c-button--after--BorderColor: transparent; - /** BorderWidth for the button after element */ - --pf-v5-c-button--after--BorderWidth: var(--pf-global--BorderWidth--sm, 1px); - /** BorderWidth for the button after element on hover */ - --pf-v5-c-button--hover--after--BorderWidth: var(--pf-global--BorderWidth--md, 2px); - /** BorderWidth for the button after element on focus */ - --pf-v5-c-button--focus--after--BorderWidth: var(--pf-global--BorderWidth--md, 2px); - /** BorderWidth for the button after element when active */ - --pf-v5-c-button--active--after--BorderWidth: var(--pf-global--BorderWidth--md, 2px); - /** Color for the button when disabled */ - --pf-v5-c-button--disabled--Color: var(--pf-global--disabled-color--100, #6a6e73); - /** BackgroundColor for the button when disabled */ - --pf-v5-c-button--disabled--BackgroundColor: var(--pf-global--disabled-color--200, #d2d2d2); - /** BorderColor for the button after element when disabled */ - --pf-v5-c-button--disabled--after--BorderColor: transparent; - /** BackgroundColor for the primary button variant */ - --pf-v5-c-button--m-primary--BackgroundColor: var(--pf-global--primary-color--100, #06c); - /** Color for the primary button variant */ - --pf-v5-c-button--m-primary--Color: var(--pf-global--Color--light-100, #fff); - /** BackgroundColor for the primary button variant on hover */ - --pf-v5-c-button--m-primary--hover--BackgroundColor: var(--pf-global--primary-color--200, #004080); - /** Color for the primary button variant on hover */ - --pf-v5-c-button--m-primary--hover--Color: var(--pf-global--Color--light-100, #fff); - /** BackgroundColor for the primary button variant on focus */ - --pf-v5-c-button--m-primary--focus--BackgroundColor: var(--pf-global--primary-color--200, #004080); - /** Color for the primary button variant on focus */ - --pf-v5-c-button--m-primary--focus--Color: var(--pf-global--Color--light-100, #fff); - /** BackgroundColor for the primary button variant when active */ - --pf-v5-c-button--m-primary--active--BackgroundColor: var(--pf-global--primary-color--200, #004080); - /** Color for the primary button variant when active */ - --pf-v5-c-button--m-primary--active--Color: var(--pf-global--Color--light-100, #fff); - /** BackgroundColor for the secondary button variant */ - --pf-v5-c-button--m-secondary--BackgroundColor: transparent; - /** BorderColor for the secondary button variant after element */ - --pf-v5-c-button--m-secondary--after--BorderColor: var(--pf-global--primary-color--100, #06c); - /** Color for the secondary button variant */ - --pf-v5-c-button--m-secondary--Color: var(--pf-global--primary-color--100, #06c); - /** BackgroundColor for the secondary button variant on hover */ - --pf-v5-c-button--m-secondary--hover--BackgroundColor: transparent; - /** BorderColor for the secondary button variant after element on hover */ - --pf-v5-c-button--m-secondary--hover--after--BorderColor: var(--pf-global--primary-color--100, #06c); - /** Color for the secondary button variant on hover */ - --pf-v5-c-button--m-secondary--hover--Color: var(--pf-global--primary-color--100, #06c); - /** BackgroundColor for the secondary button variant on focus */ - --pf-v5-c-button--m-secondary--focus--BackgroundColor: transparent; - /** BorderColor for the secondary button variant after element on focus */ - --pf-v5-c-button--m-secondary--focus--after--BorderColor: var(--pf-global--primary-color--100, #06c); - /** Color for the secondary button variant on focus */ - --pf-v5-c-button--m-secondary--focus--Color: var(--pf-global--primary-color--100, #06c); - /** BackgroundColor for the secondary button variant when active */ - --pf-v5-c-button--m-secondary--active--BackgroundColor: transparent; - --pf-v5-c-button--m-secondary--active--after--BorderColor: var(--pf-global--primary-color--100, #06c); - --pf-v5-c-button--m-secondary--active--Color: var(--pf-global--primary-color--100, #06c); - --pf-v5-c-button--m-secondary--m-danger--BackgroundColor: transparent; - --pf-v5-c-button--m-secondary--m-danger--Color: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-secondary--m-danger--after--BorderColor: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-secondary--m-danger--hover--BackgroundColor: transparent; - --pf-v5-c-button--m-secondary--m-danger--hover--Color: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-secondary--m-danger--hover--after--BorderColor: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-secondary--m-danger--focus--BackgroundColor: transparent; - --pf-v5-c-button--m-secondary--m-danger--focus--Color: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-secondary--m-danger--focus--after--BorderColor: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-secondary--m-danger--active--BackgroundColor: transparent; - --pf-v5-c-button--m-secondary--m-danger--active--Color: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-secondary--m-danger--active--after--BorderColor: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-tertiary--BackgroundColor: transparent; - --pf-v5-c-button--m-tertiary--after--BorderColor: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--hover--BackgroundColor: transparent; - --pf-v5-c-button--m-tertiary--hover--after--BorderColor: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--hover--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--focus--BackgroundColor: transparent; - --pf-v5-c-button--m-tertiary--focus--after--BorderColor: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--focus--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--active--BackgroundColor: transparent; - --pf-v5-c-button--m-tertiary--active--after--BorderColor: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-tertiary--active--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-warning--BackgroundColor: var(--pf-global--warning-color--100, #f0ab00); - --pf-v5-c-button--m-warning--Color: var(--pf-global--Color--dark-100, #151515); - --pf-v5-c-button--m-warning--hover--BackgroundColor: var(--pf-global--palette--gold-500, #c58c00); - --pf-v5-c-button--m-warning--hover--Color: var(--pf-global--Color--dark-100, #151515); - --pf-v5-c-button--m-warning--focus--BackgroundColor: var(--pf-global--palette--gold-500, #c58c00); - --pf-v5-c-button--m-warning--focus--Color: var(--pf-global--Color--dark-100, #151515); - --pf-v5-c-button--m-warning--active--BackgroundColor: var(--pf-global--palette--gold-500, #c58c00); - --pf-v5-c-button--m-warning--active--Color: var(--pf-global--Color--dark-100, #151515); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-danger--Color: var(--pf-global--Color--light-100, #fff); - --pf-v5-c-button--m-danger--hover--BackgroundColor: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-danger--hover--Color: var(--pf-global--Color--light-100, #fff); - --pf-v5-c-button--m-danger--focus--BackgroundColor: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-danger--focus--Color: var(--pf-global--Color--light-100, #fff); - --pf-v5-c-button--m-danger--active--BackgroundColor: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-danger--active--Color: var(--pf-global--Color--light-100, #fff); - --pf-v5-c-button--m-link--BackgroundColor: transparent; - --pf-v5-c-button--m-link--Color: var(--pf-global--link--Color, #06c); - --pf-v5-c-button--m-link--hover--BackgroundColor: transparent; - --pf-v5-c-button--m-link--hover--Color: var(--pf-global--link--Color--hover, #004080); - --pf-v5-c-button--m-link--focus--BackgroundColor: transparent; - --pf-v5-c-button--m-link--focus--Color: var(--pf-global--link--Color--hover, #004080); - --pf-v5-c-button--m-link--active--BackgroundColor: transparent; - --pf-v5-c-button--m-link--active--Color: var(--pf-global--link--Color--hover, #004080); - --pf-v5-c-button--m-link--disabled--BackgroundColor: transparent; - --pf-v5-c-button--m-link--m-inline--FontSize: inherit; - --pf-v5-c-button--m-link--m-inline--hover--TextDecoration: var(--pf-global--link--TextDecoration--hover, underline); - --pf-v5-c-button--m-link--m-inline--hover--Color: var(--pf-global--link--Color--hover, #004080); - --pf-v5-c-button--m-link--m-inline--PaddingTop: 0; - --pf-v5-c-button--m-link--m-inline--PaddingRight: 0; - --pf-v5-c-button--m-link--m-inline--PaddingBottom: 0; - --pf-v5-c-button--m-link--m-inline--PaddingLeft: 0; - --pf-v5-c-button--m-link--m-inline__progress--Left: var(--pf-global--spacer--xs, 0.25rem); - --pf-v5-c-button--m-link--m-inline--m-in-progress--PaddingLeft: calc(var(--pf-v5-c-button--m-link--m-inline__progress--Left) + 1rem + var(--pf-global--spacer--sm, 0.5rem)); - --pf-v5-c-button--m-link--m-danger--BackgroundColor: transparent; - --pf-v5-c-button--m-link--m-danger--Color: var(--pf-global--danger-color--100, #c9190b); - --pf-v5-c-button--m-link--m-danger--hover--BackgroundColor: transparent; - --pf-v5-c-button--m-link--m-danger--hover--Color: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-link--m-danger--focus--BackgroundColor: transparent; - --pf-v5-c-button--m-link--m-danger--focus--Color: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-link--m-danger--active--BackgroundColor: transparent; - --pf-v5-c-button--m-link--m-danger--active--Color: var(--pf-global--danger-color--200, #a30000); - --pf-v5-c-button--m-plain--BackgroundColor: transparent; - --pf-v5-c-button--m-plain--Color: var(--pf-global--Color--200, #6a6e73); - --pf-v5-c-button--m-plain--hover--BackgroundColor: transparent; - --pf-v5-c-button--m-plain--hover--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-plain--focus--BackgroundColor: transparent; - --pf-v5-c-button--m-plain--focus--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-plain--active--BackgroundColor: transparent; - --pf-v5-c-button--m-plain--active--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-plain--disabled--Color: var(--pf-global--disabled-color--200, #d2d2d2); - --pf-v5-c-button--m-plain--disabled--BackgroundColor: transparent; - --pf-v5-c-button--m-control--BackgroundColor: var(--pf-global--BackgroundColor--100, #fff); - --pf-v5-c-button--m-control--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-control--BorderRadius: 0; - --pf-v5-c-button--m-control--after--BorderWidth: var(--pf-global--BorderWidth--sm, 1px); - --pf-v5-c-button--m-control--after--BorderTopColor: var(--pf-global--BorderColor--300, #f0f0f0); - --pf-v5-c-button--m-control--after--BorderRightColor: var(--pf-global--BorderColor--300, #f0f0f0); - --pf-v5-c-button--m-control--after--BorderBottomColor: var(--pf-global--BorderColor--200, #8a8d90); - --pf-v5-c-button--m-control--after--BorderLeftColor: var(--pf-global--BorderColor--300, #f0f0f0); - --pf-v5-c-button--m-control--disabled--BackgroundColor: var(--pf-global--disabled-color--300, #f0f0f0); - --pf-v5-c-button--m-control--hover--BackgroundColor: var(--pf-global--BackgroundColor--100, #fff); - --pf-v5-c-button--m-control--hover--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-control--hover--after--BorderBottomWidth: var(--pf-global--BorderWidth--md, 2px); - --pf-v5-c-button--m-control--hover--after--BorderBottomColor: var(--pf-global--active-color--100, #06c); - --pf-v5-c-button--m-control--active--BackgroundColor: var(--pf-global--BackgroundColor--100, #fff); - --pf-v5-c-button--m-control--active--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-control--active--after--BorderBottomWidth: var(--pf-global--BorderWidth--md, 2px); - --pf-v5-c-button--m-control--active--after--BorderBottomColor: var(--pf-global--active-color--100, #06c); - --pf-v5-c-button--m-control--focus--BackgroundColor: var(--pf-global--BackgroundColor--100, #fff); - --pf-v5-c-button--m-control--focus--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-control--focus--after--BorderBottomWidth: var(--pf-global--BorderWidth--md, 2px); - --pf-v5-c-button--m-control--focus--after--BorderBottomColor: var(--pf-global--active-color--100, #06c); - --pf-v5-c-button--m-control--m-expanded--BackgroundColor: var(--pf-global--BackgroundColor--100, #fff); - --pf-v5-c-button--m-control--m-expanded--Color: var(--pf-global--Color--100, #151515); - --pf-v5-c-button--m-control--m-expanded--after--BorderBottomWidth: var(--pf-global--BorderWidth--md, 2px); - --pf-v5-c-button--m-control--m-expanded--after--BorderBottomColor: var(--pf-global--active-color--100, #06c); - --pf-v5-c-button--m-small--FontSize: var(--pf-global--FontSize--sm, 0.875rem); - --pf-v5-c-button--m-display-lg--PaddingTop: var(--pf-global--spacer--md, 1rem); - --pf-v5-c-button--m-display-lg--PaddingRight: var(--pf-global--spacer--xl, 2rem); - --pf-v5-c-button--m-display-lg--PaddingBottom: var(--pf-global--spacer--md, 1rem); - --pf-v5-c-button--m-display-lg--PaddingLeft: var(--pf-global--spacer--xl, 2rem); - --pf-v5-c-button--m-display-lg--FontWeight: var(--pf-global--FontWeight--bold, 700); - --pf-v5-c-button--m-link--m-display-lg--FontSize: var(--pf-global--FontSize--lg, 1.125rem); - --pf-v5-c-button__icon--m-start--MarginRight: var(--pf-global--spacer--xs, 0.25rem); - --pf-v5-c-button__icon--m-end--MarginLeft: var(--pf-global--spacer--xs, 0.25rem); - --pf-v5-c-button__progress--width: calc(var(--pf-global--icon--FontSize--md, 1.125rem) + var(--pf-global--spacer--sm, 0.5rem)); - --pf-v5-c-button__progress--Opacity: 0; - --pf-v5-c-button__progress--TranslateY: -50%; - --pf-v5-c-button__progress--TranslateX: 0; - --pf-v5-c-button__progress--Top: 50%; - --pf-v5-c-button__progress--Left: var(--pf-global--spacer--md, 1rem); - --pf-v5-c-button--m-progress--TransitionProperty: padding; - --pf-v5-c-button--m-progress--TransitionDuration: var(--pf-global--TransitionDuration, 250ms); - --pf-v5-c-button--m-progress--PaddingRight: calc(var(--pf-global--spacer--md, 1rem) + var(--pf-v5-c-button__progress--width) / 2); - --pf-v5-c-button--m-progress--PaddingLeft: calc(var(--pf-global--spacer--md, 1rem) + var(--pf-v5-c-button__progress--width) / 2); - --pf-v5-c-button--m-in-progress--PaddingRight: var(--pf-global--spacer--md, 1rem); - --pf-v5-c-button--m-in-progress--PaddingLeft: calc(var(--pf-global--spacer--md, 1rem) + var(--pf-v5-c-button__progress--width)); - --pf-v5-c-button--m-in-progress--m-plain--Color: var(--pf-global--primary-color--100, #06c); - --pf-v5-c-button--m-in-progress--m-plain__progress--Left: 50%; - --pf-v5-c-button--m-in-progress--m-plain__progress--TranslateX: -50%; - --pf-v5-c-button__count--MarginLeft: var(--pf-global--spacer--sm, 0.5rem); - --pf-v5-c-button--disabled__c-badge--Color: var(--pf-global--Color--dark-100, #151515); - --pf-v5-c-button--disabled__c-badge--BackgroundColor: var(--pf-global--BackgroundColor--200, #f0f0f0); - --pf-v5-c-button--m-primary__c-badge--BorderColor: var(--pf-global--BorderColor--300, #f0f0f0); - --pf-v5-c-button--m-primary__c-badge--BorderWidth: var(--pf-global--BorderWidth--sm, 1px); - - /** Internal button color property */ - --_button-color: var(--pf-v5-c-button--m-primary--Color); - /** Internal button background color property */ - --_button-background-color: var(--pf-v5-c-button--m-primary--BackgroundColor); -} diff --git a/elements/pf-v5-button/pf-v5-button.css b/elements/pf-v5-button/pf-v5-button.css deleted file mode 100644 index d1fa059247..0000000000 --- a/elements/pf-v5-button/pf-v5-button.css +++ /dev/null @@ -1,611 +0,0 @@ -:host { - font-size: var(--pf-v5-c-button--FontSize); - font-weight: var(--pf-v5-c-button--FontWeight); - line-height: var(--pf-v5-c-button--LineHeight); - text-align: center; - white-space: nowrap; - font-size: var(--pf-v5-c-button--FontSize, - var(--pf-global--FontSize--md, 1rem)); - font-weight: var(--pf-v5-c-button--FontWeight, - var(--pf-global--FontWeight--normal, 400)); - line-height: var(--pf-v5-c-button--LineHeight, - var(--pf-global--LineHeight--md, 1.5)); - display: inline-block; - height: max-content; - cursor: pointer; - position: relative; - font-family: inherit; - border-width: 0; - border-style: solid; - border-radius: var(--pf-v5-c-button--BorderRadius, - var(--pf-global--BorderRadius--sm, 3px)); -} - -:host([hidden]), -[hidden] { - display: none !important; -} - -:host([inline]) { - display: inline; - --pf-v5-c-button--PaddingTop: 0; - --pf-v5-c-button--PaddingLeft: 0; - --pf-v5-c-button--PaddingBottom: 0; - --pf-v5-c-button--PaddingRight: 0; -} - -pf-v5-icon, -::slotted(pf-v5-icon) { - color: currentcolor; - padding-inline-start: var(--_button-icon-padding-inline-start); - padding-inline-end: var(--_button-icon-padding-inline-end); - vertical-align: var(--_button-icon-vertical-align); -} - -#icon { - margin-inline-end: var(--pf-v5-c-button__icon--m-start--MarginRight, - var(--pf-global--spacer--xs, 0.25rem)); -} - -#button { - display: inline-block; - color: var(--_button-color); - padding: - var(--pf-v5-c-button--PaddingTop, - var(--pf-global--spacer--form-element, 0.375rem)) - var(--pf-v5-c-button--PaddingRight, - var(--pf-global--spacer--md, 1rem)) - var(--pf-v5-c-button--PaddingBottom, - var(--pf-global--spacer--form-element, 0.375rem)) - var(--pf-v5-c-button--PaddingLeft, - var(--pf-global--spacer--md, 1rem)); - &::before, - &::after { - position: absolute; - inset: 0; - content: ""; - } - &::before { - background-color: var(--_button-background-color); - border-radius: var(--pf-v5-c-button--BorderRadius, - var(--pf-global--BorderRadius--sm, 3px)); - } - &::after { - pointer-events: none; - border-style: solid; - border-width: var(--pf-v5-c-button--after--BorderWidth); - border-color: var(--pf-v5-c-button--after--BorderColor); - border-radius: var(--pf-v5-c-button--after--BorderRadius); - } - &.anchor { - text-decoration: none; - &::after { - pointer-events: all; - } - } -} - -#text { - display: inline; - position: relative; -} - -:host(:focus) { - --pf-v5-c-button--m-primary--Color: var(--pf-v5-c-button--m-primary--focus--Color, - var(--pf-global--Color--light-100, #fff)); - --pf-v5-c-button--m-primary--BackgroundColor: var(--pf-v5-c-button--m-primary--focus--BackgroundColor, - var(--pf-global--primary-color--200, #004080)); - --pf-v5-c-button--after--BorderWidth: var(--pf-v5-c-button--focus--after--BorderWidth, - var(--pf-global--BorderWidth--md, 2px)); - /* DANGER */ - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-danger--focus--Color, - var(--pf-global--Color--light-100, #fff)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-danger--focus--BackgroundColor, - var(--pf-global--danger-color--200, #a30000)); - /* LINK */ - --pf-v5-c-button--m-link--Color: var(--pf-v5-c-button--m-link--focus--Color, - var(--pf-global--link--Color--hover, #004080)); - --pf-v5-c-button--m-link--BackgroundColor: var(--pf-v5-c-button--m-link--hover--BackgroundColor, transparent); - /* PLAIN */ - --pf-v5-c-button--m-plain--Color: var(--pf-v5-c-button--m-plain--focus--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-plain--BackgroundColor: var(--pf-v5-c-button--m-plain--focus--BackgroundColor, - transparent); -} - -:host(:hover) { - --pf-v5-c-button--m-primary--Color: var(--pf-v5-c-button--m-primary--hover--Color, - var(--pf-global--Color--light-100, #fff)); - --pf-v5-c-button--m-primary--BackgroundColor: var(--pf-v5-c-button--m-primary--hover--BackgroundColor, - var(--pf-global--primary-color--200, #004080)); - --pf-v5-c-button--after--BorderWidth: var(--pf-v5-c-button--hover--after--BorderWidth, - var(--pf-global--BorderWidth--md, 2px)); - /* DANGER */ - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-danger--hover--Color, - var(--pf-global--Color--light-100, #fff)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-danger--hover--BackgroundColor, - var(--pf-global--danger-color--200, #a30000)); - /* LINK */ - --pf-v5-c-button--m-link--Color: var(--pf-v5-c-button--m-link--hover--Color, - var(--pf-global--link--Color--hover, #004080)); - --pf-v5-c-button--m-link--BackgroundColor: var(--pf-v5-c-button--m-link--hover--BackgroundColor, transparent); - /* PLAIN */ - --pf-v5-c-button--m-plain--Color: var(--pf-v5-c-button--m-plain--hover--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-plain--BackgroundColor: var(--pf-v5-c-button--m-plain--hover--BackgroundColor, - transparent); -} - -:host(:active) { - --pf-v5-c-button--m-primary--Color: var(--pf-v5-c-button--m-primary--active--Color, - var(--pf-global--Color--light-100, #fff)); - --pf-v5-c-button--m-primary--BackgroundColor: var(--pf-v5-c-button--m-primary--active--BackgroundColor, - var(--pf-global--primary-color--200, #004080)); - --pf-v5-c-button--after--BorderWidth: var(--pf-v5-c-button--active--after--BorderWidth, - var(--pf-global--BorderWidth--md, 2px)); - /* DANGER */ - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-danger--active--Color, - var(--pf-global--Color--light-100, #fff)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-danger--active--BackgroundColor, - var(--pf-global--danger-color--200, #a30000)); - /* LINK */ - --pf-v5-c-button--m-link--Color: var(--pf-v5-c-button--m-link--active--Color, - var(--pf-global--link--Color--hover, #004080)); - --pf-v5-c-button--m-link--BackgroundColor: var(--pf-v5-c-button--m-link--active--BackgroundColor, transparent); -} - -.disabled, -:host(:disabled), -:host([danger]:disabled), -:host([link]:disabled) .link { - pointer-events: none; - cursor: default; -} - -[part=icon] { - --pf-v5-icon--size: 16px; - display: inline-flex; - align-items: center; - position: absolute; - & ::slotted(*) { - width: 16px; - max-width: 16px; - height: 16px; - max-height: 16px; - } -} - -.hasIcon [part=icon] { - cursor: pointer; -} - -.hasIcon #button { - position: absolute; - inset: 0; -} - -/****************************** - * * - * PLAIN * - * * - ******************************/ - -#button.plain { - --pf-v5-c-button--disabled--BackgroundColor: var(--pf-v5-c-button--m-plain--disabled--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderWidth: 0 !important; - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-tertiary--after--BorderColor, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--disabled--Color: var(--pf-v5-c-button--m-plain--disabled--Color, - var(--pf-global--disabled-color--200, #d2d2d2)); - --_button-color: var(--pf-v5-c-button--m-plain--Color, - var(--pf-global--Color--200, #6a6e73)); - --_button-background-color: var(--pf-v5-c-button--m-plain--BackgroundColor, - transparent); - :host(:active) & { - --pf-v5-c-button--m-plain--Color: var(--pf-v5-c-button--m-plain--active--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-plain--BackgroundColor: var(--pf-v5-c-button--m-plain--active--BackgroundColor, - tranparent); - } - &:not(.hasIcon) [part=icon], - &.loading [part=icon] { - left: 16px; - } - & [part=icon] { - display: contents; - } - &.disabled, - &.link.disabled { - --_button-color: var(--pf-v5-c-button--disabled--Color, - var(--pf-v5-c-button--m-plain--disabled--Color, - var(--pf-global--disabled--color--200, #d2d2d2))); - } -} - -.hasIcon:not(.plain) [part=icon] { - position: relative; -} - -/****************************** - * * - * ICON POSITION RIGHT * - * * - ******************************/ - -:host([icon-position=right]) .loading [part=icon] { - order: 1; -} - -:host([icon-position=right]) #button.hasIcon { - padding-left: var(--pf-v5-c-button--PaddingLeft, var(--pf-global--spacer--md, 1rem)); - padding-right: calc(16px + 8px + var(--pf-v5-c-button--PaddingRight, var(--pf-global--spacer--md, 1rem))); -} - -/****************************** - * * - * WARNING * - * * - ******************************/ - -#button.warning { - --_button-color: var(--pf-v5-c-button--m-warning--Color, - var(--pf-global--Color--dark-100, #151515)); - --_button-background-color: var(--pf-v5-c-button--m-warning--BackgroundColor, - var(--pf-global--warning-color--100, #f0ab00)); - :host(:focus) & { - --pf-v5-c-button--m-warning--Color: var(--pf-v5-c-button--m-warning--focus--Color, - var(--pf-global--Color--dark-100, #151515)); - --pf-v5-c-button--m-warning--BackgroundColor: var(--pf-v5-c-button--m-warning--focus--BackgroundColor, - var(--pf-global--palette--gold-500, #c58c00)); - } - :host(:hover) & { - --pf-v5-c-button--m-warning--Color: var(--pf-v5-c-button--m-warning--hover--Color, - var(--pf-global--Color--dark-100, #151515)); - --pf-v5-c-button--m-warning--BackgroundColor: var(--pf-v5-c-button--m-warning--hover--BackgroundColor, - var(--pf-global--palette--gold-500, #c58c00)); - } - :host(:active) & { - --pf-v5-c-button--m-warning--Color: var(--pf-v5-c-button--m-warning--active--Color, - var(--pf-global--Color--dark-100, #151515)); - --pf-v5-c-button--m-warning--BackgroundColor: var(--pf-v5-c-button--m-warning--active--BackgroundColor, - var(--pf-global--palette--gold-500, #c58c00)); - } - &.disabled { - --_button-color: var(--pf-v5-c-button--disabled--Color, - var(--pf-global--disabled-color--100, #6a6e73)); - --_button-background-color: var(--pf-v5-c-button--disabled--BackgroundColor, - var(--pf-global--disabled-color--200, #d2d2d2)); - } -} - -/****************************** - * * - * LOADING * - * * - ******************************/ - -:host([loading]) #button { - position: relative; - display: flex; - align-items: center; -} - -#button.loading { - & [part=icon] { - display: inline-block; - z-index: 1; - position: absolute; - cursor: pointer; - top: var(--pf-v5-c-button__progress--Top, 50%); - left: var(--pf-v5-c-button__progress--Left, - var(--pf-global--spacer--md, 1rem)); - line-height: 1; - transform: translate( - var(--pf-v5-c-button__progress--TranslateX, 0), - var(--pf-v5-c-button__progress--TranslateY, -50%)); - margin-inline-end: var(--pf-v5-c-button__icon--m-start--MarginRight, - var(--pf-global--spacer--xs, 0.25rem)); - } - &.primary:not(.plain), - &.danger { - --pf-v6-c-spinner--Color: white; - } - &:not(.plain) { - padding-left: calc(12px + var(--pf-v5-c-button--PaddingLeft, var(--pf-global--spacer--md, 1rem))); - --pf-v5-c-button--PaddingRight: var(--pf-v5-c-button--m-in-progress--PaddingRight, - var(--pf-global--spacer--md, 1rem)); - --pf-v5-c-button--PaddingLeft: var(--pf-v5-c-button--m-in-progress--PaddingLeft, - calc( - var(--pf-global--spacer--md, 1rem) + var(--pf-v5-c-button__progress--width, - calc(var(--pf-global--icon--FontSize--md, 1.125rem) + var(--pf-global--spacer--sm, 0.5rem))) / 2)); - } - -} - -/****************************** - * * - * SECONDARY * - * * - ******************************/ - -#button.secondary { - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-secondary--m-danger--Color, - var(--pf-global--danger-color--100, #c9190b)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-secondary--m-danger--BackgroundColor, transparent); - --_button-color: var(--pf-v5-c-button--m-secondary--Color, - var(--pf-global--primary-color--100, #06c)); - --_button-background-color: var(--pf-v5-c-button--m-secondary--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--after--BorderColor, - var(--pf-global--primary-color--100, #06c)); - :host(:focus) & { - --pf-v5-c-button--m-secondary--Color: var(--pf-v5-c-button--m-secondary--focus--Color, - var(--pf-global--primary-color--100, #06c)); - --pf-v5-c-button--m-secondary--BackgroundColor: var(--pf-v5-c-button--m-secondary--focus--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--focus--after--BorderColor, - var(--pf-global--primary-color--100, #06c)); - /* DANGER */ - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-secondary--m-danger--focus--Color, - var(--pf-global--danger--color--200, #a30000)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-secondary--m-danger--focus--BackgroundColor, transparent); - } - :host(:hover) & { - --pf-v5-c-button--m-secondary--Color: var(--pf-v5-c-button--m-secondary--hover--Color, - var(--pf-global--primary-color--100, #06c)); - --pf-v5-c-button--m-secondary--BackgroundColor: var(--pf-v5-c-button--m-secondary--hover--BackgroundColor, - transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--hover--after--BorderColor, - var(--pf-global--primary-color--100, #06c)); - /* DANGER */ - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-secondary--m-danger--hover--Color, - var(--pf-global--danger--color--200, #a30000)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-secondary--m-danger--hover--BackgroundColor, transparent); - } - :host(:active) & { - --pf-v5-c-button--m-secondary--Color: var(--pf-v5-c-button--m-secondary--active--Color, - var(--pf-global--primary-color--100, #06c)); - --pf-v5-c-button--m-secondary--BackgroundColor: var(--pf-v5-c-button--m-secondary--active--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--active--after--BorderColor, - var(--pf-global--primary-color--100, #06c)); - /* DANGER */ - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-secondary--m-danger--active--Color, - var(--pf-global--danger--color--200, #a30000)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-secondary--m-danger--active--BackgroundColor, transparent); - } - &.danger { - --_button-color: var(--pf-v5-c-button--m-secondary--m-danger--Color, - var(--pf-global--danger--color--100, #c9190b)); - --_button-background-color: var(--pf-v5-c-button--m-secondary--m-danger--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--m-danger--after--BorderColor, - var(--pf-global--danger--color--100, #c9190b)); - :host(:focus) & { - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--m-danger--focus--after--BorderColor, - var(--pf-global--danger--color--100, #c9190b)); - } - :host(:hover) & { - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--m-danger--hover--after--BorderColor, - var(--pf-global--danger--color--100, #c9190b)); - } - :host(:active) & { - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-secondary--m-danger--active--after--BorderColor, - var(--pf-global--danger--color--100, #c9190b)); - } - } -} - -/****************************** - * * - * TERTIARY * - * * - ******************************/ - -#button.tertiary { - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-tertiary--after--BorderColor, - var(--pf-global--Color--100, #151515)); - --_button-color: var(--pf-v5-c-button--m-tertiary--Color, - var(--pf-global--Color--100, #151515)); - --_button-background-color: var(--pf-v5-c-button--m-tertiary--BackgroundColor, transparent); - :host(:focus) & { - --pf-v5-c-button--m-tertiary--Color: var(--pf-v5-c-button--m-tertiary--focus--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-tertiary--BackgroundColor: var(--pf-v5-c-button--m-tertiary--focus--BackgroundColor, - transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-tertiary--focus--after--BorderColor, - var(--pf-global--Color--100, #151515)); - } - :host(:hover) & { - --pf-v5-c-button--m-tertiary--Color: var(--pf-v5-c-button--m-tertiary--hover--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-tertiary--BackgroundColor: var(--pf-v5-c-button--m-tertiary--hover--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-tertiary--hover--after--BorderColor, - var(--pf-global--Color--100, #151515)); - } - :host(:active) & { - --pf-v5-c-button--m-tertiary--Color: var(--pf-v5-c-button--m-tertiary--active--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-tertiary--BackgroundColor: var(--pf-v5-c-button--m-tertiary--active--BackgroundColor, transparent); - --pf-v5-c-button--after--BorderColor: var(--pf-v5-c-button--m-tertiary--active--after--BorderColor, - var(--pf-global--Color--100, #151515)); - } -} - -/****************************** - * * - * CONTROL * - * * - ******************************/ - -#button.control { - --pf-v5-c-button--BorderRadius: var(--pf-v5-c-button--m-control--BorderRadius, 0); - --pf-v5-c-button--disabled--BackgroundColor: var(--pf-v5-c-button--m-control--disabled--BackgroundColor, - var(--pf-global--disabled-color--300, #f0f0f0)); - --pf-v5-c-button--after--BorderRadius: 0; - --pf-v5-c-button--after--BorderWidth: var(--pf-v5-c-button--m-control--after--BorderWidth, - var(--pf-global--BorderWidth--sm, 1px)); - --pf-v5-c-button--after--BorderColor: - var(--pf-v5-c-button--m-control--after--BorderTopColor, - var(--pf-global--BorderColor--300, #f0f0f0)) - var(--pf-v5-c-button--m-control--after--BorderRightColor, - var(--pf-global--BorderColor--300, #f0f0f0)) - var(--pf-v5-c-button--m-control--after--BorderBottomColor, - var(--pf-global--BorderColor--200, #8a8d90)) - var(--pf-v5-c-button--m-control--after--BorderLeftColor, - var(--pf-global--BorderColor--300, #f0f0f0)); - --_button-color: var(--pf-v5-c-button--m-control--Color, - var(--pf-global--Color--100, #151515)); - --_button-background-color: var(--pf-v5-c-button--m-control--BackgroundColor, - var(--pf-global--BackgroundColor--100, #fff)); - :host(:focus) & { - --pf-v5-c-button--m-control--Color: var(--pf-v5-c-button--m-control--focus--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-control--BackgroundColor: var(--pf-v5-c-button--m-control--focus--BackgroundColor, - var(--pf-global--BackgroundColor--100, #fff)); - --pf-v5-c-button--m-control--after--BorderBottomColor: var(--pf-v5-c-button--m-control--focus--after--BorderBottomColor, - var(--pf-global--active-color--100, #06c)); - &::after { - border-block-end-width: var(--pf-v5-c-button--m-control--focus--after--BorderBottomWidth, - var(--pf-global--BorderWidth--md, 2px)); - } - } - :host(:hover) & { - --pf-v5-c-button--m-control--Color: var(--pf-v5-c-button--m-control--hover--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-control--BackgroundColor: var(--pf-v5-c-button--m-control--hover--BackgroundColor, - var(--pf-global--BackgroundColor--100, #fff)); - --pf-v5-c-button--m-control--after--BorderBottomColor: var(--pf-v5-c-button--m-control--hover--after--BorderBottomColor, - var(--pf-global--active-color--100, #06c)); - &::after { - border-block-end-width: var(--pf-v5-c-button--m-control--hover--after--BorderBottomWidth, - var(--pf-global--BorderWidth--md, 2px)); - } - } - :host(:active) & { - --pf-v5-c-button--m-control--Color: var(--pf-v5-c-button--m-control--active--Color, - var(--pf-global--Color--100, #151515)); - --pf-v5-c-button--m-control--BackgroundColor: var(--pf-v5-c-button--m-control--active--BackgroundColor, - var(--pf-global--BackgroundColor--100, #fff)); - --pf-v5-c-button--m-control--after--BorderBottomColor: var(--pf-v5-c-button--m-control--active--after--BorderBottomColor, - var(--pf-global--active-color--100, #06c)); - &::after { - border-block-end-width: var(--pf-v5-c-button--m-control--active--after--BorderBottomWidth, - var(--pf-global--BorderWidth--md, 2px)); - } - } -} - -/****************************** - * * - * LINK * - * * - ******************************/ - -#button.link { - --pf-v5-c-button--disabled--BackgroundColor: var(--pf-v5-c-button--m-link--disabled--BackgroundColor, transparent); - --_button-color: var(--pf-v5-c-button--m-link--Color, var(--pf-global--link--Color, #06c)); - --_button-background-color: var(--pf-v5-c-button--m-link--BackgroundColor, - var(--pf-v5-c-button--m-link--BackgroundColor, transparent)); - &.inline { - :host(:hover) & { - text-decoration: var(--pf-v5-c-button--m-link--m-inline--hover--TextDecoration, - var(--pf-global--link--TextDecoration--hover, underline)); - } - } - &.danger { - --pf-v5-c-button--m-danger--Color: var(--pf-v5-c-button--m-link--m-danger--Color, - var(--pf-global--danger-color--100, #c9190b)); - --pf-v5-c-button--m-danger--BackgroundColor: var(--pf-v5-c-button--m-link--m-danger--BackgroundColor, transparent); - :host(:hover) & { - --pf-v5-c-button--m-link--m-danger--Color: var(--pf-v5-c-button--m-link--m-danger--hover--Color, - var(--pf-global--danger-color--200, #a30000)); - --pf-v5-c-button--m-link--m-danger--BackgroundColor: var(--pf-v5-c-button--m-link--m-danger--hover--BackgroundColor, transparent); - } - :host(:focus) & { - --pf-v5-c-button--m-link--m-danger--Color: var(--pf-v5-c-button--m-link--m-danger--focus--Color, - var(--pf-global--danger-color--200, #a30000)); - --pf-v5-c-button--m-link--m-danger--BackgroundColor: var(--pf-v5-c-button--m-link--m-danger--focus--BackgroundColor, transparent); - } - :host(:active) & { - --pf-v5-c-button--m-link--m-danger--Color: var(--pf-v5-c-button--m-link--m-danger--active--Color, - var(--pf-global--danger-color--200, #a30000)); - --pf-v5-c-button--m-link--m-danger--BackgroundColor: var(--pf-v5-c-button--m-link--m-danger--active--BackgroundColor, transparent); - } - } -} - -/****************************** - * * - * DISABLED * - * * - ******************************/ - -:host(:is(:disabled,[disabled])) { - pointer-events: none; - cursor: default; -} - -#button.disabled { - &:not(.plain) { - --_button-color: var(--pf-v5-c-button--disabled--Color, - var(--pf-global--disabled-color--100, #6a6e73)); - --_button-background-color: var(--pf-v5-c-button--disabled--BackgroundColor, - var(--pf-global--disabled-color--200, #d2d2d2)); - } - &::after { - border-color: var(--pf-v5-c-button--disabled--after--BorderColor, transparent); - } -} - -/****************************** - * * - * BLOCK * - * * - ******************************/ - -:host([block]) { - display: flex; - width: 100%; - justify-content: center; -} - -/****************************** - * * - * LARGE * - * * - ******************************/ - -:host([size="large"]) { - --pf-v5-c-button--PaddingTop: var(--pf-v5-c-button--m-display-lg--PaddingTop, - var(--pf-global--spacer--md, 1rem)); - --pf-v5-c-button--PaddingRight: var(--pf-v5-c-button--m-display-lg--PaddingRight, - var(--pf-global--spacer--xl, 2rem)); - --pf-v5-c-button--PaddingBottom: var(--pf-v5-c-button--m-display-lg--PaddingBottom, - var(--pf-global--spacer--md, 1rem)); - --pf-v5-c-button--PaddingLeft: var(--pf-v5-c-button--m-display-lg--PaddingLeft, - var(--pf-global--spacer--xl, 2rem)); - --pf-v5-c-button--FontWeight: var(--pf-v5-c-button--m-display-lg--FontWeight, - var(--pf-global--FontWeight--bold, 700)); -} - -/****************************** - * * - * SMALL * - * * - ******************************/ - -:host([size="small"]) { - --pf-v5-c-button--FontSize: var(--pf-v5-c-button--m-small--FontSize, - var(--pf-global--FontSize--md, 1rem)); -} - -/****************************** - * * - * DANGER * - * * - ******************************/ - -#button.danger { - --_button-color: var(--pf-v5-c-button--m-danger--Color, - var(--pf-global--Color--light-100, #fff)); - --_button-background-color: var(--pf-v5-c-button--m-danger--BackgroundColor, - var(--pf-global--danger-color--100, #c9190b)); -} - diff --git a/elements/pf-v5-button/pf-v5-button.ts b/elements/pf-v5-button/pf-v5-button.ts deleted file mode 100644 index 3ebf87edb7..0000000000 --- a/elements/pf-v5-button/pf-v5-button.ts +++ /dev/null @@ -1,238 +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 { ifDefined } from 'lit/directives/if-defined.js'; -import { classMap } from 'lit/directives/class-map.js'; - -import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; -import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; - -import '@patternfly/elements/pf-v5-icon/pf-v5-icon.js'; -import '@patternfly/elements/pf-v6-spinner/pf-v6-spinner.js'; - -import tokensStyles from './pf-v5-button-tokens.css'; -import iconStyles from './pf-v5-button-icon.css'; - -import styles from './pf-v5-button.css'; - -export type ButtonVariant = ( - | 'primary' - | 'secondary' - | 'tertiary' - | 'control' - | 'link' -); - -/** - * A **button** is a box area or text that communicates and triggers user actions when - * clicked or selected. Buttons can be used to communicate and immediately trigger - * actions a user can take in an application, like submitting a form, canceling a - * process, or creating a new object. Buttons can also be used to take a user to a - * new location, like another page inside of a web application, or an external site - * such as help or documentation.. - * @summary Allows users to perform an action when triggered - * @alias Button - * @attr {string} [loading-label='loading'] - ARIA label for the loading indicator - */ -@customElement('pf-v5-button') -export class PfV5Button extends LitElement { - static readonly formAssociated = true; - - static readonly styles: CSSStyleSheet[] = [ - tokensStyles, - iconStyles, - styles, - ]; - - @property({ reflect: true }) type?: 'button' | 'submit' | 'reset'; - - /** Accessible name for the button, use when the button does not have slotted text */ - @property() label?: string; - - /** Form value for the button */ - @property() value?: string; - - /** Form element name for the button */ - @property() name?: string; - - /** Disables the button */ - @property({ reflect: true, type: Boolean }) disabled = false; - - /** Represents the state of a stateful button */ - @property({ type: Boolean, reflect: true }) loading = false; - - /** Changes the size of the button. */ - @property({ reflect: true }) size?: 'small' | 'large'; - - /** Not as urgent as danger */ - @property({ type: Boolean, reflect: true }) warning = false; - - /** - * Use danger buttons for actions a user can take that are potentially - * destructive or difficult/impossible to undo, like deleting or removing - * user data. - */ - @property({ type: Boolean, reflect: true }) danger = false; - - /** Applies plain styles */ - @property({ type: Boolean, reflect: true }) plain = false; - - /** - * Changes the style of the button. - * - Primary: Used for the most important call to action on a page. Try to - * limit primary buttons to one per page. - * - Secondary: Use secondary buttons for general actions on a page, that - * don’t require as much emphasis as primary button actions. For example, - * you can use secondary buttons where there are multiple actions, like in - * toolbars or data lists. - * - Tertiary: Tertiary buttons are flexible and can be used as needed. - */ - @property({ reflect: true }) variant: ButtonVariant = 'primary'; - - @property({ reflect: true, type: Boolean }) inline = false; - - @property({ reflect: true, type: Boolean }) block = false; - - /** Shorthand for the `icon` slot, the value is icon name */ - @property() icon?: string; - - /** Icon set for the `icon` property */ - @property({ attribute: 'icon-set' }) iconSet?: string; - - /** Store the URL Link */ - @property({ reflect: true }) href?: string; - - /** Redirecting the URL Link to new Tab */ - @property({ reflect: true }) target?: string; - - #internals = InternalsController.of(this, { role: this.variant === 'link' ? 'none' : 'button' }); - - #slots = new SlotController(this, 'icon', null); - - get #disabled() { - return this.disabled || this.#internals.formDisabled; - } - - override connectedCallback(): void { - super.connectedCallback(); - this.addEventListener('click', this.#onClick); - this.addEventListener('keydown', this.#onKeydown); - } - - protected override willUpdate(): void { - this.#internals.ariaLabel = this.label || null; - this.#internals.ariaDisabled = String(!!this.disabled); - const isLink = this.variant === 'link' && this.href; - if (isLink) { - this.removeAttribute('tabindex'); - this.#internals.role = 'none'; - } else { - this.tabIndex = 0; - this.#internals.role = 'button'; - } - } - - async formDisabledCallback(): Promise { - await this.updateComplete; - this.requestUpdate(); - } - - override render(): TemplateResult<1> { - const hasIcon = !!this.icon || !!this.loading || this.#slots.hasSlotted('icon'); - const { warning, variant, danger, loading, plain, inline, block, size, href, target } = this; - - const disabled = this.#disabled; - - const content = html` - - - - - - `; - - if (variant === 'link' && href) { - return html` - ${content}`; - } else { - return html` -
${content}
`; - } - } - - #onClick() { - if (!this.#disabled) { - switch (this.type) { - case 'reset': - return this.#internals.reset(); - default: - return this.#internals.submit(); - } - } - } - - #onKeydown(event: KeyboardEvent) { - switch (event.key) { - case ' ': - event.preventDefault(); - event.stopPropagation(); - if (this.dispatchEvent(new MouseEvent('click', { - bubbles: true, - cancelable: true, - view: window, - }))) { - this.#onClick(); - } - break; - case 'Enter': - if (this.dispatchEvent(new MouseEvent('click', { - bubbles: true, - cancelable: true, - view: window, - }))) { - this.#onClick(); - } - } - } -} - -declare global { - interface HTMLElementTagNameMap { - 'pf-v5-button': PfV5Button; - } -} diff --git a/elements/pf-v5-button/test/pf-button.e2e.ts b/elements/pf-v5-button/test/pf-button.e2e.ts deleted file mode 100644 index f74a6ea00b..0000000000 --- a/elements/pf-v5-button/test/pf-button.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-button'; - -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-button/test/pf-button.spec.ts b/elements/pf-v5-button/test/pf-button.spec.ts deleted file mode 100644 index e8648456f5..0000000000 --- a/elements/pf-v5-button/test/pf-button.spec.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { expect, html } from '@open-wc/testing'; -import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; -import { sendKeys } from '@web/test-runner-commands'; -import { clickElementAtCenter } from '@patternfly/pfe-tools/test/utils.js'; - -import { PfV5Button } from '@patternfly/elements/pf-v5-button/pf-v5-button.js'; - -import '@patternfly/pfe-tools/test/stub-logger.js'; - -function press(key: string) { - return async function() { - await sendKeys({ press: key }); - }; -} - -describe('', function() { - it('imperatively instantiates', function() { - expect(document.createElement('pf-v5-button')).to.be.an.instanceof(PfV5Button); - }); - - it('should upgrade', async function() { - const el = await createFixture(html`Button`); - expect(el, 'pf-v5-button should be an instance of PfV5Button') - .to.be.an.instanceOf(customElements.get('pf-v5-button')) - .and - .to.be.an.instanceOf(PfV5Button); - }); - describe('in a fieldset', function() { - let element: PfV5Button; - let fieldset: HTMLFieldSetElement; - let form: HTMLFormElement; - let submitEvent: SubmitEvent; - - beforeEach(async function() { - form = await createFixture(html` -
- -
- OK -
- -
- `); - fieldset = form.querySelector('fieldset')!; - element = form.querySelector('pf-v5-button')!; - form.querySelector('input')?.focus(); - form.addEventListener('submit', function(event) { - event.preventDefault(); - submitEvent = event; - }); - await element.updateComplete; - }); - - afterEach(function() { - // @ts-expect-error: resetting fixture - submitEvent = undefined; - }); - - describe('clicking the button', function() { - beforeEach(() => clickElementAtCenter(element)); - it('submits the form', function() { - expect(submitEvent).to.be.ok; - }); - }); - - describe('tabbing through', function() { - beforeEach(press('Tab')); - it('does focus the button', function() { - expect(document.activeElement) - .to - .be.an.instanceof(PfV5Button); - }); - - describe('pressing Space', function() { - beforeEach(press(' ')); - it('submits the form', function() { - expect(submitEvent).to.be.ok; - }); - }); - - describe('pressing Enter', function() { - beforeEach(press('Enter')); - it('submits the form', function() { - expect(submitEvent).to.be.ok; - }); - }); - }); - - describe('disabling the fieldset', function() { - beforeEach(async function() { - fieldset.disabled = true; - await element.updateComplete; - }); - it('disables the button', function() { - expect(element.matches(':disabled'), 'matches :disabled').to.be.true; - }); - describe('tabbing through', function() { - beforeEach(press('Tab')); - it('does not focus the button', function() { - expect(document.activeElement) - .to - .not - .be.an.instanceof(PfV5Button); - }); - }); - // this was a regression spotted by @brianferry - describe('then disabling the button', function() { - beforeEach(async function() { - element.disabled = true; - await element.updateComplete; - }); - describe('then enabling the button', function() { - beforeEach(async function() { - element.disabled = false; - await element.updateComplete; - }); - describe('then enabling the fieldset', function() { - beforeEach(async function() { - fieldset.disabled = false; - await element.updateComplete; - }); - describe('tabbing through', function() { - beforeEach(press('Tab')); - it('does focus the button', function() { - expect(document.activeElement) - .to - .be.an.instanceof(PfV5Button); - }); - }); - }); - }); - }); - }); - }); -}); diff --git a/elements/pf-v5-card/demo/header-images-and-actions.html b/elements/pf-v5-card/demo/header-images-and-actions.html index edaeea341e..981da2b1fa 100644 --- a/elements/pf-v5-card/demo/header-images-and-actions.html +++ b/elements/pf-v5-card/demo/header-images-and-actions.html @@ -9,7 +9,7 @@ - + Action Link diff --git a/elements/pf-v5-card/demo/modifiers.html b/elements/pf-v5-card/demo/modifiers.html index 85f9a21124..9c9f221f64 100644 --- a/elements/pf-v5-card/demo/modifiers.html +++ b/elements/pf-v5-card/demo/modifiers.html @@ -23,15 +23,15 @@

Lightest card

This is the lightest pf-v5-card and a link, and a visited link with border.

- Try - Buy + Try + Buy
diff --git a/elements/pf-v5-tooltip/docs/pf-v5-tooltip.md b/elements/pf-v5-tooltip/docs/pf-v5-tooltip.md index 2688f24a4b..de6dded0a4 100644 --- a/elements/pf-v5-tooltip/docs/pf-v5-tooltip.md +++ b/elements/pf-v5-tooltip/docs/pf-v5-tooltip.md @@ -3,7 +3,7 @@ {% renderOverview %} ### Default - Tooltip + Tooltip {% endrenderOverview %} @@ -11,84 +11,84 @@ ### Left Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Left-Start Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Left-End Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Right Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Right-Start Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Right-End Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Top Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Top-Start Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Top-End Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Bottom Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Bottom-Start Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} ### Bottom-End Tooltip {% htmlexample %} - Tooltip + Tooltip {% endhtmlexample %} {% endband %} diff --git a/elements/pf-v6-button/pf-v6-button.ts b/elements/pf-v6-button/pf-v6-button.ts index e2c511228a..bf6eb5e3cd 100644 --- a/elements/pf-v6-button/pf-v6-button.ts +++ b/elements/pf-v6-button/pf-v6-button.ts @@ -78,6 +78,7 @@ const loadingConverter: ComplexAttributeConverter = { * `ElementInternals` via `InternalsController` — not a slotted native ` + + `); + element = wrapper.querySelector('x-at-focus-test')!; + outside = wrapper.querySelector('#outside')!; + items = [...element.querySelectorAll('.item')]; + }); + + describe('while focus is inside the container', function() { + beforeEach(async function() { + await sendKeys({ press: 'Tab' }); + await element.updateComplete; + }); + + it('moves focus when the index changes', function() { + expect(document.activeElement).to.equal(items[0]); + element.controller.atFocusedItemIndex = 1; + expect(document.activeElement).to.equal(items[1]); + }); + }); + + describe('after focus leaves the container', function() { + beforeEach(async function() { + await sendKeys({ press: 'Tab' }); + await sendKeys({ press: 'Tab' }); + await element.updateComplete; + expect(document.activeElement).to.equal(outside); + }); + + it('does not steal focus back when the index changes', function() { + element.controller.atFocusedItemIndex = 1; + expect(document.activeElement).to.equal(outside); + }); + + it('still updates the roving tabindex', function() { + element.controller.atFocusedItemIndex = 1; + expect(items[0].tabIndex).to.equal(-1); + expect(items[1].tabIndex).to.equal(0); + }); + }); + }); }); diff --git a/core/pfe-core/controllers/test/internals-controller.spec.ts b/core/pfe-core/controllers/test/internals-controller.spec.ts new file mode 100644 index 0000000000..81fcf84af8 --- /dev/null +++ b/core/pfe-core/controllers/test/internals-controller.spec.ts @@ -0,0 +1,116 @@ +import { expect, fixture } from '@open-wc/testing'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { LitElement, html } from 'lit'; + +import { InternalsController } from '../internals-controller.js'; + +@customElement('x-internals-test') +class TestInternalsElement extends LitElement { + static readonly formAssociated = true; + + internals = InternalsController.of(this); + + protected override render() { + return html``; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'x-internals-test': TestInternalsElement; + } +} + +describe('InternalsController', function() { + describe('form', function() { + it('returns the owning form', async function() { + const form = await fixture(html` +
+ +
+ `); + const element = form.querySelector('x-internals-test')!; + expect(element.internals.form).to.equal(form); + }); + + it('returns null when the host is not in a form', async function() { + const element = await fixture(html` + + `); + expect(element.internals.form).to.be.null; + }); + }); + + describe('shadowRoot', function() { + it('returns the host shadow root', async function() { + const element = await fixture(html` + + `); + expect(element.internals.shadowRoot).to.equal(element.shadowRoot); + }); + }); + + describe('submit', function() { + let form: HTMLFormElement; + let element: TestInternalsElement; + let submitted: boolean; + + beforeEach(async function() { + submitted = false; + form = await fixture(html` +
+ + +
+ `); + element = form.querySelector('x-internals-test')!; + form.addEventListener('submit', function(event) { + event.preventDefault(); + submitted = true; + }); + }); + + it('submits the associated form', function() { + element.internals.submit(); + expect(submitted).to.be.true; + }); + + it('passes the submitter to the form when the UA accepts it', function() { + const original = form.requestSubmit.bind(form); + const calls: (HTMLElement | undefined)[] = []; + form.requestSubmit = function(submitter?: HTMLElement) { + calls.push(submitter); + original(); + } as typeof form.requestSubmit; + + element.internals.submit(element); + + expect(calls).to.deep.equal([element]); + expect(submitted).to.be.true; + }); + + it('falls back to requestSubmit() when the UA rejects the submitter', function() { + const original = form.requestSubmit.bind(form); + const calls: (HTMLElement | undefined)[] = []; + form.requestSubmit = function(submitter?: HTMLElement) { + calls.push(submitter); + if (submitter) { + throw new TypeError('not a submitter'); + } + original(); + } as typeof form.requestSubmit; + + element.internals.submit(element); + + expect(calls).to.deep.equal([element, undefined]); + expect(submitted).to.be.true; + }); + + it('does nothing when the host is not associated with a form', async function() { + const standalone = await fixture(html` + + `); + expect(() => standalone.internals.submit()).to.not.throw(); + }); + }); +}); From 47ec5b4356da7e2784af2946e389c5699c5ba72e Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 9 Nov 2026 11:55:25 +0200 Subject: [PATCH 17/31] test: drop global focus sentinel and restore upstream assertions The trailing tabindex=0 sentinel was injected into every test page to give Tab somewhere to go after a fixture, which changed focus behavior for all suites and forced weaker assertions in three specs. Remove it and restore the original assertions; Tab behavior is covered with per-fixture focus targets where needed. Assisted-By: Claude Code --- .../pf-v5-accordion/test/pf-accordion.spec.ts | 5 +-- .../test/pf-label-group.spec.ts | 4 +-- tools/pfe-tools/test/config.ts | 31 ------------------- 3 files changed, 5 insertions(+), 35 deletions(-) diff --git a/elements/pf-v5-accordion/test/pf-accordion.spec.ts b/elements/pf-v5-accordion/test/pf-accordion.spec.ts index 456a292233..1085d8a264 100644 --- a/elements/pf-v5-accordion/test/pf-accordion.spec.ts +++ b/elements/pf-v5-accordion/test/pf-accordion.spec.ts @@ -675,7 +675,8 @@ describe('', function() { describe('Shift+Tab', function() { beforeEach(press('Shift+Tab')); it('moves focus to the body', async function() { - expect(await a11ySnapshot()).to.not.axContainQuery({ role: 'button', focused: true }); + const snapshot = await a11ySnapshot(); + expect(querySnapshot(snapshot, { focused: true })).to.not.be.ok; }); }); @@ -1165,7 +1166,7 @@ describe('', function() { describe('Tab', function() { beforeEach(press('Tab')); it('moves focus to the body', async function() { - expect(await a11ySnapshot()).to.not.axContainQuery({ role: 'button', focused: true }); + expect(await a11ySnapshot()).to.have.axTreeFocusOn(document.body); }); }); }); diff --git a/elements/pf-v5-label-group/test/pf-label-group.spec.ts b/elements/pf-v5-label-group/test/pf-label-group.spec.ts index e3dd2b9b95..a55b051fa2 100644 --- a/elements/pf-v5-label-group/test/pf-label-group.spec.ts +++ b/elements/pf-v5-label-group/test/pf-label-group.spec.ts @@ -91,8 +91,8 @@ describe('', function() { beforeEach(press('Enter')); beforeEach(updateComplete); it('should remove element', async function() { - expect(document.querySelector('pf-v5-label-group')).to.be.null; - expect(await a11ySnapshot()).to.not.axContainQuery({ role: 'button', name: 'Close' }); + const snapshot = await a11ySnapshot(); + expect(snapshot.children).to.not.be.ok; }); }); }); diff --git a/tools/pfe-tools/test/config.ts b/tools/pfe-tools/test/config.ts index 347d614d4b..b9b66f1ecf 100644 --- a/tools/pfe-tools/test/config.ts +++ b/tools/pfe-tools/test/config.ts @@ -28,40 +28,9 @@ const testRunnerHtml: TestRunnerConfig['testRunnerHtml'] = testFramework => /* h } } - - - - `; From 5f9f26a50bc392bbb7a7aa5f398df789564c7a39 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 9 Nov 2026 16:43:51 +0200 Subject: [PATCH 18/31] fix(button): restore focus ring and harden form and badge behavior Address code review findings: reflect the name attribute so programmatic name/value participate in FACE submission, classify the deprecated icon-position=right alias as icon-end, add a focus-visible outline, sync the count badge from the computed disabled state so fieldset disabling propagates, and cover these paths. Also correct the changeset migration notes for the v5 warning boolean and React-parity flag names. Assisted-By: Claude Code --- .changeset/bright-buttons-port.md | 3 +- elements/pf-v6-button/pf-v6-button.css | 13 +- elements/pf-v6-button/pf-v6-button.ts | 147 +++++++------ .../pf-v6-button/test/pf-v6-button.spec.ts | 208 +++++++++++++++++- 4 files changed, 287 insertions(+), 84 deletions(-) diff --git a/.changeset/bright-buttons-port.md b/.changeset/bright-buttons-port.md index 3cd178afd9..2986de31bd 100644 --- a/.changeset/bright-buttons-port.md +++ b/.changeset/bright-buttons-port.md @@ -14,9 +14,10 @@ - Renamed tag from `` to `` - CSS custom properties renamed from `--pf-v5-c-button--*` to `--pf-v6-c-button--*` -- Boolean flags drop the `is-` prefix (`disabled`, `loading`, `block`, `danger`, …) +- Boolean flag names reflect React Button parity (`disabled`, `loading`, `block`, `danger`, …); the v5 flags were already unprefixed - `label` renamed to `accessible-label` - `plain` boolean replaced by `variant="plain"` +- `warning` boolean replaced by `variant="warning"` - `size="small"|"large"` replaced by `sm`/`lg` - Default `type` no longer submits forms (matches React); set `type="submit"` explicitly diff --git a/elements/pf-v6-button/pf-v6-button.css b/elements/pf-v6-button/pf-v6-button.css index a708fa8659..ee508b2f4a 100644 --- a/elements/pf-v6-button/pf-v6-button.css +++ b/elements/pf-v6-button/pf-v6-button.css @@ -4,15 +4,6 @@ box-sizing: border-box; } -:where(button) { - margin: 0; - font-family: inherit; - font-size: 100%; - line-height: var(--pf-t--global--font--line-height--body, 1.5); - color: var(--pf-t--global--text--color--regular, #151515); - cursor: pointer; -} - :host { color-scheme: light dark; @@ -1073,6 +1064,10 @@ outline-offset: var(--pf-t--global--focus-ring--position--offset, 0.125rem); } +:host(:focus-visible) #button { + outline: var(--pf-t--global--focus-ring--width--offset, 2px) solid var(--pf-t--global--focus-ring--color--default, #0066cc); +} + :host([disabled]), :host([disabled-focusable]) { cursor: not-allowed; diff --git a/elements/pf-v6-button/pf-v6-button.ts b/elements/pf-v6-button/pf-v6-button.ts index 8ae9b6b80a..f87a9cb74b 100644 --- a/elements/pf-v6-button/pf-v6-button.ts +++ b/elements/pf-v6-button/pf-v6-button.ts @@ -141,7 +141,7 @@ export class PfV6Button extends LitElement { @property() value?: string; /** Form element name for the button */ - @property() name?: string; + @property({ reflect: true }) name?: string; /** Accessible name when the button has no visible text */ @property({ attribute: 'accessible-label' }) accessibleLabel?: string; @@ -237,6 +237,71 @@ export class PfV6Button extends LitElement { */ #submitting = false; + #onClick = (event: Event): void => { + if (!this.#operable) { + event.preventDefault(); + event.stopImmediatePropagation(); + return; + } + if (this.href) { + return; + } + switch (this.type) { + case 'submit': + // Expose the value only while this button is submitting, so multiple + // named submit buttons (or a named type=button) cannot contribute + // duplicate or spurious entries the way a native button would not. + this.#submitting = true; + this.#internals.setFormValue(this.#formValue); + try { + // Prefer this as submitter when the UA allows FACE submitters; + // otherwise InternalsController falls back to requestSubmit(). + this.#internals.submit(this); + } finally { + queueMicrotask(() => { + this.#submitting = false; + this.#internals.setFormValue(this.#formValue); + }); + } + break; + case 'reset': + this.#internals.reset(); + break; + case 'button': + default: + // Default matches React Button (`type="button"`): no form action. + break; + } + }; + + #onKeydown = (event: KeyboardEvent): void => { + if (this.href) { + return; + } + switch (event.key) { + case ' ': + event.preventDefault(); + event.stopPropagation(); + this.dispatchEvent( + new MouseEvent('click', { + bubbles: true, + cancelable: true, + view: window, + }) + ); + break; + case 'Enter': + this.dispatchEvent( + new MouseEvent('click', { + bubbles: true, + cancelable: true, + view: window, + }) + ); + break; + } + }; + /** Owning form via ElementInternals when `formAssociated` is true. */ get form(): HTMLFormElement | null { return this.#internals.form; @@ -313,6 +378,8 @@ export class PfV6Button extends LitElement { this.#hasIcon() && !this.textContent?.trim() && !this.accessibleLabel + && !this.getAttribute('aria-label') + && !this.getAttribute('aria-labelledby') ) { // eslint-disable-next-line no-console console.error( @@ -320,9 +387,10 @@ export class PfV6Button extends LitElement { ); } - if (changed.has('disabled')) { - this.#syncCountBadgeDisabled(); - } + // Called on every update (not only when `disabled` changes) so that + // fieldset disable/enable via `formDisabledCallback` also syncs the + // slotted count badge. + this.#syncCountBadgeDisabled(); } override render(): TemplateResult<1> { @@ -442,7 +510,7 @@ export class PfV6Button extends LitElement { return; } for (const badge of this.querySelectorAll('pf-v6-badge[slot="count"]')) { - if (this.disabled) { + if (this.#disabled) { badge.setAttribute('disabled', ''); } else { badge.removeAttribute('disabled'); @@ -481,8 +549,8 @@ export class PfV6Button extends LitElement { part="icon" class="${classMap({ 'icon': true, - 'icon-start': hasText && this.iconPosition !== 'end', - 'icon-end': hasText && this.iconPosition === 'end', + 'icon-start': hasText && !(this.iconPosition === 'end' || this.iconPosition === 'right'), + 'icon-end': hasText && (this.iconPosition === 'end' || this.iconPosition === 'right'), })}" ?hidden="${!hasIcon}" >${iconContent} `; } - - #onClick = (event: Event): void => { - if (!this.#operable) { - event.preventDefault(); - event.stopImmediatePropagation(); - return; - } - if (this.href) { - return; - } - switch (this.type) { - case 'submit': - // Expose the value only while this button is submitting, so multiple - // named submit buttons (or a named type=button) cannot contribute - // duplicate or spurious entries the way a native button would not. - this.#submitting = true; - this.#internals.setFormValue(this.#formValue); - try { - // Prefer this as submitter when the UA allows FACE submitters; - // otherwise InternalsController falls back to requestSubmit(). - this.#internals.submit(this); - } finally { - queueMicrotask(() => { - this.#submitting = false; - this.#internals.setFormValue(this.#formValue); - }); - } - break; - case 'reset': - this.#internals.reset(); - break; - case 'button': - default: - // Default matches React Button (`type="button"`): no form action. - break; - } - }; - - #onKeydown = (event: KeyboardEvent): void => { - if (this.href) { - return; - } - switch (event.key) { - case ' ': - event.preventDefault(); - event.stopPropagation(); - this.dispatchEvent( - new MouseEvent('click', { - bubbles: true, - cancelable: true, - view: window, - }) - ); - break; - case 'Enter': - this.dispatchEvent( - new MouseEvent('click', { - bubbles: true, - cancelable: true, - view: window, - }) - ); - break; - } - }; } declare global { diff --git a/elements/pf-v6-button/test/pf-v6-button.spec.ts b/elements/pf-v6-button/test/pf-v6-button.spec.ts index ba6f67bfe3..c3329618e2 100644 --- a/elements/pf-v6-button/test/pf-v6-button.spec.ts +++ b/elements/pf-v6-button/test/pf-v6-button.spec.ts @@ -6,6 +6,7 @@ import { sendKeys } from '@web/test-runner-commands'; import { clickElementAtCenter } from '@patternfly/pfe-tools/test/utils.js'; import { PfV6Button } from '@patternfly/elements/pf-v6-button/pf-v6-button.js'; +import { PfV6Badge } from '@patternfly/elements/pf-v6-badge/pf-v6-badge.js'; function press(key: string) { return async function() { @@ -173,8 +174,53 @@ describe('', function() { `); expect(element.variant).to.equal(variant); + const part = element.shadowRoot!.querySelector('[part="button"]')!; + expect(part.classList.contains(variant), `renders the ${variant} class`).to.be.true; }); } + + describe('filled variants', function() { + const variants = ['primary', 'secondary', 'tertiary', 'danger', 'warning'] as const; + let elements: Record; + + beforeEach(async function() { + elements = {}; + for (const variant of variants) { + const element = await createFixture(html` + + `); + await element.updateComplete; + elements[variant] = element; + } + }); + + function background(element: PfV6Button): string { + const part = element.shadowRoot!.querySelector('[part="button"]')!; + return getComputedStyle(part).backgroundColor; + } + + it('renders the filled variants with distinct backgrounds', function() { + const backgrounds = ['primary', 'danger', 'warning'].map(v => background(elements[v]!)); + expect(new Set(backgrounds).size, 'unique backgrounds').to.equal(3); + }); + + it('renders secondary and tertiary unfilled', function() { + for (const variant of ['secondary', 'tertiary'] as const) { + expect(background(elements[variant]!), `${variant} background`).to.equal('rgba(0, 0, 0, 0)'); + } + }); + }); + + describe('stateful variant', function() { + it('remains a button in the accessibility tree', async function() { + await createFixture(html` + Messages + `); + const snapshot = await a11ySnapshot({ selector: 'pf-v6-button' }); + expect(snapshot.role).to.equal('button'); + expect(snapshot.name).to.equal('Messages'); + }); + }); }); describe('loading', function() { @@ -224,6 +270,18 @@ describe('', function() { expect(element.loading).to.be.false; expect(element.getAttribute('loading')).to.equal('false'); }); + + it('renders no spinner', function() { + expect(element.shadowRoot!.querySelector('pf-v6-spinner')).to.not.be.ok; + expect(element.shadowRoot!.querySelector('[part="progress"]')).to.not.be.ok; + }); + + it('reserves progress padding', async function() { + const idle = await createFixture(html`Reserved`); + await idle.updateComplete; + await element.updateComplete; + expect(element.offsetWidth, 'wider than an idle button').to.be.greaterThan(idle.offsetWidth); + }); }); describe('icon-only button loading with a custom loading-label', function() { @@ -259,6 +317,15 @@ describe('', function() { `); expect(element.iconPosition).to.equal('right'); }); + + it('applies icon-end styling for the deprecated right alias', async function() { + const element = await createFixture(html` + Label + `); + await element.updateComplete; + const icon = element.shadowRoot!.querySelector('#icon')!; + expect(icon.classList.contains('icon-end')).to.be.true; + }); }); describe('icon slot', function() { @@ -487,19 +554,95 @@ describe('', function() { }); }); + describe('dev warnings', function() { + let errors: string[]; + let originalError: typeof console.error; + + beforeEach(function() { + originalError = console.error; + errors = []; + console.error = function(...args: unknown[]) { + errors.push(args.join(' ')); + }; + }); + + afterEach(function() { + console.error = originalError; + }); + + it('warns when hamburger is set without expanded', async function() { + await createFixture(html` + + `); + expect(errors.some(x => x.includes('hamburger'))).to.be.true; + }); + + it('warns when icon-only has no accessible-label', async function() { + await createFixture(html` + + `); + expect(errors.some(x => x.includes('accessible-label'))).to.be.true; + }); + + it('does not warn when the host has aria-label', async function() { + await createFixture(html` + + `); + expect(errors).to.have.length(0); + }); + }); + describe('link with href', function() { let element: PfV6Button; + let snapshot: A11yTreeSnapshot; beforeEach(async function() { element = await createFixture(html` Docs `); + snapshot = await a11ySnapshot({ selector: 'pf-v6-button' }); }); it('exposes href for link buttons', function() { expect(element.href).to.equal('#destination'); expect(element.variant).to.equal('link'); }); + + it('does not expose role button on the host', function() { + expect(snapshot.role).to.not.equal('button'); + }); + + it('exposes a link in the accessibility tree', async function() { + const tree = await a11ySnapshot(); + expect(tree).to.axContainQuery({ role: 'link', name: 'Docs' }); + }); + + it('renders an anchor with the href', function() { + const anchor = element.shadowRoot!.querySelector('a#button')!; + expect(anchor).to.be.ok; + expect(anchor.getAttribute('href')).to.equal('#destination'); + }); + + it('sets tabindex -1 on the anchor when disabled', async function() { + element.disabled = true; + await element.updateComplete; + const anchor = element.shadowRoot!.querySelector('a#button')!; + expect(anchor.tabIndex).to.equal(-1); + }); + + it('does not dispatch a synthetic click on Space or Enter', function() { + let clicks = 0; + element.addEventListener('click', function() { + clicks += 1; + }); + element.dispatchEvent(new KeyboardEvent('keydown', { + key: 'Enter', bubbles: true, composed: true, + })); + element.dispatchEvent(new KeyboardEvent('keydown', { + key: ' ', bubbles: true, composed: true, + })); + expect(clicks).to.equal(0); + }); }); describe('form association', function() { @@ -670,13 +813,34 @@ describe('', function() { expect(submitData!.getAll('action')).to.deep.equal(['cancel']); }); }); + + it('submits a programmatically set name and value', async function() { + const form = await createFixture(html` +
+ Save +
+ `); + const element = form.querySelector('pf-v6-button')!; + let submitData: FormData | null = null; + form.addEventListener('submit', function(event) { + event.preventDefault(); + submitData = new FormData(form); + }); + await element.updateComplete; + element.name = 'save'; + element.value = 'yes'; + await element.updateComplete; + await clickElementAtCenter(element); + expect(submitData).to.be.ok; + expect(submitData!.get('save')).to.equal('yes'); + }); }); describe('in a fieldset', function() { let element: PfV6Button; let fieldset: HTMLFieldSetElement; let form: HTMLFormElement; - let submitEvent: SubmitEvent; + let submitEvent: SubmitEvent | undefined; beforeEach(async function() { form = await createFixture(html` @@ -699,7 +863,6 @@ describe('', function() { }); afterEach(function() { - // @ts-expect-error: resetting fixture submitEvent = undefined; }); @@ -773,4 +936,45 @@ describe('', function() { }); }); }); + + describe('count badge in a fieldset', function() { + let element: PfV6Button; + let badge: PfV6Badge; + let fieldset: HTMLFieldSetElement; + + beforeEach(async function() { + const form = await createFixture(html` +
+
+ + Issues + 3 + +
+
+ `); + fieldset = form.querySelector('fieldset')!; + element = form.querySelector('pf-v6-button')!; + badge = element.querySelector('pf-v6-badge')!; + await element.updateComplete; + await badge.updateComplete; + }); + + it('disables the slotted badge when the fieldset is disabled', async function() { + fieldset.disabled = true; + await element.updateComplete; + await element.updateComplete; + expect(badge.hasAttribute('disabled'), 'badge disabled attribute').to.be.true; + }); + + it('re-enables the slotted badge when the fieldset is re-enabled', async function() { + fieldset.disabled = true; + await element.updateComplete; + await element.updateComplete; + fieldset.disabled = false; + await element.updateComplete; + await element.updateComplete; + expect(badge.hasAttribute('disabled'), 'badge disabled attribute').to.be.false; + }); + }); }); From 69bc5aac8149454a8bf71eb767a3adb0df19fbfc Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 9 Nov 2026 16:44:02 +0200 Subject: [PATCH 19/31] fix(core): harden combobox focusout, tabindex focus API, and submit fallback Address review findings: cancel the deferred listbox hide on disconnect and generation change, reuse the item list for the re-focus check so slotted options are recognized, add RovingTabindexController.focusItem for documented programmatic focus APIs and use it in chip groups, and rethrow non-TypeError failures from requestSubmit(submitter). Assisted-By: Claude Code --- .../controllers/combobox-controller.ts | 14 ++- .../controllers/internals-controller.ts | 5 +- .../controllers/roving-tabindex-controller.ts | 13 +++ .../test/at-focus-controller.spec.ts | 7 ++ .../test/combobox-controller.spec.ts | 88 ++++++++++++++++++- elements/pf-v5-chip/pf-v5-chip-group.ts | 4 +- 6 files changed, 126 insertions(+), 5 deletions(-) diff --git a/core/pfe-core/controllers/combobox-controller.ts b/core/pfe-core/controllers/combobox-controller.ts index b9b4afd9b3..b8f828d560 100644 --- a/core/pfe-core/controllers/combobox-controller.ts +++ b/core/pfe-core/controllers/combobox-controller.ts @@ -244,6 +244,7 @@ export class ComboboxController< #listbox: HTMLElement | null = null; #buttonInitialRole: string | null = null; #buttonHasMouseDown = false; + #focusoutGeneration = 0; #mo = new MutationObserver(() => this.#initItems()); #microcopy = new Map>(Object.entries({ dimmed: { @@ -375,6 +376,7 @@ export class ComboboxController< } hostDisconnected(): void { + this.#focusoutGeneration++; this.#fc?.hostDisconnected(); } @@ -777,9 +779,19 @@ export class ComboboxController< // Wait for the browser to finish moving focus (e.g. Tab out of the // listbox) before hiding it. Hiding while the focused option is // removed can cancel the focus move and leave focus on the combobox. + const generation = ++this.#focusoutGeneration; await new Promise(requestAnimationFrame); + if (generation !== this.#focusoutGeneration || !this.host.isConnected) { + return; + } } - if (this.options.isExpanded() && !this.#listbox?.contains(root.activeElement)) { + // Slotted options are not DOM descendants of the shadow listbox div, + // so check both the item list and `contains()`; focus on the toggle + // button is neither an item nor a listbox descendant, and should hide. + const { activeElement } = root; + if (this.options.isExpanded() + && !this.items.includes(activeElement as Item) + && !this.#listbox?.contains(activeElement)) { this.#hide(); } } diff --git a/core/pfe-core/controllers/internals-controller.ts b/core/pfe-core/controllers/internals-controller.ts index d5923deeeb..f6df66675f 100644 --- a/core/pfe-core/controllers/internals-controller.ts +++ b/core/pfe-core/controllers/internals-controller.ts @@ -341,8 +341,11 @@ export class InternalsController implements ReactiveController, ARIAMixin { try { form.requestSubmit(submitter); return; - } catch { + } catch (error) { // FACE hosts are not yet accepted as submitters in all engines. + if (!(error instanceof TypeError)) { + throw error; + } } } form.requestSubmit(); diff --git a/core/pfe-core/controllers/roving-tabindex-controller.ts b/core/pfe-core/controllers/roving-tabindex-controller.ts index dda994d035..e6ab5b13e1 100644 --- a/core/pfe-core/controllers/roving-tabindex-controller.ts +++ b/core/pfe-core/controllers/roving-tabindex-controller.ts @@ -56,6 +56,19 @@ export class RovingTabindexController< return !!container?.matches(':focus-within'); } + /** + * Sets assistive-technology focus to the item at `index` and moves DOM focus + * to it, even when focus is currently outside the widget. Use this for + * documented focus APIs; prefer the `atFocusedItemIndex` setter for keyboard + * navigation, which does not steal focus from outside the widget. + * @param index item index + */ + focusItem(index: number): void { + this.atFocusedItemIndex = index; + const item = this.items.at(this.atFocusedItemIndex); + item?.focus(); + } + get items() { return this._items; } diff --git a/core/pfe-core/controllers/test/at-focus-controller.spec.ts b/core/pfe-core/controllers/test/at-focus-controller.spec.ts index 95b4aedc8c..b1b009724e 100644 --- a/core/pfe-core/controllers/test/at-focus-controller.spec.ts +++ b/core/pfe-core/controllers/test/at-focus-controller.spec.ts @@ -295,6 +295,13 @@ describe('ATFocusController', function() { expect(items[0].tabIndex).to.equal(-1); expect(items[1].tabIndex).to.equal(0); }); + + it('moves DOM focus to the item via focusItem()', function() { + element.controller.focusItem(1); + expect(document.activeElement).to.equal(items[1]); + expect(items[1].tabIndex).to.equal(0); + expect(items[0].tabIndex).to.equal(-1); + }); }); }); }); diff --git a/core/pfe-core/controllers/test/combobox-controller.spec.ts b/core/pfe-core/controllers/test/combobox-controller.spec.ts index 63e5fc0356..1fc637b411 100644 --- a/core/pfe-core/controllers/test/combobox-controller.spec.ts +++ b/core/pfe-core/controllers/test/combobox-controller.spec.ts @@ -4,7 +4,7 @@ import { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; import { customElement } from 'lit/decorators/custom-element.js'; import { query } from 'lit/decorators/query.js'; -import { ReactiveElement, html, render, type PropertyValues, type TemplateResult } from 'lit'; +import { LitElement, ReactiveElement, html, render, type PropertyValues, type TemplateResult } from 'lit'; import { ComboboxController } from '../combobox-controller.js'; @@ -303,8 +303,94 @@ class XComboboxShadow extends TestCombobox { } } +/** + * Toggle-button-only combobox (no text input): listbox items receive DOM focus. + */ +@customElement('x-combobox-toggle') +class XComboboxToggle extends LitElement { + static template = html` + +
1
+
2
+
3
+
+ `; + + hideCount = 0; + + controller = ComboboxController.of(this, { + getItems: () => [...this.querySelectorAll('.opt')], + isItem: (item): item is HTMLElement => + item instanceof HTMLElement && item.classList.contains('opt'), + getFallbackLabel: () => 'options', + getListboxElement: () => this.listbox ?? null, + getToggleButton: () => this.button ?? null, + getComboboxInput: () => null, + isExpanded: () => !this.listbox.hidden, + requestShowListbox: () => void (this.listbox.hidden = false), + requestHideListbox: () => void (this.hideCount += 1, this.listbox.hidden = true), + }); + + @query('#listbox') listbox!: HTMLElement; + @query('#button') button!: HTMLButtonElement; + + get options(): HTMLElement[] { + return [...this.querySelectorAll('.opt')]; + } + + override render(): TemplateResult { + return html` + + `; + } +} + describe('ComboboxController', function() { describe('Cross-root ARIA', XComboboxCrossRoot.test.bind(XComboboxCrossRoot)); describe('Light-DOM only', XComboboxLight.test.bind(XComboboxLight)); describe('Shadow-DOM only', XComboboxShadow.test.bind(XComboboxShadow)); + + describe('listbox focusout', function() { + let element: XComboboxToggle; + + beforeEach(async function() { + element = await fixture(XComboboxToggle.template); + // open the listbox and focus the first option + element.button.click(); + await element.updateComplete; + element.options[0]!.focus(); + }); + + function nextFrame() { + return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); + } + + it('hides the listbox one frame after focus leaves it', async function() { + expect(element.listbox.hidden, 'listbox starts expanded').to.be.false; + await sendKeys({ press: 'Tab' }); + await nextFrame(); + expect(element.listbox.hidden, 'listbox hides after the frame').to.be.true; + expect(element.hideCount).to.equal(1); + }); + + it('does not hide when focus returns to an item within the frame', async function() { + expect(element.listbox.hidden, 'listbox starts expanded').to.be.false; + // focusout with focus headed outside the element ... + element.options[0]!.dispatchEvent(new FocusEvent('focusout', { bubbles: true })); + // ... but focus lands on another item before the pending frame resolves + element.options[1]!.focus(); + await nextFrame(); + expect(element.listbox.hidden, 'listbox stays expanded').to.be.false; + expect(element.hideCount).to.equal(0); + }); + + it('does not throw or hide when the host disconnects during the pending frame', async function() { + expect(element.listbox.hidden, 'listbox starts expanded').to.be.false; + element.options[0]!.dispatchEvent(new FocusEvent('focusout', { bubbles: true })); + element.remove(); + await nextFrame(); + expect(element.hideCount, 'no hide after disconnect').to.equal(0); + expect(element.listbox.hidden, 'listbox stays expanded').to.be.false; + }); + }); }); diff --git a/elements/pf-v5-chip/pf-v5-chip-group.ts b/elements/pf-v5-chip/pf-v5-chip-group.ts index 6652e027e6..c014a8c7e1 100644 --- a/elements/pf-v5-chip/pf-v5-chip-group.ts +++ b/elements/pf-v5-chip/pf-v5-chip-group.ts @@ -117,7 +117,7 @@ export class PfV5ChipGroup extends LitElement { set activeChip(chip: HTMLElement) { const button = chip.shadowRoot?.querySelector('button'); if (button) { - this.#tabindex.atFocusedItemIndex = this.#tabindex.items.indexOf(button); + this.#tabindex.focusItem(this.#tabindex.items.indexOf(button)); } } @@ -234,7 +234,7 @@ export class PfV5ChipGroup extends LitElement { * @param chip pf-v5-chip element */ focusOnChip(chip: PfV5Chip): void { - this.#tabindex.atFocusedItemIndex = this.#tabindex.items.indexOf(chip); + this.#tabindex.focusItem(this.#tabindex.items.indexOf(chip)); } } From 6493db4ffd24b82532f3835425da9fdc42d7901b Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 9 Nov 2026 16:44:12 +0200 Subject: [PATCH 20/31] fix: correct migrated v6 button demos and alert close label Add type=submit to migrated form controls that relied on the implicit v5 submit behavior, use variant=danger for the tabs demo delete button, and label the icon-only alert close button. These demos and the alert would otherwise render non-submitting controls or unlabeled buttons. Assisted-By: Claude Code --- elements/pf-v5-alert/pf-v5-alert.ts | 1 + elements/pf-v5-jump-links/demo/scrollspy-with-subsections.html | 2 +- elements/pf-v5-search-input/demo/disabled.html | 2 +- .../pf-v5-search-input/demo/pf-search-input-with-submit.html | 2 +- elements/pf-v5-tabs/demo/dynamic-tabs.html | 2 +- elements/pf-v5-text-area/demo/validated.html | 2 +- elements/pf-v5-text-input/demo/validation.html | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/elements/pf-v5-alert/pf-v5-alert.ts b/elements/pf-v5-alert/pf-v5-alert.ts index 12d4dc4ce7..1e0565e508 100644 --- a/elements/pf-v5-alert/pf-v5-alert.ts +++ b/elements/pf-v5-alert/pf-v5-alert.ts @@ -165,6 +165,7 @@ export class PfV5Alert extends LitElement { Heading 4
- Submit + Submit

At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum diff --git a/elements/pf-v5-search-input/demo/disabled.html b/elements/pf-v5-search-input/demo/disabled.html index 4346853f90..282845c3bf 100644 --- a/elements/pf-v5-search-input/demo/disabled.html +++ b/elements/pf-v5-search-input/demo/disabled.html @@ -11,7 +11,7 @@ Red Yellow - Search + Search diff --git a/elements/pf-v5-search-input/demo/pf-search-input-with-submit.html b/elements/pf-v5-search-input/demo/pf-search-input-with-submit.html index c72368c40b..dc7f3eec9b 100644 --- a/elements/pf-v5-search-input/demo/pf-search-input-with-submit.html +++ b/elements/pf-v5-search-input/demo/pf-search-input-with-submit.html @@ -22,7 +22,7 @@ New Mexico 3 North Carolina 3 - Search + Search diff --git a/elements/pf-v5-tabs/demo/dynamic-tabs.html b/elements/pf-v5-tabs/demo/dynamic-tabs.html index db041ef51a..d3caa8aad4 100644 --- a/elements/pf-v5-tabs/demo/dynamic-tabs.html +++ b/elements/pf-v5-tabs/demo/dynamic-tabs.html @@ -4,7 +4,7 @@ Add Tab - + Delete Tab diff --git a/elements/pf-v5-text-area/demo/validated.html b/elements/pf-v5-text-area/demo/validated.html index a4744e5542..727c79b68a 100644 --- a/elements/pf-v5-text-area/demo/validated.html +++ b/elements/pf-v5-text-area/demo/validated.html @@ -1,6 +1,6 @@

- Validate + Validate