mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
IconButton: introduce variant for red and blue icon buttons (#33479)
* feat(iconbutton): introduce variant for red and blue icon buttons * refactor(iconbutton): give variants breathing space in story * docs(iconbutton): add docblock comment for variant prop * refactor(iconbutton): prefer secondary to undefined variant prop and add default * refactor(iconbutton): use icon color for hover
This commit is contained in:
parent
440f4182b9
commit
0836e7bde8
@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/css';
|
||||
import { IconButton } from '@grafana/ui';
|
||||
import { IconButton, IconButtonVariant } from './IconButton';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { useTheme2 } from '../../themes';
|
||||
import { IconSize, IconName } from '../../types';
|
||||
import mdx from './IconButton.mdx';
|
||||
import { VerticalGroup } from '../Layout/Layout';
|
||||
|
||||
export default {
|
||||
title: 'Buttons/IconButton',
|
||||
@ -35,6 +36,7 @@ const RenderScenario = ({ background }: ScenarioProps) => {
|
||||
const theme = useTheme2();
|
||||
const sizes: IconSize[] = ['sm', 'md', 'lg', 'xl', 'xxl'];
|
||||
const icons: IconName[] = ['search', 'trash-alt', 'arrow-left', 'times'];
|
||||
const variants: IconButtonVariant[] = ['secondary', 'primary', 'destructive'];
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -48,14 +50,22 @@ const RenderScenario = ({ background }: ScenarioProps) => {
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div>{background}</div>
|
||||
{icons.map((icon) => {
|
||||
return sizes.map((size) => (
|
||||
<span key={icon + size}>
|
||||
<IconButton name={icon} size={size} />
|
||||
</span>
|
||||
));
|
||||
})}
|
||||
<VerticalGroup spacing="md">
|
||||
<div>{background}</div>
|
||||
{variants.map((variant) => {
|
||||
return (
|
||||
<div key={variant}>
|
||||
{icons.map((icon) => {
|
||||
return sizes.map((size) => (
|
||||
<span key={icon + size}>
|
||||
<IconButton name={icon} size={size} variant={variant} />
|
||||
</span>
|
||||
));
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -4,11 +4,13 @@ import { IconName, IconSize, IconType } from '../../types/icon';
|
||||
import { stylesFactory } from '../../themes/stylesFactory';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
import { GrafanaThemeV2 } from '@grafana/data';
|
||||
import { GrafanaThemeV2, colorManipulator } from '@grafana/data';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
import { TooltipPlacement } from '../Tooltip/PopoverController';
|
||||
import { getFocusStyles, getMouseFocusStyles } from '../../themes/mixins';
|
||||
|
||||
export type IconButtonVariant = 'primary' | 'secondary' | 'destructive';
|
||||
|
||||
export interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
/** Name of the icon **/
|
||||
name: IconName;
|
||||
@ -22,14 +24,16 @@ export interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
tooltip?: string;
|
||||
/** Position of the tooltip */
|
||||
tooltipPlacement?: TooltipPlacement;
|
||||
/** Variant to change the color of the Icon */
|
||||
variant?: IconButtonVariant;
|
||||
}
|
||||
|
||||
type SurfaceType = 'dashboard' | 'panel' | 'header';
|
||||
|
||||
export const IconButton = React.forwardRef<HTMLButtonElement, Props>(
|
||||
({ name, size = 'md', iconType, tooltip, tooltipPlacement, className, ...restProps }, ref) => {
|
||||
({ name, size = 'md', iconType, tooltip, tooltipPlacement, className, variant = 'secondary', ...restProps }, ref) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme, size);
|
||||
const styles = getStyles(theme, size, variant);
|
||||
|
||||
const button = (
|
||||
<button ref={ref} {...restProps} className={cx(styles.button, className)}>
|
||||
@ -51,10 +55,16 @@ export const IconButton = React.forwardRef<HTMLButtonElement, Props>(
|
||||
|
||||
IconButton.displayName = 'IconButton';
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize) => {
|
||||
const hoverColor = theme.colors.action.hover;
|
||||
const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize, variant: IconButtonVariant) => {
|
||||
const pixelSize = getSvgSize(size);
|
||||
const hoverSize = Math.max(pixelSize / 3, 8);
|
||||
let iconColor = theme.colors.text.primary;
|
||||
|
||||
if (variant === 'primary') {
|
||||
iconColor = theme.colors.primary.main;
|
||||
} else if (variant === 'destructive') {
|
||||
iconColor = theme.colors.error.main;
|
||||
}
|
||||
|
||||
return {
|
||||
button: css`
|
||||
@ -62,6 +72,7 @@ const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize) => {
|
||||
height: ${pixelSize}px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: ${iconColor};
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
@ -77,6 +88,7 @@ const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize) => {
|
||||
&[disabled],
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
color: ${theme.colors.action.disabledText};
|
||||
opacity: 0.65;
|
||||
box-shadow: none;
|
||||
}
|
||||
@ -110,10 +122,12 @@ const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize) => {
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: ${theme.colors.text.primary};
|
||||
color: ${iconColor};
|
||||
|
||||
&:before {
|
||||
background-color: ${hoverColor};
|
||||
background-color: ${variant === 'secondary'
|
||||
? theme.colors.action.hover
|
||||
: colorManipulator.alpha(iconColor, 0.12)};
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
opacity: 1;
|
||||
|
Loading…
Reference in New Issue
Block a user