Buttons: Active style for buttons (#111235)
* chore: initial tweaks * chore: remove shadow * chore: add reduced motion support, clean up * chore: clean * chore: active states tweaks * Buttons: Add active state / style * Update ToolbarButton and IconButton * Update * Update * Get rid of important on disabled styles * Only color for active * Remove transform bits --------- Co-authored-by: Galen <galen.kistler@grafana.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import * as React from 'react';
|
||||
import { GrafanaTheme2, ThemeRichColor } from '@grafana/data';
|
||||
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
|
||||
import { getButtonFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
|
||||
import { IconName, IconSize, IconType } from '../../types/icon';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { getPropertiesForButtonSize } from '../Forms/commonStyles';
|
||||
@@ -234,7 +234,7 @@ export const getButtonStyles = (props: StyleProps) => {
|
||||
const { height, padding, fontSize } = getPropertiesForButtonSize(size, theme);
|
||||
const variantStyles = getPropertiesForVariant(theme, variant, fill);
|
||||
const disabledStyles = getPropertiesForDisabled(theme, variant, fill);
|
||||
const focusStyle = getFocusStyles(theme);
|
||||
const focusStyle = getButtonFocusStyles(theme);
|
||||
const paddingMinusBorder = theme.spacing.gridSize * padding - 1;
|
||||
|
||||
return {
|
||||
@@ -263,6 +263,12 @@ export const getButtonStyles = (props: StyleProps) => {
|
||||
...variantStyles,
|
||||
':disabled': disabledStyles,
|
||||
'&[disabled]': disabledStyles,
|
||||
|
||||
[theme.transitions.handleMotion('no-preference', 'reduce')]: {
|
||||
transition: theme.transitions.create(['background-color', 'border-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
disabled: css(disabledStyles, {
|
||||
'&:hover': css(disabledStyles),
|
||||
@@ -290,12 +296,18 @@ export const getButtonStyles = (props: StyleProps) => {
|
||||
};
|
||||
};
|
||||
|
||||
function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fill: ButtonFill) {
|
||||
export function getActiveButtonStyles(color: ThemeRichColor, fill: ButtonFill) {
|
||||
return {
|
||||
background: fill === 'solid' ? color.main : 'transparent',
|
||||
};
|
||||
}
|
||||
|
||||
export function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fill: ButtonFill) {
|
||||
let outlineBorderColor = color.border;
|
||||
let borderColor = 'transparent';
|
||||
let hoverBorderColor = 'transparent';
|
||||
|
||||
// Secondary button has some special rules as we lack theem color token to
|
||||
// Secondary button has some special rules as we lack the color token to
|
||||
// specify border color for normal button vs border color for outline button
|
||||
if (color.name === 'secondary') {
|
||||
borderColor = color.border;
|
||||
@@ -308,15 +320,16 @@ function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fil
|
||||
background: 'transparent',
|
||||
color: color.text,
|
||||
border: `1px solid ${outlineBorderColor}`,
|
||||
transition: theme.transitions.create(['background-color', 'border-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
'&:hover': {
|
||||
'&:hover, &:focus': {
|
||||
background: color.transparent,
|
||||
borderColor: theme.colors.emphasize(outlineBorderColor, 0.25),
|
||||
color: color.text,
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
...getActiveButtonStyles(color, fill),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -325,18 +338,15 @@ function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fil
|
||||
background: 'transparent',
|
||||
color: color.text,
|
||||
border: '1px solid transparent',
|
||||
transition: theme.transitions.create(['background-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
'&:focus': {
|
||||
outline: 'none',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
|
||||
'&:hover': {
|
||||
'&:hover, &:focus': {
|
||||
background: color.transparent,
|
||||
textDecoration: 'none',
|
||||
outline: 'none',
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
...getActiveButtonStyles(color, fill),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -345,9 +355,6 @@ function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fil
|
||||
background: color.main,
|
||||
color: color.contrastText,
|
||||
border: `1px solid ${borderColor}`,
|
||||
transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
'&:hover': {
|
||||
background: color.shade,
|
||||
@@ -355,6 +362,15 @@ function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fil
|
||||
boxShadow: theme.shadows.z1,
|
||||
borderColor: hoverBorderColor,
|
||||
},
|
||||
|
||||
'&:focus': {
|
||||
background: color.shade,
|
||||
color: color.contrastText,
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
...getActiveButtonStyles(color, fill),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -364,6 +380,7 @@ function getPropertiesForDisabled(theme: GrafanaTheme2, variant: ButtonVariant,
|
||||
boxShadow: 'none',
|
||||
color: theme.colors.text.disabled,
|
||||
transition: 'none',
|
||||
background: theme.colors.action.disabledBackground,
|
||||
};
|
||||
|
||||
if (fill === 'text') {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import * as React from 'react';
|
||||
|
||||
import { GrafanaTheme2, colorManipulator, deprecationWarning } from '@grafana/data';
|
||||
import { GrafanaTheme2, deprecationWarning } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
|
||||
import { IconName, IconSize, IconType } from '../../types/icon';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { IconRenderer } from '../Button/Button';
|
||||
import { getActiveButtonStyles, IconRenderer } from '../Button/Button';
|
||||
import { getSvgSize } from '../Icon/utils';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { PopoverContent, TooltipPlacement } from '../Tooltip/types';
|
||||
@@ -107,13 +107,17 @@ const getStyles = (theme: GrafanaTheme2, size: IconSize, variant: IconButtonVari
|
||||
// overall size of the IconButton on hover
|
||||
// theme.spacing.gridSize originates from 2*4px for padding and letting the IconSize generally decide on the hoverSize
|
||||
const hoverSize = getSvgSize(size) + theme.spacing.gridSize;
|
||||
const activeButtonStyle = getActiveButtonStyles(theme.colors.secondary, 'text');
|
||||
|
||||
let iconColor = theme.colors.text.primary;
|
||||
let iconColor = theme.colors.primary.text;
|
||||
let hoverColor = theme.colors.primary.transparent;
|
||||
|
||||
if (variant === 'primary') {
|
||||
iconColor = theme.colors.primary.text;
|
||||
if (variant === 'secondary') {
|
||||
iconColor = theme.colors.secondary.text;
|
||||
hoverColor = theme.colors.secondary.transparent;
|
||||
} else if (variant === 'destructive') {
|
||||
iconColor = theme.colors.error.text;
|
||||
hoverColor = theme.colors.error.transparent;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -129,11 +133,21 @@ const getStyles = (theme: GrafanaTheme2, size: IconSize, variant: IconButtonVari
|
||||
alignItems: 'center',
|
||||
padding: 0,
|
||||
color: iconColor,
|
||||
borderRadius: theme.shape.radius.default,
|
||||
|
||||
'&:active': {
|
||||
'&:before, &:hover:before': {
|
||||
backgroundColor: activeButtonStyle.background,
|
||||
},
|
||||
},
|
||||
|
||||
'&[disabled], &:disabled': {
|
||||
cursor: 'not-allowed',
|
||||
color: theme.colors.action.disabledText,
|
||||
opacity: 0.65,
|
||||
'&:hover:before': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
},
|
||||
|
||||
'&:before': {
|
||||
@@ -155,12 +169,9 @@ const getStyles = (theme: GrafanaTheme2, size: IconSize, variant: IconButtonVari
|
||||
|
||||
'&:focus:not(:focus-visible)': getMouseFocusStyles(theme),
|
||||
|
||||
'&:hover': {
|
||||
'&:before': {
|
||||
backgroundColor:
|
||||
variant === 'secondary' ? theme.colors.action.hover : colorManipulator.alpha(iconColor, 0.12),
|
||||
opacity: 1,
|
||||
},
|
||||
'&:hover:before': {
|
||||
backgroundColor: hoverColor,
|
||||
opacity: 1,
|
||||
},
|
||||
}),
|
||||
icon: css({
|
||||
|
||||
@@ -8,7 +8,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { getFocusStyles, getMouseFocusStyles, mediaUp } from '../../themes/mixins';
|
||||
import { IconSize } from '../../types/icon';
|
||||
import { getPropertiesForVariant } from '../Button/Button';
|
||||
import { getActiveButtonStyles, getPropertiesForVariant } from '../Button/Button';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
|
||||
@@ -134,11 +134,15 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
color: theme.colors.text.primary,
|
||||
background: theme.colors.secondary.main,
|
||||
|
||||
'&:hover': {
|
||||
'&:hover, &:focus': {
|
||||
color: theme.colors.text.primary,
|
||||
background: theme.colors.secondary.shade,
|
||||
border: `1px solid ${theme.colors.border.medium}`,
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
...getActiveButtonStyles(theme.colors.secondary, 'solid'),
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -155,7 +159,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
border: `1px solid ${theme.colors.secondary.border}`,
|
||||
whiteSpace: 'nowrap',
|
||||
[theme.transitions.handleMotion('no-preference', 'reduce')]: {
|
||||
transition: theme.transitions.create(['background', 'box-shadow', 'border-color', 'color'], {
|
||||
transition: theme.transitions.create(['background-color', 'border-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
},
|
||||
@@ -189,10 +193,14 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
background: 'transparent',
|
||||
border: `1px solid transparent`,
|
||||
|
||||
'&:hover': {
|
||||
'&:hover, &:focus': {
|
||||
color: theme.colors.text.primary,
|
||||
background: theme.colors.action.hover,
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
...getActiveButtonStyles(theme.colors.secondary, 'solid'),
|
||||
},
|
||||
}),
|
||||
canvas: defaultOld,
|
||||
active: cx(
|
||||
|
||||
@@ -72,6 +72,13 @@ export function getFocusStyles(theme: GrafanaTheme2) {
|
||||
};
|
||||
}
|
||||
|
||||
export function getButtonFocusStyles(theme: GrafanaTheme2) {
|
||||
return {
|
||||
...getFocusStyles(theme),
|
||||
transitionProperty: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// max-width is set up based on .grafana-tooltip class that's used in dashboard
|
||||
export const getTooltipContainerStyles = (theme: GrafanaTheme2) => ({
|
||||
overflow: 'hidden',
|
||||
|
||||
Reference in New Issue
Block a user