mirror of https://github.com/grafana/grafana
ToolbarButton: New emotion based component to replace all navbar, DashNavButton and scss styles (#30333)
* ToolbarButton: New emotion based component to replace all navbar, DashNavButton and scss styles * Component ready for use * Dam dam dam * Starting big button design update * Tried to use main button component but failed * Minor fix * Updates * Updated * Update packages/grafana-ui/src/components/Button/Button.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Update packages/grafana-ui/src/components/Button/ButtonGroup.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Updated to use spacing base * Button updates * Removd unused import * Remove unused import * Use correct theme variable for border-radius Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>pull/30364/head
parent
c0cddc303a
commit
abe808bcfd
@ -1,53 +0,0 @@ |
||||
import React from 'react'; |
||||
import { css } from 'emotion'; |
||||
import { stylesFactory, useTheme } from '../../themes'; |
||||
import { IconName } from '../../types/icon'; |
||||
import { Icon } from '../Icon/Icon'; |
||||
import { ComponentSize } from '../../types/size'; |
||||
import { GrafanaTheme } from '@grafana/data'; |
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => ({ |
||||
content: css` |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
white-space: nowrap; |
||||
height: 100%; |
||||
`,
|
||||
|
||||
icon: css` |
||||
& + * { |
||||
margin-left: ${theme.spacing.sm}; |
||||
} |
||||
`,
|
||||
})); |
||||
|
||||
type Props = { |
||||
icon?: IconName; |
||||
className?: string; |
||||
children: React.ReactNode; |
||||
size?: ComponentSize; |
||||
}; |
||||
|
||||
export function ButtonContent(props: Props) { |
||||
const { icon, children, size } = props; |
||||
const theme = useTheme(); |
||||
const styles = getStyles(theme); |
||||
|
||||
if (!children) { |
||||
return <span className={styles.content}>{icon && <Icon name={icon} size={size} />}</span>; |
||||
} |
||||
|
||||
const iconElement = icon && ( |
||||
<span className={styles.icon}> |
||||
<Icon name={icon} size={size} /> |
||||
</span> |
||||
); |
||||
|
||||
return ( |
||||
<span className={styles.content}> |
||||
{iconElement} |
||||
<span>{children}</span> |
||||
</span> |
||||
); |
||||
} |
@ -0,0 +1,54 @@ |
||||
import React, { forwardRef, HTMLAttributes } from 'react'; |
||||
import { css } from 'emotion'; |
||||
import { GrafanaTheme } from '@grafana/data'; |
||||
import { useStyles } from '../../themes'; |
||||
|
||||
export interface Props extends HTMLAttributes<HTMLDivElement> { |
||||
noSpacing?: boolean; |
||||
} |
||||
|
||||
export const ButtonGroup = forwardRef<HTMLDivElement, Props>(({ noSpacing, children, ...rest }, ref) => { |
||||
const styles = useStyles(getStyles); |
||||
const className = noSpacing ? styles.wrapperNoSpacing : styles.wrapper; |
||||
|
||||
return ( |
||||
<div ref={ref} className={className} {...rest}> |
||||
{children} |
||||
</div> |
||||
); |
||||
}); |
||||
|
||||
ButtonGroup.displayName = 'ButtonGroup'; |
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({ |
||||
wrapper: css` |
||||
display: flex; |
||||
|
||||
> a, |
||||
> button { |
||||
margin-left: ${theme.spacing.sm}; |
||||
|
||||
&:first-child { |
||||
margin-left: 0; |
||||
} |
||||
} |
||||
`,
|
||||
wrapperNoSpacing: css` |
||||
display: flex; |
||||
|
||||
> a, |
||||
> button { |
||||
border-radius: 0; |
||||
border-right: 0; |
||||
|
||||
&:last-child { |
||||
border-radius: 0 ${theme.border.radius.sm} ${theme.border.radius.sm} 0; |
||||
border-right: 1px solid ${theme.colors.border2}; |
||||
} |
||||
|
||||
&:first-child { |
||||
border-radius: ${theme.border.radius.sm} 0 0 ${theme.border.radius.sm}; |
||||
} |
||||
} |
||||
`,
|
||||
}); |
@ -0,0 +1,47 @@ |
||||
import React from 'react'; |
||||
import { ToolbarButton, ButtonGroup, useTheme, VerticalGroup } from '@grafana/ui'; |
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; |
||||
|
||||
export default { |
||||
title: 'Buttons/ToolbarButton', |
||||
component: ToolbarButton, |
||||
decorators: [withCenteredStory], |
||||
parameters: {}, |
||||
}; |
||||
|
||||
export const List = () => { |
||||
const theme = useTheme(); |
||||
|
||||
return ( |
||||
<div style={{ background: theme.colors.dashboardBg, padding: '32px' }}> |
||||
<VerticalGroup> |
||||
Wrapped in normal ButtonGroup (md spacing) |
||||
<ButtonGroup> |
||||
<ToolbarButton>Just text</ToolbarButton> |
||||
<ToolbarButton icon="sync" tooltip="Sync" /> |
||||
<ToolbarButton imgSrc="./grafana_icon.svg">With imgSrc</ToolbarButton> |
||||
<ToolbarButton icon="cloud" isOpen={true}> |
||||
isOpen |
||||
</ToolbarButton> |
||||
<ToolbarButton icon="cloud" isOpen={false}> |
||||
isOpen = false |
||||
</ToolbarButton> |
||||
</ButtonGroup> |
||||
<br /> |
||||
Wrapped in noSpacing ButtonGroup |
||||
<ButtonGroup noSpacing> |
||||
<ToolbarButton icon="clock-nine" tooltip="Time picker"> |
||||
2020-10-02 |
||||
</ToolbarButton> |
||||
<ToolbarButton icon="search-minus" /> |
||||
</ButtonGroup> |
||||
<br /> |
||||
Wrapped in noSpacing ButtonGroup |
||||
<ButtonGroup noSpacing> |
||||
<ToolbarButton icon="sync" /> |
||||
<ToolbarButton isOpen={false} narrow /> |
||||
</ButtonGroup> |
||||
</VerticalGroup> |
||||
</div> |
||||
); |
||||
}; |
@ -0,0 +1,103 @@ |
||||
import React, { forwardRef, HTMLAttributes } from 'react'; |
||||
import { cx, css } from 'emotion'; |
||||
import { GrafanaTheme } from '@grafana/data'; |
||||
import { styleMixins, useStyles } from '../../themes'; |
||||
import { IconName } from '../../types/icon'; |
||||
import { Tooltip } from '../Tooltip/Tooltip'; |
||||
import { Icon } from '../Icon/Icon'; |
||||
|
||||
export interface Props extends HTMLAttributes<HTMLButtonElement> { |
||||
/** Icon name */ |
||||
icon?: IconName; |
||||
/** Tooltip */ |
||||
tooltip?: string; |
||||
/** For image icons */ |
||||
imgSrc?: string; |
||||
/** if true or false will show angle-down/up */ |
||||
isOpen?: boolean; |
||||
/** Controls flex-grow: 1 */ |
||||
fullWidth?: boolean; |
||||
/** reduces padding to xs */ |
||||
narrow?: boolean; |
||||
} |
||||
|
||||
export const ToolbarButton = forwardRef<HTMLButtonElement, Props>( |
||||
({ tooltip, icon, className, children, imgSrc, fullWidth, isOpen, narrow, ...rest }, ref) => { |
||||
const styles = useStyles(getStyles); |
||||
|
||||
const contentStyles = cx({ |
||||
[styles.content]: true, |
||||
[styles.contentWithIcon]: !!icon, |
||||
[styles.contentWithRightIcon]: isOpen !== undefined, |
||||
}); |
||||
|
||||
const buttonStyles = cx( |
||||
{ |
||||
[styles.button]: true, |
||||
[styles.buttonFullWidth]: fullWidth, |
||||
[styles.narrow]: narrow, |
||||
}, |
||||
className |
||||
); |
||||
|
||||
const body = ( |
||||
<button ref={ref} className={buttonStyles} {...rest}> |
||||
{icon && <Icon name={icon} size={'lg'} />} |
||||
{imgSrc && <img className={styles.img} src={imgSrc} />} |
||||
{children && <span className={contentStyles}>{children}</span>} |
||||
{isOpen === false && <Icon name="angle-down" />} |
||||
{isOpen === true && <Icon name="angle-up" />} |
||||
</button> |
||||
); |
||||
|
||||
return tooltip ? ( |
||||
<Tooltip content={tooltip} placement="bottom"> |
||||
{body} |
||||
</Tooltip> |
||||
) : ( |
||||
body |
||||
); |
||||
} |
||||
); |
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({ |
||||
button: css` |
||||
background: ${theme.colors.bg1}; |
||||
border: 1px solid ${theme.colors.border2}; |
||||
height: ${theme.height.md}px; |
||||
padding: 0 ${theme.spacing.sm}; |
||||
color: ${theme.colors.textWeak}; |
||||
border-radius: ${theme.border.radius.sm}; |
||||
display: flex; |
||||
align-items: center; |
||||
|
||||
&:focus { |
||||
outline: none; |
||||
} |
||||
|
||||
&:hover { |
||||
color: ${theme.colors.text}; |
||||
background: ${styleMixins.hoverColor(theme.colors.bg1, theme)}; |
||||
} |
||||
`,
|
||||
narrow: css` |
||||
padding: 0 ${theme.spacing.xs}; |
||||
`,
|
||||
img: css` |
||||
width: 16px; |
||||
height: 16px; |
||||
margin-right: ${theme.spacing.sm}; |
||||
`,
|
||||
buttonFullWidth: css` |
||||
flex-grow: 1; |
||||
`,
|
||||
content: css` |
||||
flex-grow: 1; |
||||
`,
|
||||
contentWithIcon: css` |
||||
padding-left: ${theme.spacing.sm}; |
||||
`,
|
||||
contentWithRightIcon: css` |
||||
padding-right: ${theme.spacing.sm}; |
||||
`,
|
||||
}); |
@ -1 +1,3 @@ |
||||
export * from './Button'; |
||||
export { ButtonGroup } from './ButtonGroup'; |
||||
export { ToolbarButton } from './ToolbarButton'; |
||||
|
Loading…
Reference in new issue