diff --git a/packages/components/button/src/Button/Button.module.scss b/packages/components/button/src/Button/Button.module.scss index ad95129ef4..9536fbfc99 100644 --- a/packages/components/button/src/Button/Button.module.scss +++ b/packages/components/button/src/Button/Button.module.scss @@ -2,6 +2,75 @@ $disabled-on-primary-color-opacity: 0.5; +// Tri-state pattern: a color modifier with three states (Active class, :hover, :focus) +// all sharing the same background. Generates two rules: +// .#{$class} { ...defaults } +// .#{$class}Active, .#{$class}:hover, .#{$class}:focus { background: $bg-active } +@mixin solid-tristate($class, $bg, $bg-active, $fg: null) { + &.#{$class} { + background: $bg; + @if $fg != null { + color: $fg; + } + } + + &.#{$class}Active, + &.#{$class}:hover, + &.#{$class}:focus { + background: $bg-active; + } +} + +// Outlined variant (kindSecondary): sets fg color + border-color, tri-state bg. +@mixin outlined-tristate($class, $color, $bg-active) { + &.#{$class} { + color: $color; + border-color: $color; + } + + &.#{$class}Active, + &.#{$class}:hover, + &.#{$class}:focus { + background: $bg-active; + } +} + +// Flat variant (kindTertiary): sets fg color only, tri-state bg. +@mixin flat-tristate($class, $color, $bg-active) { + &.#{$class} { + color: $color; + } + + &.#{$class}Active, + &.#{$class}:hover, + &.#{$class}:focus { + background: $bg-active; + } +} + +// Brightness overlay tri-state used by onPrimaryColor / fixedLight on all kinds. +// $literal-bg, when given, is set as a literal background-color (used by kindPrimary +// to overlay #e6e9ef before the brightness filter). +@mixin brightness-overlay-tristate($class, $literal-bg: null) { + &.#{$class}Active, + &.#{$class}:hover, + &.#{$class}:focus { + @if $literal-bg != null { + background-color: $literal-bg; + } + backdrop-filter: brightness(85%); + @include focus-style-on-primary(); + } +} + +// `.disabled` with the opacity-on-primary-color pattern. +@mixin disabled-with-opacity($class, $fg) { + &.#{$class}.disabled { + opacity: $disabled-on-primary-color-opacity; + color: $fg; + } +} + .button { --loader-padding: 8px; outline: none; @@ -129,138 +198,70 @@ $disabled-on-primary-color-opacity: 0.5; .kindPrimary { color: var(--text-color-on-primary); -} - -.kindPrimary.colorPrimary { - background: var(--primary-color); -} - -.kindPrimary.colorBrand { - background: var(--brand-color); - color: var(--text-color-on-brand); -} - -.kindPrimary.colorPrimaryActive, -.kindPrimary.colorPrimary:hover, -.kindPrimary.colorPrimary:focus { - background: var(--primary-hover-color); -} - -.kindPrimary.colorBrandActive, -.kindPrimary.colorBrand:hover, -.kindPrimary.colorBrand:focus { - background: var(--brand-hover-color); -} - -.kindPrimary.colorPositive { - background: var(--positive-color); -} - -.kindPrimary.colorPositiveActive, -.kindPrimary.colorPositive:hover, -.kindPrimary.colorPositive:focus { - background: var(--positive-color-hover); -} - -.kindPrimary.colorNegative { - background: var(--negative-color); -} - -.kindPrimary.colorNegativeActive, -.kindPrimary.colorNegative:hover, -.kindPrimary.colorNegative:focus { - background: var(--negative-color-hover); -} - -.kindPrimary.colorInverted { - background: var(--inverted-color-background); - color: var(--text-color-on-inverted); -} - -.kindPrimary.colorInvertedActive, -.kindPrimary.colorInverted:hover, -.kindPrimary.colorInverted:focus { - background: var(--placeholder-color); -} - -.kindPrimary.button.colorInverted.disabled { - background: var(--disabled-text-color); - color: var(--disabled-background-color); -} -.kindPrimary.colorOnPrimaryColor { - background: var(--text-color-on-primary); -} - -.kindPrimary.colorOnPrimaryColorActive, -.kindPrimary.colorOnPrimaryColor:hover, -.kindPrimary.colorOnPrimaryColor:focus { - background-color: #e6e9ef; - backdrop-filter: brightness(85%); - @include focus-style-on-primary(); -} + @include solid-tristate(colorPrimary, var(--primary-color), var(--primary-hover-color)); + @include solid-tristate(colorBrand, var(--brand-color), var(--brand-hover-color), var(--text-color-on-brand)); + @include solid-tristate(colorPositive, var(--positive-color), var(--positive-color-hover)); + @include solid-tristate(colorNegative, var(--negative-color), var(--negative-color-hover)); + @include solid-tristate( + colorInverted, + var(--inverted-color-background), + var(--placeholder-color), + var(--text-color-on-inverted) + ); + + &.button.colorInverted.disabled { + background: var(--disabled-text-color); + color: var(--disabled-background-color); + } -.kindPrimary.colorOnPrimaryColor.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--text-color-on-primary); -} + &.colorOnPrimaryColor { + background: var(--text-color-on-primary); + } -.kindPrimary.colorFixedLight { - background: var(--fixed-light-color); -} + @include brightness-overlay-tristate(colorOnPrimaryColor, #e6e9ef); + @include disabled-with-opacity(colorOnPrimaryColor, var(--text-color-on-primary)); -.kindPrimary.colorFixedLightActive, -.kindPrimary.colorFixedLight:hover, -.kindPrimary.colorFixedLight:focus { - background-color: #e6e9ef; - backdrop-filter: brightness(85%); - @include focus-style-on-primary(); -} + &.colorFixedLight { + background: var(--fixed-light-color); + } -.kindPrimary.colorFixedLight.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--fixed-light-color); -} + @include brightness-overlay-tristate(colorFixedLight, #e6e9ef); + @include disabled-with-opacity(colorFixedLight, var(--fixed-light-color)); -.kindPrimary.colorFixedDark { - background: var(--fixed-dark-color); - color: var(--fixed-light-color); -} + &.colorFixedDark { + background: var(--fixed-dark-color); + color: var(--fixed-light-color); + } -.kindPrimary.colorFixedDarkActive, -.kindPrimary.colorFixedDark:hover, -.kindPrimary.colorFixedDark:focus { - filter: brightness(125%); - @include focus-style-on-primary(); -} + &.colorFixedDarkActive, + &.colorFixedDark:hover, + &.colorFixedDark:focus { + filter: brightness(125%); + @include focus-style-on-primary(); + } -.kindPrimary.colorFixedDark.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--fixed-dark-color); -} + @include disabled-with-opacity(colorFixedDark, var(--fixed-dark-color)); -.kindPrimary.colorOnInvertedBackground { - background: var(--primary-background-color); - color: var(--primary-text-color); -} + @include solid-tristate( + colorOnInvertedBackground, + var(--primary-background-color), + var(--ui-background-color), + var(--primary-text-color) + ); -.kindPrimary.colorOnInvertedBackgroundActive, -.kindPrimary.colorOnInvertedBackground:hover, -.kindPrimary.colorOnInvertedBackground:focus { - background: var(--ui-background-color); -} - -.kindPrimary.button.colorOnInvertedBackground.disabled { - background: var(--ui-background-color); - color: var(--primary-text-color); - opacity: $disabled-on-primary-color-opacity; -} + &.button.colorOnInvertedBackground.disabled { + background: var(--ui-background-color); + color: var(--primary-text-color); + opacity: $disabled-on-primary-color-opacity; + } -.kindPrimary.button.disabled { - background: var(--disabled-background-color); - color: var(--disabled-text-color); - cursor: not-allowed; - pointer-events: none; + &.button.disabled { + background: var(--disabled-background-color); + color: var(--disabled-text-color); + cursor: not-allowed; + pointer-events: none; + } } .kindSecondary { @@ -268,305 +269,183 @@ $disabled-on-primary-color-opacity: 0.5; border-color: var(--ui-border-color); color: var(--primary-text-color); background-color: transparent; -} - -.kindSecondary.sizeSmall { - line-height: 22px; -} - -.kindSecondary.sizeMedium { - line-height: 22px; -} - -.kindSecondary.sizeLarge { - line-height: 22px; -} - -.kindSecondary.colorPrimaryActive { - background-color: var(--primary-selected-color); - border-color: var(--primary-color); -} - -.kindSecondary.colorPrimaryActive:hover { - background-color: var(--primary-selected-hover-color); - border-color: var(--primary-color); -} - -.kindSecondary.colorBrandActive { - color: var(--text-color-on-brand); -} - -.kindSecondary.colorBrandActive, -.kindSecondary.colorBrandActive:hover { - background-color: var(--brand-selected-color); - border-color: var(--brand-color); -} - -.kindSecondary.colorPrimary:hover:not(.colorPrimaryActive), -.kindSecondary.colorPrimary:focus:not(.colorPrimaryActive) { - background: var(--primary-background-hover-color); -} - -.kindSecondary.colorBrand:hover:not(.colorBrandActive), -.kindSecondary.colorBrand:focus:not(.colorBrandActive) { - background: var(--primary-background-hover-color); -} - -.kindSecondary.colorPositive { - color: var(--positive-color); - border-color: var(--positive-color); -} -.kindSecondary.colorPositiveActive, -.kindSecondary.colorPositive:hover, -.kindSecondary.colorPositive:focus { - background: var(--positive-color-selected); -} - -.kindSecondary.colorNegative { - color: var(--negative-color); - border-color: var(--negative-color); -} + &.sizeSmall, + &.sizeMedium, + &.sizeLarge { + line-height: 22px; + } -.kindSecondary.colorNegativeActive, -.kindSecondary.colorNegative:hover, -.kindSecondary.colorNegative:focus { - background: var(--negative-color-selected); -} + &.colorPrimaryActive { + background-color: var(--primary-selected-color); + border-color: var(--primary-color); + } -.kindSecondary.colorInverted { - color: var(--primary-text-color); - border-color: var(--primary-text-color); -} + &.colorPrimaryActive:hover { + background-color: var(--primary-selected-hover-color); + border-color: var(--primary-color); + } -.kindSecondary.colorInvertedActive, -.kindSecondary.colorInverted:hover, -.kindSecondary.colorInverted:focus { - background: var(--primary-background-hover-color); -} + &.colorBrandActive { + color: var(--text-color-on-brand); + } -.kindSecondary.colorInverted.disabled { - border-color: var(--disabled-text-color); - color: var(--disabled-text-color); -} + &.colorBrandActive, + &.colorBrandActive:hover { + background-color: var(--brand-selected-color); + border-color: var(--brand-color); + } -.kindSecondary.colorOnPrimaryColor { - color: var(--text-color-on-primary); - border-color: var(--text-color-on-primary); -} + &.colorPrimary:hover:not(.colorPrimaryActive), + &.colorPrimary:focus:not(.colorPrimaryActive), + &.colorBrand:hover:not(.colorBrandActive), + &.colorBrand:focus:not(.colorBrandActive) { + background: var(--primary-background-hover-color); + } -.kindSecondary.colorOnPrimaryColorActive, -.kindSecondary.colorOnPrimaryColor:hover, -.kindSecondary.colorOnPrimaryColor:focus { - backdrop-filter: brightness(85%); - @include focus-style-on-primary(); -} + @include outlined-tristate(colorPositive, var(--positive-color), var(--positive-color-selected)); + @include outlined-tristate(colorNegative, var(--negative-color), var(--negative-color-selected)); + @include outlined-tristate(colorInverted, var(--primary-text-color), var(--primary-background-hover-color)); -.kindSecondary.colorOnPrimaryColor.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--text-color-on-primary); -} + &.colorInverted.disabled { + border-color: var(--disabled-text-color); + color: var(--disabled-text-color); + } -.kindSecondary.colorFixedLight { - border-color: var(--fixed-light-color); - color: var(--fixed-light-color); -} + &.colorOnPrimaryColor { + color: var(--text-color-on-primary); + border-color: var(--text-color-on-primary); + } -.kindSecondary.colorFixedLightActive, -.kindSecondary.colorFixedLight:hover, -.kindSecondary.colorFixedLight:focus { - backdrop-filter: brightness(85%); - @include focus-style-on-primary(); -} + @include brightness-overlay-tristate(colorOnPrimaryColor); + @include disabled-with-opacity(colorOnPrimaryColor, var(--text-color-on-primary)); -.kindSecondary.colorFixedDark { - border-color: var(--fixed-dark-color); - color: var(--fixed-dark-color); -} + &.colorFixedLight { + border-color: var(--fixed-light-color); + color: var(--fixed-light-color); + } -.kindSecondary.colorFixedDarkActive, -.kindSecondary.colorFixedDark:hover, -.kindSecondary.colorFixedDark:focus { - background-color: var(--primary-background-hover-color); - @include focus-style-on-primary(); -} + @include brightness-overlay-tristate(colorFixedLight); -.kindSecondary.colorOnInvertedBackground { - border-color: var(--text-color-on-inverted); - color: var(--text-color-on-inverted); -} + &.colorFixedDark { + border-color: var(--fixed-dark-color); + color: var(--fixed-dark-color); + } -.kindSecondary.colorOnInvertedBackgroundActive, -.kindSecondary.colorOnInvertedBackground:hover, -.kindSecondary.colorOnInvertedBackground:focus { - background: var(--icon-color); -} + &.colorFixedDarkActive, + &.colorFixedDark:hover, + &.colorFixedDark:focus { + background-color: var(--primary-background-hover-color); + @include focus-style-on-primary(); + } -.kindSecondary.colorOnInvertedBackground.disabled { - border-color: var(--text-color-on-inverted); - color: var(--text-color-on-inverted); - opacity: $disabled-on-primary-color-opacity; -} + @include outlined-tristate( + colorOnInvertedBackground, + var(--text-color-on-inverted), + var(--icon-color) + ); -.kindSecondary.colorFixedLight.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--fixed-light-color); -} + &.colorOnInvertedBackground.disabled { + border-color: var(--text-color-on-inverted); + color: var(--text-color-on-inverted); + opacity: $disabled-on-primary-color-opacity; + } -.kindSecondary.colorFixedDark.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--fixed-dark-color); -} + @include disabled-with-opacity(colorFixedLight, var(--fixed-light-color)); + @include disabled-with-opacity(colorFixedDark, var(--fixed-dark-color)); -.kindSecondary.disabled { - border-color: var(--disabled-text-color); - color: var(--disabled-text-color); - cursor: not-allowed; - pointer-events: none; -} + &.disabled { + border-color: var(--disabled-text-color); + color: var(--disabled-text-color); + cursor: not-allowed; + pointer-events: none; + } -.kindSecondary.disabled:hover { - background-color: transparent; + &.disabled:hover { + background-color: transparent; + } } .kindTertiary { color: var(--primary-text-color); background-color: transparent; -} - -.kindTertiary.colorPrimaryActive { - background-color: var(--primary-selected-color); -} -.kindTertiary.colorPrimaryActive:hover { - background-color: var(--primary-selected-hover-color); -} - -.kindTertiary.colorBrandActive { - color: var(--text-color-on-brand); -} - -.kindTertiary.colorBrandActive, -.kindTertiary.colorBrandActive:hover { - background-color: var(--brand-selected-color); -} - -.kindTertiary.colorPrimary:hover:not(.colorPrimaryActive), -.kindTertiary.colorPrimary:focus:not(.colorPrimaryActive) { - background: var(--primary-background-hover-color); -} - -.kindTertiary.colorBrand:hover:not(.colorBrandActive), -.kindTertiary.colorBrand:focus:not(.colorBrandActive) { - background: var(--primary-background-hover-color); -} - -.kindTertiary.colorPositive { - color: var(--positive-color); -} - -.kindTertiary.colorPositiveActive, -.kindTertiary.colorPositive:hover, -.kindTertiary.colorPositive:focus { - background: var(--positive-color-selected); -} - -.kindTertiary.colorNegative { - color: var(--negative-color); -} + &.colorPrimaryActive { + background-color: var(--primary-selected-color); + } -.kindTertiary.colorNegativeActive, -.kindTertiary.colorNegative:hover, -.kindTertiary.colorNegative:focus { - background: var(--negative-color-selected); -} + &.colorPrimaryActive:hover { + background-color: var(--primary-selected-hover-color); + } -.kindTertiary.colorInverted { - color: var(--primary-text-color); -} + &.colorBrandActive { + color: var(--text-color-on-brand); + } -.kindTertiary.colorInvertedActive, -.kindTertiary.colorInverted:hover, -.kindTertiary.colorInverted:focus { - background: var(--primary-background-hover-color); -} + &.colorBrandActive, + &.colorBrandActive:hover { + background-color: var(--brand-selected-color); + } -.kindTertiary.colorInverted.disabled { - color: var(--disabled-text-color); -} + &.colorPrimary:hover:not(.colorPrimaryActive), + &.colorPrimary:focus:not(.colorPrimaryActive), + &.colorBrand:hover:not(.colorBrandActive), + &.colorBrand:focus:not(.colorBrandActive) { + background: var(--primary-background-hover-color); + } -.kindTertiary.colorOnPrimaryColor { - color: var(--text-color-on-primary); -} + @include flat-tristate(colorPositive, var(--positive-color), var(--positive-color-selected)); + @include flat-tristate(colorNegative, var(--negative-color), var(--negative-color-selected)); + @include flat-tristate(colorInverted, var(--primary-text-color), var(--primary-background-hover-color)); -.kindTertiary.colorOnPrimaryColorActive, -.kindTertiary.colorOnPrimaryColor:hover, -.kindTertiary.colorOnPrimaryColor:focus { - backdrop-filter: brightness(85%); - @include focus-style-on-primary(); -} + &.colorInverted.disabled { + color: var(--disabled-text-color); + } -.kindTertiary.colorOnPrimaryColor.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--text-color-on-primary); -} + &.colorOnPrimaryColor { + color: var(--text-color-on-primary); + } -.kindTertiary.colorFixedLight { - color: var(--fixed-light-color); -} + @include brightness-overlay-tristate(colorOnPrimaryColor); + @include disabled-with-opacity(colorOnPrimaryColor, var(--text-color-on-primary)); -.kindTertiary.colorFixedLightActive, -.kindTertiary.colorFixedLight:hover, -.kindTertiary.colorFixedLight:focus { - backdrop-filter: brightness(85%); - @include focus-style-on-primary(); -} + &.colorFixedLight { + color: var(--fixed-light-color); + } -.kindTertiary.colorFixedLight.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--fixed-light-color); -} + @include brightness-overlay-tristate(colorFixedLight); + @include disabled-with-opacity(colorFixedLight, var(--fixed-light-color)); -.kindTertiary.colorFixedDark { - color: var(--fixed-dark-color); -} - -.kindTertiary.colorFixedDarkActive, -.kindTertiary.colorFixedDark:hover, -.kindTertiary.colorFixedDark:focus { - background-color: var(--primary-background-hover-color); - @include focus-style-on-primary(); -} + &.colorFixedDark { + color: var(--fixed-dark-color); + } -.kindTertiary.colorFixedDark.disabled { - opacity: $disabled-on-primary-color-opacity; - color: var(--fixed-dark-color); -} + &.colorFixedDarkActive, + &.colorFixedDark:hover, + &.colorFixedDark:focus { + background-color: var(--primary-background-hover-color); + @include focus-style-on-primary(); + } -.kindTertiary.colorOnInvertedBackground { - color: var(--text-color-on-inverted); -} + @include disabled-with-opacity(colorFixedDark, var(--fixed-dark-color)); -.kindTertiary.colorOnInvertedBackgroundActive, -.kindTertiary.colorOnInvertedBackground:hover, -.kindTertiary.colorOnInvertedBackground:focus { - background: var(--icon-color); -} + @include flat-tristate(colorOnInvertedBackground, var(--text-color-on-inverted), var(--icon-color)); -.kindTertiary.colorOnInvertedBackground.disabled { - background: var(--icon-color); - opacity: $disabled-on-primary-color-opacity; - color: var(--text-color-on-inverted); -} + &.colorOnInvertedBackground.disabled { + background: var(--icon-color); + opacity: $disabled-on-primary-color-opacity; + color: var(--text-color-on-inverted); + } -.kindTertiary.disabled { - color: var(--disabled-text-color); - cursor: not-allowed; - pointer-events: none; -} + &.disabled { + color: var(--disabled-text-color); + cursor: not-allowed; + pointer-events: none; + } -.kindTertiary.disabled:hover { - background-color: transparent; + &.disabled:hover { + background-color: transparent; + } } .noSidePadding {