Commit b0515f46 by Marcus Andersson Committed by Torkel Ödegaard

DeleteButton: Button with icon only was not centered correctly. (#21432)

* Refactoring to get the correct spacing between the first icon and button border.

* Should not be smaller then 8px to the left.

* Removed unused dependency.

* Updated snapshot for LinkButton.
parent 35679d46
...@@ -2,7 +2,6 @@ import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, useContext } from 'r ...@@ -2,7 +2,6 @@ import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, useContext } from 'r
import { ThemeContext } from '../../themes'; import { ThemeContext } from '../../themes';
import { getButtonStyles } from './styles'; import { getButtonStyles } from './styles';
import { ButtonContent } from './ButtonContent'; import { ButtonContent } from './ButtonContent';
import cx from 'classnames';
import { ButtonSize, ButtonStyles, ButtonVariant } from './types'; import { ButtonSize, ButtonStyles, ButtonVariant } from './types';
type CommonProps = { type CommonProps = {
...@@ -31,11 +30,11 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, r ...@@ -31,11 +30,11 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, r
theme, theme,
size: size || 'md', size: size || 'md',
variant: variant || 'primary', variant: variant || 'primary',
textAndIcon: !!(children && icon),
}); });
const buttonClassName = cx(styles.button, icon && styles.buttonWithIcon, icon && !children && styles.iconButton);
return ( return (
<button className={buttonClassName} {...buttonProps} ref={ref}> <button className={styles.button} {...buttonProps} ref={ref}>
<ButtonContent icon={icon}>{children}</ButtonContent> <ButtonContent icon={icon}>{children}</ButtonContent>
</button> </button>
); );
...@@ -59,11 +58,11 @@ export const LinkButton = React.forwardRef<HTMLAnchorElement, LinkButtonProps>(( ...@@ -59,11 +58,11 @@ export const LinkButton = React.forwardRef<HTMLAnchorElement, LinkButtonProps>((
theme, theme,
size: size || 'md', size: size || 'md',
variant: variant || 'primary', variant: variant || 'primary',
textAndIcon: !!(children && icon),
}); });
const buttonClassName = cx(styles.button, icon && styles.buttonWithIcon, icon && !children && styles.iconButton);
return ( return (
<a className={buttonClassName} {...anchorProps} ref={ref}> <a className={styles.button} {...anchorProps} ref={ref}>
<ButtonContent icon={icon}>{children}</ButtonContent> <ButtonContent icon={icon}>{children}</ButtonContent>
</a> </a>
); );
......
...@@ -2,6 +2,7 @@ import React from 'react'; ...@@ -2,6 +2,7 @@ import React from 'react';
import { css } from 'emotion'; import { css } from 'emotion';
import { stylesFactory, useTheme } from '../../themes'; import { stylesFactory, useTheme } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { ButtonSize } from './types';
const getStyles = stylesFactory((theme: GrafanaTheme) => ({ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
content: css` content: css`
...@@ -23,12 +24,22 @@ type Props = { ...@@ -23,12 +24,22 @@ type Props = {
icon?: string; icon?: string;
className?: string; className?: string;
children: React.ReactNode; children: React.ReactNode;
size?: ButtonSize;
}; };
export function ButtonContent(props: Props) { export function ButtonContent(props: Props) {
const { icon, children } = props; const { icon, children } = props;
const theme = useTheme(); const theme = useTheme();
const styles = getStyles(theme); const styles = getStyles(theme);
if (!children) {
return (
<span className={styles.content}>
<i className={icon} />
</span>
);
}
const iconElement = icon && ( const iconElement = icon && (
<span className={styles.icon}> <span className={styles.icon}>
<i className={icon} /> <i className={icon} />
......
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Button renders correct html 1`] = `"<button class=\\"css-1ffx2x7-button css-5383lb\\" type=\\"button\\"><span class=\\"css-1beih13\\"><span class=\\"css-xhe2zh\\"><i class=\\"fa fa-plus\\"></i></span><span>Click me</span></span></button>"`; exports[`Button renders correct html 1`] = `"<button class=\\"css-uzitec-button\\" type=\\"button\\"><span class=\\"css-1beih13\\"><span class=\\"css-xhe2zh\\"><i class=\\"fa fa-plus\\"></i></span><span>Click me</span></span></button>"`;
exports[`LinkButton renders correct html 1`] = `"<a class=\\"css-1ffx2x7-button css-5383lb\\"><span class=\\"css-1beih13\\"><span class=\\"css-xhe2zh\\"><i class=\\"fa fa-plus\\"></i></span><span>Click me</span></span></a>"`; exports[`LinkButton renders correct html 1`] = `"<a class=\\"css-uzitec-button\\"><span class=\\"css-1beih13\\"><span class=\\"css-xhe2zh\\"><i class=\\"fa fa-plus\\"></i></span><span>Click me</span></span></a>"`;
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { css } from 'emotion'; import { css } from 'emotion';
import { selectThemeVariant, stylesFactory } from '../../themes'; import { selectThemeVariant, stylesFactory } from '../../themes';
import { StyleDeps } from './types'; import { StyleDeps, ButtonSize } from './types';
import { GrafanaTheme } from '@grafana/data';
const buttonVariantStyles = ( const buttonVariantStyles = (
from: string, from: string,
...@@ -24,39 +25,11 @@ const buttonVariantStyles = ( ...@@ -24,39 +25,11 @@ const buttonVariantStyles = (
} }
`; `;
export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleDeps) => { export const getButtonStyles = stylesFactory(({ theme, size, variant, textAndIcon }: StyleDeps) => {
const borderRadius = theme.border.radius.sm; const borderRadius = theme.border.radius.sm;
let padding, const { padding, fontSize, height, fontWeight } = calculateMeasures(theme, size, !!textAndIcon);
background,
fontSize,
height,
fontWeight = theme.typography.weight.semibold;
switch (size) { let background;
case 'sm':
padding = `${theme.spacing.xs} ${theme.spacing.sm}`;
fontSize = theme.typography.size.sm;
height = theme.height.sm;
break;
case 'md':
padding = `${theme.spacing.sm} ${theme.spacing.md}`;
fontSize = theme.typography.size.md;
height = theme.height.md;
break;
case 'lg':
padding = `${theme.spacing.md} ${theme.spacing.lg}`;
fontSize = theme.typography.size.lg;
fontWeight = theme.typography.weight.regular;
height = theme.height.lg;
break;
default:
padding = `${theme.spacing.sm} ${theme.spacing.md}`;
fontSize = theme.typography.size.base;
height = theme.height.md;
}
switch (variant) { switch (variant) {
case 'primary': case 'primary':
...@@ -120,13 +93,6 @@ export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleDep ...@@ -120,13 +93,6 @@ export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleDep
box-shadow: none; box-shadow: none;
} }
`, `,
buttonWithIcon: css`
padding-left: ${theme.spacing.sm};
`,
// used for buttons with icon onlys
iconButton: css`
padding-right: 0;
`,
iconWrap: css` iconWrap: css`
label: button-icon-wrap; label: button-icon-wrap;
& + * { & + * {
...@@ -135,3 +101,56 @@ export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleDep ...@@ -135,3 +101,56 @@ export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleDep
`, `,
}; };
}); });
type ButtonMeasures = {
padding: string;
fontSize: string;
height: string;
fontWeight: number;
};
const calculateMeasures = (theme: GrafanaTheme, size: ButtonSize, textAndIcon: boolean): ButtonMeasures => {
switch (size) {
case 'sm': {
return {
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
fontSize: theme.typography.size.sm,
height: theme.height.sm,
fontWeight: theme.typography.weight.semibold,
};
}
case 'md': {
const leftPadding = textAndIcon ? theme.spacing.sm : theme.spacing.md;
return {
padding: `${theme.spacing.sm} ${theme.spacing.md} ${theme.spacing.sm} ${leftPadding}`,
fontSize: theme.typography.size.md,
height: theme.height.md,
fontWeight: theme.typography.weight.semibold,
};
}
case 'lg': {
const leftPadding = textAndIcon ? theme.spacing.md : theme.spacing.lg;
return {
padding: `${theme.spacing.md} ${theme.spacing.lg} ${theme.spacing.md} ${leftPadding}`,
fontSize: theme.typography.size.lg,
height: theme.height.lg,
fontWeight: theme.typography.weight.regular,
};
}
default: {
const leftPadding = textAndIcon ? theme.spacing.sm : theme.spacing.md;
return {
padding: `${theme.spacing.sm} ${theme.spacing.md} ${theme.spacing.sm} ${leftPadding}`,
fontSize: theme.typography.size.base,
height: theme.height.md,
fontWeight: theme.typography.weight.regular,
};
}
}
};
...@@ -8,12 +8,11 @@ export interface StyleDeps { ...@@ -8,12 +8,11 @@ export interface StyleDeps {
theme: GrafanaTheme; theme: GrafanaTheme;
size: ButtonSize; size: ButtonSize;
variant: ButtonVariant; variant: ButtonVariant;
textAndIcon?: boolean;
} }
export interface ButtonStyles { export interface ButtonStyles {
button: string; button: string;
buttonWithIcon: string;
iconButton: string;
iconWrap: string; iconWrap: string;
icon?: string; icon?: string;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment