Commit 6de75de7 by Tobias Skarhed Committed by GitHub

Refactor buttons (#17611)

parent 8192fa53
...@@ -4,21 +4,9 @@ import { css, cx } from 'emotion'; ...@@ -4,21 +4,9 @@ import { css, cx } from 'emotion';
import { Themeable, GrafanaTheme } from '../../types'; import { Themeable, GrafanaTheme } from '../../types';
import { selectThemeVariant } from '../../themes/selectThemeVariant'; import { selectThemeVariant } from '../../themes/selectThemeVariant';
export enum ButtonVariant { export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'inverse' | 'transparent';
Primary = 'primary',
Secondary = 'secondary',
Danger = 'danger',
Inverse = 'inverse',
Transparent = 'transparent',
}
export enum ButtonSize { export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
ExtraSmall = 'xs',
Small = 'sm',
Medium = 'md',
Large = 'lg',
ExtraLarge = 'xl',
}
export interface CommonButtonProps { export interface CommonButtonProps {
size?: ButtonSize; size?: ButtonSize;
...@@ -69,19 +57,19 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV ...@@ -69,19 +57,19 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV
fontWeight = theme.typography.weight.semibold; fontWeight = theme.typography.weight.semibold;
switch (size) { switch (size) {
case ButtonSize.Small: case 'sm':
padding = `${theme.spacing.xs} ${theme.spacing.sm}`; padding = `${theme.spacing.xs} ${theme.spacing.sm}`;
fontSize = theme.typography.size.sm; fontSize = theme.typography.size.sm;
iconDistance = theme.spacing.xs; iconDistance = theme.spacing.xs;
height = theme.height.sm; height = theme.height.sm;
break; break;
case ButtonSize.Medium: case 'md':
padding = `${theme.spacing.sm} ${theme.spacing.md}`; padding = `${theme.spacing.sm} ${theme.spacing.md}`;
fontSize = theme.typography.size.md; fontSize = theme.typography.size.md;
iconDistance = theme.spacing.sm; iconDistance = theme.spacing.sm;
height = theme.height.md; height = theme.height.md;
break; break;
case ButtonSize.Large: case 'lg':
padding = `${theme.spacing.md} ${theme.spacing.lg}`; padding = `${theme.spacing.md} ${theme.spacing.lg}`;
fontSize = theme.typography.size.lg; fontSize = theme.typography.size.lg;
fontWeight = theme.typography.weight.regular; fontWeight = theme.typography.weight.regular;
...@@ -96,16 +84,16 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV ...@@ -96,16 +84,16 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV
} }
switch (variant) { switch (variant) {
case ButtonVariant.Primary: case 'primary':
background = buttonVariantStyles(theme.colors.greenBase, theme.colors.greenShade, theme.colors.white); background = buttonVariantStyles(theme.colors.greenBase, theme.colors.greenShade, theme.colors.white);
break; break;
case ButtonVariant.Secondary: case 'secondary':
background = buttonVariantStyles(theme.colors.blueBase, theme.colors.blueShade, theme.colors.white); background = buttonVariantStyles(theme.colors.blueBase, theme.colors.blueShade, theme.colors.white);
break; break;
case ButtonVariant.Danger: case 'danger':
background = buttonVariantStyles(theme.colors.redBase, theme.colors.redShade, theme.colors.white); background = buttonVariantStyles(theme.colors.redBase, theme.colors.redShade, theme.colors.white);
break; break;
case ButtonVariant.Inverse: case 'inverse':
const from = selectThemeVariant({ light: theme.colors.gray5, dark: theme.colors.dark6 }, theme.type) as string; const from = selectThemeVariant({ light: theme.colors.gray5, dark: theme.colors.dark6 }, theme.type) as string;
const to = selectThemeVariant( const to = selectThemeVariant(
{ {
...@@ -121,7 +109,7 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV ...@@ -121,7 +109,7 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV
background = buttonVariantStyles(from, to, theme.colors.link, 'rgba(0, 0, 0, 0.1)', true); background = buttonVariantStyles(from, to, theme.colors.link, 'rgba(0, 0, 0, 0.1)', true);
break; break;
case ButtonVariant.Transparent: case 'transparent':
background = css` background = css`
${buttonVariantStyles('', '', theme.colors.link, 'rgba(0, 0, 0, 0.1)', true)}; ${buttonVariantStyles('', '', theme.colors.link, 'rgba(0, 0, 0, 0.1)', true)};
background: transparent; background: transparent;
...@@ -170,8 +158,8 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV ...@@ -170,8 +158,8 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV
export const AbstractButton: React.FunctionComponent<AbstractButtonProps> = ({ export const AbstractButton: React.FunctionComponent<AbstractButtonProps> = ({
renderAs, renderAs,
theme, theme,
size = ButtonSize.Medium, size = 'md',
variant = ButtonVariant.Primary, variant = 'primary',
className, className,
icon, icon,
children, children,
......
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import { Button, LinkButton } from './Button'; import { Button, LinkButton } from './Button';
import { ButtonSize, ButtonVariant, CommonButtonProps } from './AbstractButton'; import { CommonButtonProps } from './AbstractButton';
// @ts-ignore // @ts-ignore
import withPropsCombinations from 'react-storybook-addon-props-combinations'; import withPropsCombinations from 'react-storybook-addon-props-combinations';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
...@@ -15,14 +15,8 @@ const defaultProps = { ...@@ -15,14 +15,8 @@ const defaultProps = {
}; };
const variants = { const variants = {
size: [ButtonSize.ExtraSmall, ButtonSize.Small, ButtonSize.Medium, ButtonSize.Large, ButtonSize.ExtraLarge], size: ['xs', 'sm', 'md', 'lg', 'xl'],
variant: [ variant: ['primary', 'secondary', 'danger', 'inverse', 'transparent'],
ButtonVariant.Primary,
ButtonVariant.Secondary,
ButtonVariant.Danger,
ButtonVariant.Inverse,
ButtonVariant.Transparent,
],
}; };
const combinationOptions = { const combinationOptions = {
CombinationRenderer: ThemeableCombinationsRowRenderer, CombinationRenderer: ThemeableCombinationsRowRenderer,
......
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { AbstractButton, ButtonProps, ButtonSize, LinkButtonProps } from './AbstractButton'; import { AbstractButton, ButtonProps, LinkButtonProps } from './AbstractButton';
import { ThemeContext } from '../../themes'; import { ThemeContext } from '../../themes';
const getSizeNameComponentSegment = (size: ButtonSize) => {
switch (size) {
case ButtonSize.ExtraSmall:
return 'ExtraSmall';
case ButtonSize.Small:
return 'Small';
case ButtonSize.Large:
return 'Large';
case ButtonSize.ExtraLarge:
return 'ExtraLarge';
default:
return 'Medium';
}
};
const buttonFactory: <T>(renderAs: string, size: ButtonSize, displayName: string) => React.ComponentType<T> = (
renderAs,
size,
displayName
) => {
const ButtonComponent: React.FunctionComponent<any> = props => {
const theme = useContext(ThemeContext);
return <AbstractButton {...props} size={size} renderAs={renderAs} theme={theme} />;
};
ButtonComponent.displayName = displayName;
return ButtonComponent;
};
export const Button: React.FunctionComponent<ButtonProps> = props => { export const Button: React.FunctionComponent<ButtonProps> = props => {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
return <AbstractButton {...props} renderAs="button" theme={theme} />; return <AbstractButton {...props} renderAs="button" theme={theme} />;
...@@ -42,45 +13,3 @@ export const LinkButton: React.FunctionComponent<LinkButtonProps> = props => { ...@@ -42,45 +13,3 @@ export const LinkButton: React.FunctionComponent<LinkButtonProps> = props => {
return <AbstractButton {...props} renderAs="a" theme={theme} />; return <AbstractButton {...props} renderAs="a" theme={theme} />;
}; };
LinkButton.displayName = 'LinkButton'; LinkButton.displayName = 'LinkButton';
export const ExtraSmallButton = buttonFactory<ButtonProps>(
'button',
ButtonSize.ExtraSmall,
`${getSizeNameComponentSegment(ButtonSize.ExtraSmall)}Button`
);
export const SmallButton = buttonFactory<ButtonProps>(
'button',
ButtonSize.Small,
`${getSizeNameComponentSegment(ButtonSize.Small)}Button`
);
export const LargeButton = buttonFactory<ButtonProps>(
'button',
ButtonSize.Large,
`${getSizeNameComponentSegment(ButtonSize.Large)}Button`
);
export const ExtraLargeButton = buttonFactory<ButtonProps>(
'button',
ButtonSize.ExtraLarge,
`${getSizeNameComponentSegment(ButtonSize.ExtraLarge)}Button`
);
export const ExtraSmallLinkButton = buttonFactory<LinkButtonProps>(
'a',
ButtonSize.ExtraSmall,
`${getSizeNameComponentSegment(ButtonSize.ExtraSmall)}LinkButton`
);
export const SmallLinkButton = buttonFactory<LinkButtonProps>(
'a',
ButtonSize.Small,
`${getSizeNameComponentSegment(ButtonSize.Small)}LinkButton`
);
export const LargeLinkButton = buttonFactory<LinkButtonProps>(
'a',
ButtonSize.Large,
`${getSizeNameComponentSegment(ButtonSize.Large)}LinkButton`
);
export const ExtraLargeLinkButton = buttonFactory<LinkButtonProps>(
'a',
ButtonSize.ExtraLarge,
`${getSizeNameComponentSegment(ButtonSize.ExtraLarge)}LinkButton`
);
...@@ -3,7 +3,7 @@ import { storiesOf } from '@storybook/react'; ...@@ -3,7 +3,7 @@ import { storiesOf } from '@storybook/react';
import { renderComponentWithTheme } from '../../utils/storybook/withTheme'; import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
import { CallToActionCard } from './CallToActionCard'; import { CallToActionCard } from './CallToActionCard';
import { select, text } from '@storybook/addon-knobs'; import { select, text } from '@storybook/addon-knobs';
import { LargeButton } from '../Button/Button'; import { Button } from '../Button/Button';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
const CallToActionCardStories = storiesOf('UI/CallToActionCard', module); const CallToActionCardStories = storiesOf('UI/CallToActionCard', module);
...@@ -12,9 +12,9 @@ CallToActionCardStories.add('default', () => { ...@@ -12,9 +12,9 @@ CallToActionCardStories.add('default', () => {
const ctaElements: { [key: string]: JSX.Element } = { const ctaElements: { [key: string]: JSX.Element } = {
custom: <h1>This is just H1 tag, you can any component as CTA element</h1>, custom: <h1>This is just H1 tag, you can any component as CTA element</h1>,
button: ( button: (
<LargeButton icon="fa fa-plus" onClick={action('cta button clicked')}> <Button size="lg" icon="fa fa-plus" onClick={action('cta button clicked')}>
Add datasource Add datasource
</LargeButton> </Button>
), ),
}; };
const ctaElement = select( const ctaElement = select(
......
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { CallToActionCard, LargeLinkButton, ThemeContext } from '@grafana/ui'; import { CallToActionCard, LinkButton, ThemeContext } from '@grafana/ui';
import { css } from 'emotion'; import { css } from 'emotion';
export interface Props { export interface Props {
model: any; model: any;
...@@ -37,9 +37,9 @@ const EmptyListCTA: React.FunctionComponent<Props> = props => { ...@@ -37,9 +37,9 @@ const EmptyListCTA: React.FunctionComponent<Props> = props => {
: ''; : '';
const ctaElement = ( const ctaElement = (
<LargeLinkButton onClick={onClick} href={buttonLink} icon={buttonIcon} className={ctaElementClassName}> <LinkButton size="lg" onClick={onClick} href={buttonLink} icon={buttonIcon} className={ctaElementClassName}>
{buttonTitle} {buttonTitle}
</LargeLinkButton> </LinkButton>
); );
return <CallToActionCard message={title} footer={footer} callToActionElement={ctaElement} theme={theme} />; return <CallToActionCard message={title} footer={footer} callToActionElement={ctaElement} theme={theme} />;
......
...@@ -11,7 +11,6 @@ import { ...@@ -11,7 +11,6 @@ import {
} from '@grafana/ui'; } from '@grafana/ui';
import ElapsedTime from './ElapsedTime'; import ElapsedTime from './ElapsedTime';
import { ButtonSize, ButtonVariant } from '@grafana/ui/src/components/Button/AbstractButton';
const getStyles = (theme: GrafanaTheme) => ({ const getStyles = (theme: GrafanaTheme) => ({
logsRowsLive: css` logsRowsLive: css`
...@@ -110,8 +109,8 @@ class LiveLogs extends PureComponent<Props, State> { ...@@ -110,8 +109,8 @@ class LiveLogs extends PureComponent<Props, State> {
</span> </span>
<LinkButton <LinkButton
onClick={this.props.stopLive} onClick={this.props.stopLive}
size={ButtonSize.Medium} size="md"
variant={ButtonVariant.Transparent} variant="transparent"
style={{ color: theme.colors.orange }} style={{ color: theme.colors.orange }}
> >
Stop Live Stop Live
......
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { css } from 'emotion'; import { css } from 'emotion';
import { ThemeContext, LargeLinkButton, CallToActionCard } from '@grafana/ui'; import { ThemeContext, LinkButton, CallToActionCard } from '@grafana/ui';
export const NoDataSourceCallToAction = () => { export const NoDataSourceCallToAction = () => {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
...@@ -22,9 +22,9 @@ export const NoDataSourceCallToAction = () => { ...@@ -22,9 +22,9 @@ export const NoDataSourceCallToAction = () => {
); );
const ctaElement = ( const ctaElement = (
<LargeLinkButton href="/datasources/new" icon="gicon gicon-datasources"> <LinkButton size="lg" href="/datasources/new" icon="gicon gicon-datasources">
Add data source Add data source
</LargeLinkButton> </LinkButton>
); );
const cardClassName = css` const cardClassName = css`
......
...@@ -7,7 +7,6 @@ import { PluginMeta, AppPlugin, Button } from '@grafana/ui'; ...@@ -7,7 +7,6 @@ import { PluginMeta, AppPlugin, Button } from '@grafana/ui';
import { AngularComponent, getAngularLoader } from '@grafana/runtime'; import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
import { ButtonVariant } from '@grafana/ui/src/components/Button/AbstractButton';
import { css } from 'emotion'; import { css } from 'emotion';
interface Props { interface Props {
...@@ -71,17 +70,17 @@ export class AppConfigCtrlWrapper extends PureComponent<Props, State> { ...@@ -71,17 +70,17 @@ export class AppConfigCtrlWrapper extends PureComponent<Props, State> {
{model && ( {model && (
<div className="gf-form"> <div className="gf-form">
{!model.enabled && ( {!model.enabled && (
<Button variant={ButtonVariant.Primary} onClick={this.enable} className={withRightMargin}> <Button variant="primary" onClick={this.enable} className={withRightMargin}>
Enable Enable
</Button> </Button>
)} )}
{model.enabled && ( {model.enabled && (
<Button variant={ButtonVariant.Primary} onClick={this.update} className={withRightMargin}> <Button variant="primary" onClick={this.update} className={withRightMargin}>
Update Update
</Button> </Button>
)} )}
{model.enabled && ( {model.enabled && (
<Button variant={ButtonVariant.Danger} onClick={this.disable} className={withRightMargin}> <Button variant="danger" onClick={this.disable} className={withRightMargin}>
Disable Disable
</Button> </Button>
)} )}
......
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