Form Migrations: Button (#23019)
* Update legacy exports and fix Type errors * Remove Button and LinkButton from Forms namespace * Fix errors * Update snapshots * Move Legacy button * Migrate more Buttons * Remove legacy button dependency * Move button up * Remove legacy button * Update Snapshots * Fix ComponentSize issues * Switch primary button * Switch primary * Add classNames and fix some angular directive issues * Fix failing build and remove log Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
co-authored by
Torkel Ödegaard
parent
f63877f247
commit
5cdb8f8e44
+17
@@ -59,5 +59,22 @@ Used for removing or deleting entities.
|
||||
</div>
|
||||
</Preview>
|
||||
|
||||
## Link
|
||||
|
||||
Used for for hyperlinks.
|
||||
|
||||
<Preview>
|
||||
<div>
|
||||
<Button href="/" variant="link" size="sm" renderAs="button" style={{ margin: '5px' }}>
|
||||
Small
|
||||
</Button>
|
||||
<Button href="/" variant="link" size="md" renderAs="button" style={{ margin: '5px' }}>
|
||||
Medium
|
||||
</Button>
|
||||
<Button href="/" variant="link" size="lg" renderAs="button" style={{ margin: '5px' }}>
|
||||
Large
|
||||
</Button>
|
||||
</div>
|
||||
</Preview>
|
||||
|
||||
<Props of={Button} />
|
||||
@@ -1,45 +1,35 @@
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { Button, LinkButton } from './Button';
|
||||
// @ts-ignore
|
||||
import withPropsCombinations from 'react-storybook-addon-props-combinations';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ThemeableCombinationsRowRenderer } from '../../utils/storybook/CombinationsRowRenderer';
|
||||
import { boolean } from '@storybook/addon-knobs';
|
||||
import React from 'react';
|
||||
import { select, text } from '@storybook/addon-knobs';
|
||||
import { Button, ButtonVariant } from './Button';
|
||||
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { getIconKnob } from '../../utils/storybook/knobs';
|
||||
import mdx from './Button.mdx';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
|
||||
const ButtonStories = storiesOf('General/Button', module);
|
||||
|
||||
const defaultProps = {
|
||||
onClick: [action('Button clicked')],
|
||||
children: ['Click click!'],
|
||||
export default {
|
||||
title: 'Forms/Button',
|
||||
component: Button,
|
||||
decorators: [withCenteredStory, withHorizontallyCenteredStory],
|
||||
parameters: {
|
||||
docs: {
|
||||
page: mdx,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const variants = {
|
||||
size: ['xs', 'sm', 'md', 'lg'],
|
||||
variant: ['primary', 'secondary', 'danger', 'inverse', 'transparent', 'link'],
|
||||
};
|
||||
const combinationOptions = {
|
||||
CombinationRenderer: ThemeableCombinationsRowRenderer,
|
||||
};
|
||||
const variants = ['primary', 'secondary', 'destructive', 'link'];
|
||||
|
||||
const renderButtonStory = (buttonComponent: typeof Button | typeof LinkButton) => {
|
||||
const isDisabled = boolean('Disable button', false);
|
||||
return withPropsCombinations(
|
||||
buttonComponent,
|
||||
{ ...variants, ...defaultProps, disabled: [isDisabled] },
|
||||
combinationOptions
|
||||
)();
|
||||
};
|
||||
const sizes = ['sm', 'md', 'lg'];
|
||||
|
||||
ButtonStories.add('as button element', () => renderButtonStory(Button));
|
||||
|
||||
ButtonStories.add('as link element', () => renderButtonStory(LinkButton));
|
||||
|
||||
ButtonStories.add('with icon', () => {
|
||||
export const simple = () => {
|
||||
const variant = select('Variant', variants, 'primary');
|
||||
const size = select('Size', sizes, 'md');
|
||||
const buttonText = text('text', 'Button');
|
||||
const icon = getIconKnob();
|
||||
return withPropsCombinations(
|
||||
Button,
|
||||
{ ...variants, ...defaultProps, icon: [icon && `fa fa-${icon}`] },
|
||||
combinationOptions
|
||||
)();
|
||||
});
|
||||
|
||||
return (
|
||||
<Button variant={variant as ButtonVariant} size={size as ComponentSize} icon={icon && `fa fa-${icon}`}>
|
||||
{buttonText}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Button, LinkButton } from './Button';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
describe('Button', () => {
|
||||
it('renders correct html', () => {
|
||||
const wrapper = mount(<Button icon={'fa fa-plus'}>Click me</Button>);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('LinkButton', () => {
|
||||
it('renders correct html', () => {
|
||||
const wrapper = mount(<LinkButton icon={'fa fa-plus'}>Click me</LinkButton>);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('allows a disable state on link button', () => {
|
||||
const wrapper = mount(
|
||||
<LinkButton disabled icon={'fa fa-plus'}>
|
||||
Click me
|
||||
</LinkButton>
|
||||
);
|
||||
expect(wrapper.find('a[disabled]').length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,72 +1,178 @@
|
||||
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, useContext } from 'react';
|
||||
import { ThemeContext } from '../../themes';
|
||||
import { getButtonStyles } from './styles';
|
||||
import { css, cx } from 'emotion';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { selectThemeVariant, stylesFactory, ThemeContext } from '../../themes';
|
||||
import { getFocusStyle, getPropertiesForButtonSize } from '../Forms/commonStyles';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { ButtonContent } from './ButtonContent';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { ButtonStyles, ButtonVariant } from './types';
|
||||
import { cx } from 'emotion';
|
||||
|
||||
const buttonVariantStyles = (from: string, to: string, textColor: string) => css`
|
||||
background: linear-gradient(180deg, ${from} 0%, ${to} 100%);
|
||||
color: ${textColor};
|
||||
&:hover {
|
||||
background: ${from};
|
||||
color: ${textColor};
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: ${from};
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const getPropertiesForVariant = (theme: GrafanaTheme, variant: ButtonVariant) => {
|
||||
switch (variant) {
|
||||
case 'secondary':
|
||||
const from = selectThemeVariant({ light: theme.colors.gray7, dark: theme.colors.gray15 }, theme.type) as string;
|
||||
const to = selectThemeVariant(
|
||||
{
|
||||
light: tinycolor(from)
|
||||
.darken(5)
|
||||
.toString(),
|
||||
dark: tinycolor(from)
|
||||
.lighten(4)
|
||||
.toString(),
|
||||
},
|
||||
theme.type
|
||||
) as string;
|
||||
|
||||
return {
|
||||
borderColor: selectThemeVariant({ light: theme.colors.gray85, dark: theme.colors.gray25 }, theme.type),
|
||||
background: buttonVariantStyles(
|
||||
from,
|
||||
to,
|
||||
selectThemeVariant({ light: theme.colors.gray25, dark: theme.colors.gray4 }, theme.type) as string
|
||||
),
|
||||
};
|
||||
|
||||
case 'destructive':
|
||||
return {
|
||||
borderColor: theme.colors.redShade,
|
||||
background: buttonVariantStyles(theme.colors.redBase, theme.colors.redShade, theme.colors.white),
|
||||
};
|
||||
|
||||
case 'link':
|
||||
return {
|
||||
borderColor: 'transparent',
|
||||
background: buttonVariantStyles('transparent', 'transparent', theme.colors.linkExternal),
|
||||
variantStyles: css`
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
};
|
||||
case 'primary':
|
||||
default:
|
||||
return {
|
||||
borderColor: theme.colors.blueShade,
|
||||
background: buttonVariantStyles(theme.colors.blueBase, theme.colors.blueShade, theme.colors.white),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export interface StyleProps {
|
||||
theme: GrafanaTheme;
|
||||
size: ComponentSize;
|
||||
variant: ButtonVariant;
|
||||
textAndIcon?: boolean;
|
||||
}
|
||||
|
||||
export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleProps) => {
|
||||
const { padding, fontSize, height } = getPropertiesForButtonSize(theme, size);
|
||||
const { background, borderColor, variantStyles } = getPropertiesForVariant(theme, variant);
|
||||
|
||||
return {
|
||||
button: cx(
|
||||
css`
|
||||
label: button;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-weight: ${theme.typography.weight.semibold};
|
||||
font-family: ${theme.typography.fontFamily.sansSerif};
|
||||
font-size: ${fontSize};
|
||||
padding: ${padding};
|
||||
height: ${height};
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid ${borderColor};
|
||||
border-radius: ${theme.border.radius.sm};
|
||||
${background};
|
||||
|
||||
&[disabled],
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
getFocusStyle(theme),
|
||||
css`
|
||||
${variantStyles}
|
||||
`
|
||||
),
|
||||
buttonWithIcon: css`
|
||||
padding-left: ${theme.spacing.sm};
|
||||
`,
|
||||
// used for buttons with icon only
|
||||
iconButton: css`
|
||||
padding-right: 0;
|
||||
`,
|
||||
iconWrap: css`
|
||||
label: button-icon-wrap;
|
||||
& + * {
|
||||
margin-left: ${theme.spacing.sm};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export type ButtonVariant = 'primary' | 'secondary' | 'destructive' | 'link';
|
||||
|
||||
type CommonProps = {
|
||||
size?: ComponentSize;
|
||||
variant?: ButtonVariant;
|
||||
/**
|
||||
* icon prop is a temporary solution. It accepts legacy icon class names for the icon to be rendered.
|
||||
* TODO: migrate to a component when we are going to migrate icons to @grafana/ui
|
||||
*/
|
||||
icon?: string;
|
||||
className?: string;
|
||||
styles?: ButtonStyles;
|
||||
};
|
||||
|
||||
export type ButtonProps = CommonProps & ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const { size, variant, icon, children, className, styles: stylesProp, ...buttonProps } = props;
|
||||
|
||||
// Default this to 'button', otherwise html defaults to 'submit' which then submits any form it is in.
|
||||
buttonProps.type = buttonProps.type || 'button';
|
||||
|
||||
const styles: ButtonStyles =
|
||||
stylesProp ||
|
||||
getButtonStyles({
|
||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ variant, icon, children, className, ...otherProps }, ref) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const styles = getButtonStyles({
|
||||
theme,
|
||||
size: size || 'md',
|
||||
size: otherProps.size || 'md',
|
||||
variant: variant || 'primary',
|
||||
textAndIcon: !!(children && icon),
|
||||
});
|
||||
|
||||
return (
|
||||
<button className={cx(styles.button, className)} {...buttonProps} ref={ref}>
|
||||
<ButtonContent icon={icon}>{children}</ButtonContent>
|
||||
</button>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<button className={cx(styles.button, className)} {...otherProps} ref={ref}>
|
||||
<ButtonContent icon={icon}>{children}</ButtonContent>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Button.displayName = 'Button';
|
||||
|
||||
export type LinkButtonProps = CommonProps &
|
||||
AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||
// We allow disabled here even though it is not standard for a link. We use it as a selector to style it as
|
||||
// disabled.
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export const LinkButton = React.forwardRef<HTMLAnchorElement, LinkButtonProps>((props, ref) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const { size, variant, icon, children, className, styles: stylesProp, ...anchorProps } = props;
|
||||
const styles: ButtonStyles =
|
||||
stylesProp ||
|
||||
getButtonStyles({
|
||||
type ButtonLinkProps = CommonProps & AnchorHTMLAttributes<HTMLAnchorElement>;
|
||||
export const LinkButton = React.forwardRef<HTMLAnchorElement, ButtonLinkProps>(
|
||||
({ variant, icon, children, className, ...otherProps }, ref) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const styles = getButtonStyles({
|
||||
theme,
|
||||
size: size || 'md',
|
||||
size: otherProps.size || 'md',
|
||||
variant: variant || 'primary',
|
||||
textAndIcon: !!(children && icon),
|
||||
});
|
||||
|
||||
return (
|
||||
<a className={cx(styles.button, className)} {...anchorProps} ref={ref}>
|
||||
<ButtonContent icon={icon}>{children}</ButtonContent>
|
||||
</a>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<a className={cx(styles.button, className)} {...otherProps} ref={ref}>
|
||||
<ButtonContent icon={icon}>{children}</ButtonContent>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
);
|
||||
LinkButton.displayName = 'LinkButton';
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Button renders correct html 1`] = `"<button class=\\"css-12s5hlm-button\\" type=\\"button\\"><span class=\\"css-1beih13\\"><span class=\\"css-1rgbe4\\"><i class=\\"fa fa-plus\\"></i></span><span>Click me</span></span></button>"`;
|
||||
|
||||
exports[`LinkButton renders correct html 1`] = `"<a class=\\"css-12s5hlm-button\\"><span class=\\"css-1beih13\\"><span class=\\"css-1rgbe4\\"><i class=\\"fa fa-plus\\"></i></span><span>Click me</span></span></a>"`;
|
||||
@@ -0,0 +1 @@
|
||||
export * from './Button';
|
||||
@@ -1,164 +0,0 @@
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { css } from 'emotion';
|
||||
import { selectThemeVariant, stylesFactory } from '../../themes';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { StyleDeps } from './types';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
|
||||
const buttonVariantStyles = (
|
||||
from: string,
|
||||
to: string,
|
||||
textColor: string,
|
||||
textShadowColor = 'rgba(0, 0, 0, 0.1)',
|
||||
invert = false
|
||||
) => css`
|
||||
background: linear-gradient(to bottom, ${from}, ${to});
|
||||
color: ${textColor};
|
||||
text-shadow: 0 ${invert ? '1px' : '-1px'} ${textShadowColor};
|
||||
&:hover {
|
||||
background: ${from};
|
||||
color: ${textColor};
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: ${from};
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export const getButtonStyles = stylesFactory(({ theme, size, variant, textAndIcon }: StyleDeps) => {
|
||||
const borderRadius = theme.border.radius.sm;
|
||||
const { padding, fontSize, height, fontWeight } = calculateMeasures(theme, size, !!textAndIcon);
|
||||
|
||||
let background;
|
||||
|
||||
switch (variant) {
|
||||
case 'primary':
|
||||
background = buttonVariantStyles(theme.colors.greenBase, theme.colors.greenShade, theme.colors.white);
|
||||
break;
|
||||
|
||||
case 'secondary':
|
||||
background = buttonVariantStyles(theme.colors.blueBase, theme.colors.blueShade, theme.colors.white);
|
||||
break;
|
||||
|
||||
case 'danger':
|
||||
background = buttonVariantStyles(theme.colors.redBase, theme.colors.redShade, theme.colors.white);
|
||||
break;
|
||||
|
||||
case 'inverse':
|
||||
const from = selectThemeVariant({ light: theme.colors.gray5, dark: theme.colors.dark6 }, theme.type) as string;
|
||||
const to = selectThemeVariant(
|
||||
{
|
||||
light: tinycolor(from)
|
||||
.darken(5)
|
||||
.toString(),
|
||||
dark: tinycolor(from)
|
||||
.lighten(4)
|
||||
.toString(),
|
||||
},
|
||||
theme.type
|
||||
) as string;
|
||||
|
||||
background = buttonVariantStyles(from, to, theme.colors.link, 'rgba(0, 0, 0, 0.1)', true);
|
||||
break;
|
||||
|
||||
case 'transparent':
|
||||
background = css`
|
||||
${buttonVariantStyles('', '', theme.colors.link, 'rgba(0, 0, 0, 0.1)', true)};
|
||||
background: transparent;
|
||||
`;
|
||||
break;
|
||||
|
||||
case 'link':
|
||||
background = css`
|
||||
${buttonVariantStyles('', '', theme.colors.linkExternal, 'rgba(0, 0, 0, 0.1)', true)};
|
||||
background: transparent;
|
||||
`;
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
button: css`
|
||||
label: button;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-weight: ${fontWeight};
|
||||
font-size: ${fontSize};
|
||||
font-family: ${theme.typography.fontFamily.sansSerif};
|
||||
line-height: ${theme.typography.lineHeight.md};
|
||||
padding: ${padding};
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
height: ${height};
|
||||
border-radius: ${borderRadius};
|
||||
${background};
|
||||
|
||||
&[disabled],
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
iconWrap: css`
|
||||
label: button-icon-wrap;
|
||||
& + * {
|
||||
margin-left: ${theme.spacing.sm};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
type ButtonMeasures = {
|
||||
padding: string;
|
||||
fontSize: string;
|
||||
height: string;
|
||||
fontWeight: number;
|
||||
};
|
||||
|
||||
const calculateMeasures = (theme: GrafanaTheme, size: ComponentSize, textAndIcon: boolean): ButtonMeasures => {
|
||||
switch (size) {
|
||||
case 'sm': {
|
||||
return {
|
||||
padding: `0 ${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: `0 ${theme.spacing.md} 0 ${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: `0 ${theme.spacing.lg} 0 ${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: `0 ${theme.spacing.md} 0 ${leftPadding}`,
|
||||
fontSize: theme.typography.size.base,
|
||||
height: theme.height.md,
|
||||
fontWeight: theme.typography.weight.regular,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
|
||||
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'inverse' | 'transparent' | 'destructive' | 'link';
|
||||
|
||||
export interface StyleDeps {
|
||||
theme: GrafanaTheme;
|
||||
size: ComponentSize;
|
||||
variant: ButtonVariant;
|
||||
textAndIcon?: boolean;
|
||||
}
|
||||
|
||||
export interface ButtonStyles {
|
||||
button: string;
|
||||
iconWrap: string;
|
||||
icon?: string;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import Clipboard from 'clipboard';
|
||||
import { Button, ButtonProps } from '../Button/Button';
|
||||
import { Button, ButtonProps } from '../Button';
|
||||
|
||||
interface Props extends ButtonProps {
|
||||
getText(): string;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
export { ClipboardButton } from '../ClipboardButton/ClipboardButton';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { text, boolean, select } from '@storybook/addon-knobs';
|
||||
import { ConfirmButton } from './ConfirmButton';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
|
||||
const getKnobs = () => {
|
||||
return {
|
||||
@@ -16,9 +17,8 @@ const getKnobs = () => {
|
||||
{
|
||||
primary: 'primary',
|
||||
secondary: 'secondary',
|
||||
danger: 'danger',
|
||||
inverse: 'inverse',
|
||||
transparent: 'transparent',
|
||||
destructive: 'destructive',
|
||||
link: 'link',
|
||||
},
|
||||
'primary'
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { ConfirmButton } from './ConfirmButton';
|
||||
import { mount, ShallowWrapper } from 'enzyme';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
|
||||
describe('ConfirmButton', () => {
|
||||
let wrapper: any;
|
||||
|
||||
@@ -4,9 +4,7 @@ import { stylesFactory, withTheme } from '../../themes';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { Themeable } from '../../types';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { Button } from '../Button/Button';
|
||||
import Forms from '../Forms';
|
||||
import { ButtonVariant } from '../Button/types';
|
||||
import { Button, ButtonVariant } from '../Button';
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
return {
|
||||
@@ -135,9 +133,9 @@ class UnThemedConfirmButton extends PureComponent<Props, State> {
|
||||
<span className={styles.buttonContainer}>
|
||||
{typeof children === 'string' ? (
|
||||
<span className={buttonClass}>
|
||||
<Forms.Button size={size} variant="link" onClick={onClick}>
|
||||
<Button size={size} variant="link" onClick={onClick}>
|
||||
{children}
|
||||
</Forms.Button>
|
||||
</Button>
|
||||
</span>
|
||||
) : (
|
||||
<span className={buttonClass} onClick={onClick}>
|
||||
@@ -146,7 +144,7 @@ class UnThemedConfirmButton extends PureComponent<Props, State> {
|
||||
)}
|
||||
<span className={styles.confirmButtonContainer}>
|
||||
<span className={confirmButtonClass}>
|
||||
<Button size={size} variant="transparent" onClick={this.onClickCancel}>
|
||||
<Button size={size} variant="secondary" onClick={this.onClickCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button size={size} variant={confirmButtonVariant} onClick={onConfirm}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { FC } from 'react';
|
||||
import { ConfirmButton } from './ConfirmButton';
|
||||
import { Button } from '../Button/Button';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { Button } from '../Button';
|
||||
|
||||
interface Props {
|
||||
size?: ComponentSize;
|
||||
@@ -13,12 +13,12 @@ export const DeleteButton: FC<Props> = ({ size, disabled, onConfirm }) => {
|
||||
return (
|
||||
<ConfirmButton
|
||||
confirmText="Delete"
|
||||
confirmVariant="danger"
|
||||
confirmVariant="destructive"
|
||||
size={size || 'md'}
|
||||
disabled={disabled}
|
||||
onConfirm={onConfirm}
|
||||
>
|
||||
<Button variant="danger" icon="fa fa-remove" size={size || 'sm'} />
|
||||
<Button variant="destructive" icon="fa fa-remove" size={size || 'sm'} />
|
||||
</ConfirmButton>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { FC, useContext } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { Modal } from '../Modal/Modal';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
import { stylesFactory, ThemeContext } from '../../themes';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { HorizontalGroup } from '..';
|
||||
@@ -53,10 +53,10 @@ export const ConfirmModal: FC<Props> = ({
|
||||
<div className={styles.modalContent}>
|
||||
<div className={styles.modalText}>{body}</div>
|
||||
<HorizontalGroup justify="center">
|
||||
<Button variant="danger" onClick={onConfirm}>
|
||||
<Button variant="destructive" onClick={onConfirm}>
|
||||
{confirmText}
|
||||
</Button>
|
||||
<Button variant="inverse" onClick={onDismiss}>
|
||||
<Button variant="secondary" onClick={onDismiss}>
|
||||
{dismissText}
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
|
||||
@@ -73,7 +73,7 @@ export const DataLinksEditor: FC<DataLinksEditorProps> = React.memo(
|
||||
)}
|
||||
|
||||
{(!value || (value && value.length < (maxLinks || Infinity))) && (
|
||||
<Button variant="inverse" icon="fa fa-plus" onClick={() => onAdd()}>
|
||||
<Button variant="secondary" icon="fa fa-plus" onClick={() => onAdd()}>
|
||||
Add link
|
||||
</Button>
|
||||
)}
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@ import { DataFrame, DataLink, VariableSuggestion } from '@grafana/data';
|
||||
import React, { FC, useState } from 'react';
|
||||
import { DataLinkEditor } from '../DataLinkEditor';
|
||||
import { HorizontalGroup } from '../../Layout/Layout';
|
||||
import Forms from '../../Forms';
|
||||
import { Button } from '../../Button';
|
||||
|
||||
interface DataLinkEditorModalContentProps {
|
||||
link: DataLink;
|
||||
@@ -34,17 +34,17 @@ export const DataLinkEditorModalContent: FC<DataLinkEditorModalContentProps> = (
|
||||
onRemove={() => {}}
|
||||
/>
|
||||
<HorizontalGroup>
|
||||
<Forms.Button
|
||||
<Button
|
||||
onClick={() => {
|
||||
onChange(index, dirtyLink);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Forms.Button>
|
||||
<Forms.Button variant="secondary" onClick={() => onClose()}>
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={() => onClose()}>
|
||||
Cancel
|
||||
</Forms.Button>
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
</>
|
||||
);
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
import { DataFrame, DataLink, GrafanaTheme, VariableSuggestion } from '@grafana/data';
|
||||
import React, { useState } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import Forms from '../../Forms';
|
||||
import { Button } from '../../Button/Button';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { Modal } from '../../Modal/Modal';
|
||||
import { FullWidthButtonContainer } from '../../Button/FullWidthButtonContainer';
|
||||
@@ -100,9 +100,9 @@ export const DataLinksInlineEditor: React.FC<DataLinksInlineEditorProps> = ({ li
|
||||
)}
|
||||
|
||||
<FullWidthButtonContainer>
|
||||
<Forms.Button size="sm" icon="fa fa-plus" onClick={onDataLinkAdd}>
|
||||
<Button size="sm" icon="fa fa-plus" onClick={onDataLinkAdd}>
|
||||
Add link
|
||||
</Forms.Button>
|
||||
</Button>
|
||||
</FullWidthButtonContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ describe('Render', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
const removeButton = wrapper.find('Button').find({ variant: 'transparent' });
|
||||
const removeButton = wrapper.find('Button').find({ variant: 'destructive' });
|
||||
removeButton.simulate('click', { preventDefault: () => {} });
|
||||
expect(wrapper.find('FormField').exists()).toBeFalsy();
|
||||
expect(wrapper.find('SecretFormField').exists()).toBeFalsy();
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import uniqueId from 'lodash/uniqueId';
|
||||
import { DataSourceSettings } from '@grafana/data';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
import { FormField } from '../FormField/FormField';
|
||||
import { SecretFormField } from '../SecretFormFied/SecretFormField';
|
||||
import { stylesFactory } from '../../themes';
|
||||
@@ -76,7 +76,7 @@ const CustomHeaderRow: React.FC<CustomHeaderRowProps> = ({ header, onBlur, onCha
|
||||
onChange={e => onChange({ ...header, value: e.target.value })}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
<Button variant="transparent" size="xs" onClick={_e => onRemove(header.id)}>
|
||||
<Button variant="destructive" size="xs" onClick={_e => onRemove(header.id)}>
|
||||
<i className="fa fa-trash" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -202,7 +202,7 @@ export class CustomHeadersSettings extends PureComponent<Props, State> {
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<Button
|
||||
variant="inverse"
|
||||
variant="secondary"
|
||||
size="xs"
|
||||
onClick={e => {
|
||||
this.onHeaderAdd();
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import { select, text } from '@storybook/addon-knobs';
|
||||
import { Button, ButtonVariant } from './Button';
|
||||
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { getIconKnob } from '../../utils/storybook/knobs';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import mdx from './Button.mdx';
|
||||
|
||||
export default {
|
||||
title: 'Forms/Button',
|
||||
component: Button,
|
||||
decorators: [withCenteredStory, withHorizontallyCenteredStory],
|
||||
parameters: {
|
||||
docs: {
|
||||
page: mdx,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const variants = ['primary', 'secondary', 'destructive', 'link'];
|
||||
|
||||
const sizes = ['sm', 'md', 'lg'];
|
||||
|
||||
export const simple = () => {
|
||||
const variant = select('Variant', variants, 'primary');
|
||||
const size = select('Size', sizes, 'md');
|
||||
const buttonText = text('text', 'Button');
|
||||
const icon = getIconKnob();
|
||||
|
||||
return (
|
||||
<Button variant={variant as ButtonVariant} size={size as ComponentSize} icon={icon && `fa fa-${icon}`}>
|
||||
{buttonText}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -1,161 +0,0 @@
|
||||
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, useContext } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { selectThemeVariant, stylesFactory, ThemeContext } from '../../themes';
|
||||
import { Button as DefaultButton, LinkButton as DefaultLinkButton } from '../Button/Button';
|
||||
import { getFocusStyle, getPropertiesForButtonSize } from './commonStyles';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { StyleDeps } from '../Button/types';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
|
||||
const buttonVariantStyles = (from: string, to: string, textColor: string) => css`
|
||||
background: linear-gradient(180deg, ${from} 0%, ${to} 100%);
|
||||
color: ${textColor};
|
||||
&:hover {
|
||||
background: ${from};
|
||||
color: ${textColor};
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: ${from};
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const getPropertiesForVariant = (theme: GrafanaTheme, variant: ButtonVariant) => {
|
||||
switch (variant) {
|
||||
case 'secondary':
|
||||
const from = selectThemeVariant({ light: theme.colors.gray7, dark: theme.colors.gray15 }, theme.type) as string;
|
||||
const to = selectThemeVariant(
|
||||
{
|
||||
light: tinycolor(from)
|
||||
.darken(5)
|
||||
.toString(),
|
||||
dark: tinycolor(from)
|
||||
.lighten(4)
|
||||
.toString(),
|
||||
},
|
||||
theme.type
|
||||
) as string;
|
||||
|
||||
return {
|
||||
borderColor: selectThemeVariant({ light: theme.colors.gray85, dark: theme.colors.gray25 }, theme.type),
|
||||
background: buttonVariantStyles(
|
||||
from,
|
||||
to,
|
||||
selectThemeVariant({ light: theme.colors.gray25, dark: theme.colors.gray4 }, theme.type) as string
|
||||
),
|
||||
};
|
||||
|
||||
case 'destructive':
|
||||
return {
|
||||
borderColor: theme.colors.redShade,
|
||||
background: buttonVariantStyles(theme.colors.redBase, theme.colors.redShade, theme.colors.white),
|
||||
};
|
||||
|
||||
case 'link':
|
||||
return {
|
||||
borderColor: 'transparent',
|
||||
background: buttonVariantStyles('transparent', 'transparent', theme.colors.linkExternal),
|
||||
variantStyles: css`
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
};
|
||||
case 'primary':
|
||||
default:
|
||||
return {
|
||||
borderColor: theme.colors.blueShade,
|
||||
background: buttonVariantStyles(theme.colors.blueBase, theme.colors.blueShade, theme.colors.white),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Need to do this because of mismatch between variants in standard buttons and here
|
||||
type StyleProps = Omit<StyleDeps, 'variant'> & { variant: ButtonVariant };
|
||||
|
||||
export const getButtonStyles = stylesFactory(({ theme, size, variant }: StyleProps) => {
|
||||
const { padding, fontSize, height } = getPropertiesForButtonSize(theme, size);
|
||||
const { background, borderColor, variantStyles } = getPropertiesForVariant(theme, variant);
|
||||
|
||||
return {
|
||||
button: cx(
|
||||
css`
|
||||
label: button;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-weight: ${theme.typography.weight.semibold};
|
||||
font-family: ${theme.typography.fontFamily.sansSerif};
|
||||
line-height: ${theme.typography.lineHeight.md};
|
||||
font-size: ${fontSize};
|
||||
padding: ${padding};
|
||||
height: ${height};
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid ${borderColor};
|
||||
border-radius: ${theme.border.radius.sm};
|
||||
${background};
|
||||
|
||||
&[disabled],
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
getFocusStyle(theme),
|
||||
css`
|
||||
${variantStyles}
|
||||
`
|
||||
),
|
||||
buttonWithIcon: css`
|
||||
padding-left: ${theme.spacing.sm};
|
||||
`,
|
||||
// used for buttons with icon only
|
||||
iconButton: css`
|
||||
padding-right: 0;
|
||||
`,
|
||||
iconWrap: css`
|
||||
label: button-icon-wrap;
|
||||
& + * {
|
||||
margin-left: ${theme.spacing.sm};
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
// These are different from the standard Button where there are more variants.
|
||||
export type ButtonVariant = 'primary' | 'secondary' | 'destructive' | 'link';
|
||||
|
||||
// These also needs to be different because the ButtonVariant is different
|
||||
type CommonProps = {
|
||||
size?: ComponentSize;
|
||||
variant?: ButtonVariant;
|
||||
icon?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export type ButtonProps = CommonProps & ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ variant, ...otherProps }, ref) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const styles = getButtonStyles({
|
||||
theme,
|
||||
size: otherProps.size || 'md',
|
||||
variant: variant || 'primary',
|
||||
});
|
||||
return <DefaultButton {...otherProps} variant={variant} styles={styles} ref={ref} />;
|
||||
});
|
||||
|
||||
type ButtonLinkProps = CommonProps & AnchorHTMLAttributes<HTMLAnchorElement>;
|
||||
export const LinkButton = React.forwardRef<HTMLAnchorElement, ButtonLinkProps>(({ variant, ...otherProps }, ref) => {
|
||||
const theme = useContext(ThemeContext);
|
||||
const styles = getButtonStyles({
|
||||
theme,
|
||||
size: otherProps.size || 'md',
|
||||
variant: variant || 'primary',
|
||||
});
|
||||
return <DefaultLinkButton {...otherProps} variant={variant} styles={styles} ref={ref} />;
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { withStoryContainer } from '../../utils/storybook/withStoryContainer';
|
||||
import { Field } from './Field';
|
||||
import { Input } from './Input/Input';
|
||||
import { Button } from './Button';
|
||||
import { Button } from '../Button';
|
||||
import { Form } from './Form';
|
||||
import { Switch } from './Switch';
|
||||
import { Checkbox } from './Checkbox';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { boolean, text, select, number } from '@storybook/addon-knobs';
|
||||
import { withCenteredStory } from '../../../utils/storybook/withCenteredStory';
|
||||
import { Input } from './Input';
|
||||
import { Button } from '../Button';
|
||||
import { Button } from '../../Button';
|
||||
import mdx from './Input.mdx';
|
||||
import { getAvailableIcons, IconType } from '../../Icon/types';
|
||||
import { KeyValue } from '@grafana/data';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
|
||||
import { Button, ButtonVariant, ButtonProps } from '../Button';
|
||||
import { Button, ButtonVariant, ButtonProps } from '../../Button';
|
||||
import { ComponentSize } from '../../../types/size';
|
||||
import { SelectCommonProps, CustomControlProps } from './types';
|
||||
import { SelectBase } from './SelectBase';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { SelectableValue } from '@grafana/data';
|
||||
import { getAvailableIcons, IconType } from '../../Icon/types';
|
||||
import { select, boolean } from '@storybook/addon-knobs';
|
||||
import { Icon } from '../../Icon/Icon';
|
||||
import { Button } from '../Button';
|
||||
import { Button } from '../../Button';
|
||||
import { ButtonSelect } from './ButtonSelect';
|
||||
import { getIconKnob } from '../../../utils/storybook/knobs';
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { GrafanaTheme } from '@grafana/data';
|
||||
import { getLabelStyles } from './Label';
|
||||
import { getLegendStyles } from './Legend';
|
||||
import { getFieldValidationMessageStyles } from './FieldValidationMessage';
|
||||
import { getButtonStyles, ButtonVariant } from './Button';
|
||||
import { getButtonStyles, ButtonVariant } from '../Button';
|
||||
import { ComponentSize } from '../../types/size';
|
||||
import { getInputStyles } from './Input/Input';
|
||||
import { getSwitchStyles } from './Switch';
|
||||
|
||||
@@ -7,21 +7,22 @@ import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup';
|
||||
import { AsyncSelect, Select } from './Select/Select';
|
||||
import { Form } from './Form';
|
||||
import { Field } from './Field';
|
||||
import { Button, LinkButton } from './Button';
|
||||
import { Switch } from './Switch';
|
||||
import { TextArea } from './TextArea/TextArea';
|
||||
import { Checkbox } from './Checkbox';
|
||||
//Will be removed after Enterprise changes have been merged
|
||||
import { Button, LinkButton } from '../Button';
|
||||
|
||||
const Forms = {
|
||||
RadioButtonGroup,
|
||||
Button,
|
||||
LinkButton,
|
||||
Switch,
|
||||
getFormStyles,
|
||||
Label,
|
||||
Input,
|
||||
Form,
|
||||
Field,
|
||||
Button,
|
||||
LinkButton,
|
||||
Select,
|
||||
ButtonSelect,
|
||||
InputControl,
|
||||
@@ -30,5 +31,4 @@ const Forms = {
|
||||
Checkbox,
|
||||
};
|
||||
|
||||
export { ButtonVariant } from './Button';
|
||||
export default Forms;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { VerticalGroup, HorizontalGroup, Layout } from './Layout';
|
||||
import { Button } from '../Forms/Button';
|
||||
import { Button } from '../Button';
|
||||
import { withStoryContainer } from '../../utils/storybook/withStoryContainer';
|
||||
import { select } from '@storybook/addon-knobs';
|
||||
|
||||
@@ -11,7 +11,7 @@ export default {
|
||||
decorators: [withStoryContainer, withCenteredStory, withHorizontallyCenteredStory],
|
||||
};
|
||||
|
||||
const justifyVariants = ['flex-start', 'flex-end', 'space-between'];
|
||||
const justifyVariants = ['flex-start', 'flex-end', 'space-betw een'];
|
||||
|
||||
const spacingVariants = ['xs', 'sm', 'md', 'lg'];
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class UnThemedLogDetailsRow extends PureComponent<Props, State> {
|
||||
<>
|
||||
|
||||
<LinkButton
|
||||
variant={'transparent'}
|
||||
variant="link"
|
||||
size={'sm'}
|
||||
icon={cx('fa', link.onClick ? 'fa-list' : 'fa-external-link')}
|
||||
href={link.href}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { stylesFactory } from '../../themes';
|
||||
import { Button, ButtonVariant } from '../Forms/Button';
|
||||
import { Button, ButtonVariant } from '../Button';
|
||||
|
||||
interface Props {
|
||||
currentPage: number;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { ChangeEvent, KeyboardEvent, PureComponent } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { stylesFactory } from '../../themes/stylesFactory';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
import { Input } from '../Input/Input';
|
||||
import { TagItem } from './TagItem';
|
||||
|
||||
@@ -106,7 +106,7 @@ export class TagsInput extends PureComponent<Props, State> {
|
||||
)}
|
||||
>
|
||||
<Input placeholder="Add Name" onChange={this.onNameChange} value={newTag} onKeyUp={this.onKeyboardAdd} />
|
||||
<Button className={getStyles().addButtonStyle} onClick={this.onAdd} variant="secondary" size="md">
|
||||
<Button className={getStyles().addButtonStyle} onClick={this.onAdd} variant="primary" size="md">
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ import { stylesFactory } from '../../themes';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { RadioButtonGroup } from '../Forms/RadioButtonGroup/RadioButtonGroup';
|
||||
import { Field } from '../Forms/Field';
|
||||
import { Button } from '../Forms/Button';
|
||||
import { Button } from '../Button';
|
||||
import { FullWidthButtonContainer } from '../Button/FullWidthButtonContainer';
|
||||
|
||||
const modes: Array<SelectableValue<ThresholdsMode>> = [
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@ import { GrafanaTheme, dateTime, TIME_FORMAT } from '@grafana/data';
|
||||
import { stringToDateTimeType } from '../time';
|
||||
import { useTheme, stylesFactory } from '../../../themes';
|
||||
import { TimePickerTitle } from './TimePickerTitle';
|
||||
import Forms from '../../Forms';
|
||||
import { Button } from '../../Button';
|
||||
import { Portal } from '../../Portal/Portal';
|
||||
import { getThemeColors } from './colors';
|
||||
import { ClickOutsideWrapper } from '../../ClickOutsideWrapper/ClickOutsideWrapper';
|
||||
@@ -281,12 +281,12 @@ const Footer = memo<Props>(({ onClose, onApply }) => {
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Forms.Button className={styles.apply} onClick={onApply}>
|
||||
<Button className={styles.apply} onClick={onApply}>
|
||||
Apply time range
|
||||
</Forms.Button>
|
||||
<Forms.Button variant="secondary" onClick={onClose}>
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={onClose}>
|
||||
Cancel
|
||||
</Forms.Button>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { stringToDateTimeType, isValidTimeString } from '../time';
|
||||
import { mapStringsToTimeRange } from './mapper';
|
||||
import { TimePickerCalendar } from './TimePickerCalendar';
|
||||
import Forms from '../../Forms';
|
||||
import { Button } from '../../Button';
|
||||
|
||||
interface Props {
|
||||
isFullscreen: boolean;
|
||||
@@ -60,7 +61,7 @@ export const TimeRangeForm: React.FC<Props> = props => {
|
||||
[timeZone]
|
||||
);
|
||||
|
||||
const icon = isFullscreen ? null : <Forms.Button icon="fa fa-calendar" variant="secondary" onClick={onOpen} />;
|
||||
const icon = isFullscreen ? null : <Button icon="fa fa-calendar" variant="secondary" onClick={onOpen} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -82,7 +83,7 @@ export const TimeRangeForm: React.FC<Props> = props => {
|
||||
value={to.value}
|
||||
/>
|
||||
</Forms.Field>
|
||||
<Forms.Button onClick={onApply}>Apply time range</Forms.Button>
|
||||
<Button onClick={onApply}>Apply time range</Button>
|
||||
|
||||
<TimePickerCalendar
|
||||
isFullscreen={isFullscreen}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Select } from '../Select/Select';
|
||||
import { transformersUIRegistry } from './transformers';
|
||||
import React from 'react';
|
||||
import { TransformationRow } from './TransformationRow';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
import { css } from 'emotion';
|
||||
|
||||
interface TransformationsEditorState {
|
||||
@@ -118,7 +118,7 @@ export class TransformationsEditor extends React.PureComponent<TransformationsEd
|
||||
return (
|
||||
<>
|
||||
{this.renderTransformationEditors()}
|
||||
<Button variant="inverse" icon="fa fa-plus" onClick={this.onTransformationAdd}>
|
||||
<Button variant="secondary" icon="fa fa-plus" onClick={this.onTransformationAdd}>
|
||||
Add transformation
|
||||
</Button>
|
||||
</>
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
||||
|
||||
import LegacyMappingRow from './LegacyMappingRow';
|
||||
import { MappingType, ValueMapping } from '@grafana/data';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button } from '../Button';
|
||||
import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup';
|
||||
|
||||
export interface Props {
|
||||
@@ -98,7 +98,7 @@ export class LegacyValueMappingsEditor extends PureComponent<Props, State> {
|
||||
removeValueMapping={() => this.onRemoveMapping(valueMapping.id)}
|
||||
/>
|
||||
))}
|
||||
<Button variant="inverse" icon="fa fa-plus" onClick={this.onAddMapping}>
|
||||
<Button variant="primary" icon="fa fa-plus" onClick={this.onAddMapping}>
|
||||
Add mapping
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { MappingType, ValueMapping } from '@grafana/data';
|
||||
import Forms from '../Forms';
|
||||
import { Button } from '../Button/Button';
|
||||
import { FullWidthButtonContainer } from '../Button/FullWidthButtonContainer';
|
||||
import { MappingRow } from './MappingRow';
|
||||
|
||||
@@ -66,9 +66,9 @@ export const ValueMappingsEditor: React.FC<Props> = ({ valueMappings, onChange,
|
||||
</>
|
||||
)}
|
||||
<FullWidthButtonContainer>
|
||||
<Forms.Button size="sm" icon="fa fa-plus" onClick={onAdd} aria-label="ValueMappingsEditor add mapping button">
|
||||
<Button size="sm" icon="fa fa-plus" onClick={onAdd} aria-label="ValueMappingsEditor add mapping button">
|
||||
Add mapping
|
||||
</Forms.Button>
|
||||
</Button>
|
||||
</FullWidthButtonContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ exports[`Render should render component 1`] = `
|
||||
<Button
|
||||
icon="fa fa-plus"
|
||||
onClick={[Function]}
|
||||
variant="inverse"
|
||||
variant="primary"
|
||||
>
|
||||
Add mapping
|
||||
</Button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { IconType } from '../Icon/types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, ButtonVariant } from '../Forms/Button';
|
||||
import { Button, ButtonVariant } from '../Button';
|
||||
import { Select } from '../Forms/Select/Select';
|
||||
import { FullWidthButtonContainer } from '../Button/FullWidthButtonContainer';
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ export { Popover } from './Tooltip/Popover';
|
||||
export { Portal } from './Portal/Portal';
|
||||
export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
|
||||
|
||||
export * from './Button/Button';
|
||||
export { ClipboardButton } from './ClipboardButton/ClipboardButton';
|
||||
|
||||
// Select
|
||||
@@ -99,7 +98,7 @@ export { LogLabels } from './Logs/LogLabels';
|
||||
export { LogRows } from './Logs/LogRows';
|
||||
export { getLogRowStyles } from './Logs/getLogRowStyles';
|
||||
export { ToggleButtonGroup, ToggleButton } from './ToggleButtonGroup/ToggleButtonGroup';
|
||||
// Panel editors
|
||||
// Panel editors./Forms/Legacy/Button/FullWidthButtonContainer
|
||||
export { FullWidthButtonContainer } from './Button/FullWidthButtonContainer';
|
||||
export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
|
||||
export { ClickOutsideWrapper } from './ClickOutsideWrapper/ClickOutsideWrapper';
|
||||
@@ -151,7 +150,8 @@ export {
|
||||
export { FieldConfigItemHeaderTitle } from './FieldConfigs/FieldConfigItemHeaderTitle';
|
||||
|
||||
// Next-gen forms
|
||||
export { default as Forms, ButtonVariant } from './Forms';
|
||||
export { default as Forms } from './Forms';
|
||||
export * from './Button';
|
||||
export { ValuePicker } from './ValuePicker/ValuePicker';
|
||||
export { fieldMatchersUI } from './MatchersUI/fieldMatchersUI';
|
||||
export { getStandardFieldConfigs } from './FieldConfigs/standardFieldConfigEditors';
|
||||
|
||||
@@ -168,11 +168,11 @@ $table-bg-hover: $dark-6;
|
||||
|
||||
// Buttons
|
||||
// -------------------------
|
||||
$btn-secondary-bg: $blue-base;
|
||||
$btn-secondary-bg-hl: $blue-shade;
|
||||
$btn-primary-bg: $blue-base;
|
||||
$btn-primary-bg-hl: $blue-shade;
|
||||
|
||||
$btn-primary-bg: $green-base;
|
||||
$btn-primary-bg-hl: $green-shade;
|
||||
$btn-secondary-bg: $dark-6;
|
||||
$btn-secondary-bg-hl: lighten($dark-6, 4%);
|
||||
|
||||
$btn-success-bg: $green-base;
|
||||
$btn-success-bg-hl: $green-shade;
|
||||
|
||||
@@ -160,11 +160,11 @@ $table-bg-hover: $gray-5;
|
||||
|
||||
// Buttons
|
||||
// -------------------------
|
||||
$btn-primary-bg: $green-base;
|
||||
$btn-primary-bg-hl: $green-shade;
|
||||
$btn-secondary-bg: $gray-5;
|
||||
$btn-secondary-bg-hl: $gray-4;
|
||||
|
||||
$btn-secondary-bg: $blue-base;
|
||||
$btn-secondary-bg-hl: $blue-shade;
|
||||
$btn-primary-bg: $blue-base;
|
||||
$btn-primary-bg-hl: $blue-shade;
|
||||
|
||||
$btn-success-bg: $green-base;
|
||||
$btn-success-bg-hl: $green-shade;
|
||||
@@ -173,7 +173,6 @@ $btn-danger-bg: $red-base;
|
||||
$btn-danger-bg-hl: $red-shade;
|
||||
|
||||
$btn-inverse-bg: $gray-5;
|
||||
$btn-inverse-bg-hl: darken($gray-5, 5%);
|
||||
$btn-inverse-bg-hl: $gray-4;
|
||||
$btn-inverse-text-color: $gray-1;
|
||||
$btn-inverse-text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4);
|
||||
|
||||
Reference in New Issue
Block a user