mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Grafana-UI: Export Card container styles (#33386)
* Export Card container styles * Export CardContainer as a separate component * Update story * Remove tooltip
This commit is contained in:
parent
0d1cdbe227
commit
1336a57e99
@ -21,13 +21,9 @@ export default {
|
||||
knobs: {
|
||||
disable: true,
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
heading: { control: { disable: true } },
|
||||
description: { control: { disable: true } },
|
||||
href: { control: { disable: true } },
|
||||
tooltip: { control: { disable: true } },
|
||||
onClick: { control: { disable: true } },
|
||||
controls: {
|
||||
exclude: ['onClick', 'href', 'heading', 'description', 'className'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -63,17 +59,6 @@ export const AsLink: Story<Props> = ({ disabled }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const WithTooltip: Story<Props> = ({ disabled }) => {
|
||||
return (
|
||||
<Card
|
||||
heading="Reduce"
|
||||
description="Reduce all rows or data points to a single value using a function like max, min, mean or last."
|
||||
tooltip="Click to apply this transformation."
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithTags: Story<Props> = ({ disabled }) => {
|
||||
return (
|
||||
<Card heading="Elasticsearch – Custom Templated Query" disabled={disabled}>
|
||||
|
@ -1,50 +1,13 @@
|
||||
import React, { memo, cloneElement, FC, HTMLAttributes, ReactNode, useCallback } from 'react';
|
||||
import React, { memo, cloneElement, FC, ReactNode, useCallback } from 'react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaThemeV2 } from '@grafana/data';
|
||||
import { useTheme2, styleMixins, stylesFactory } from '../../themes';
|
||||
import { Tooltip, PopoverContent } from '../Tooltip/Tooltip';
|
||||
import { useTheme2, stylesFactory } from '../../themes';
|
||||
import { CardContainer, CardContainerProps } from './CardContainer';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ContainerProps extends HTMLAttributes<HTMLOrSVGElement> {
|
||||
/** Content for the card's tooltip */
|
||||
tooltip?: PopoverContent;
|
||||
}
|
||||
|
||||
const CardContainer: FC<ContainerProps> = ({ children, tooltip, ...props }) => {
|
||||
return tooltip ? (
|
||||
<Tooltip placement="top" content={tooltip} theme="info">
|
||||
<div {...props}>{children}</div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div {...props}>{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface CardInnerProps {
|
||||
href?: string;
|
||||
}
|
||||
|
||||
const CardInner: FC<CardInnerProps> = ({ children, href }) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getCardStyles(theme);
|
||||
return href ? (
|
||||
<a className={styles.innerLink} href={href}>
|
||||
{children}
|
||||
</a>
|
||||
) : (
|
||||
<div className={styles.innerLink}>{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Props extends ContainerProps {
|
||||
export interface Props extends Omit<CardContainerProps, 'disableEvents' | 'disableHover'> {
|
||||
/** Main heading for the Card **/
|
||||
heading: ReactNode;
|
||||
/** Card description text */
|
||||
@ -74,7 +37,6 @@ export const Card: CardInterface = ({
|
||||
heading,
|
||||
description,
|
||||
disabled,
|
||||
tooltip,
|
||||
href,
|
||||
onClick,
|
||||
className,
|
||||
@ -100,66 +62,40 @@ export const Card: CardInterface = ({
|
||||
const disableHover = disabled || (!onClick && !href);
|
||||
const disableEvents = disabled && !actions;
|
||||
|
||||
const containerStyles = getContainerStyles(theme, disableEvents, disableHover);
|
||||
const onCardClick = useCallback(() => (disableHover ? () => {} : onClick?.()), [disableHover, onClick]);
|
||||
|
||||
return (
|
||||
<CardContainer
|
||||
tooltip={tooltip}
|
||||
tabIndex={disableHover ? undefined : 0}
|
||||
className={cx(containerStyles, className)}
|
||||
onClick={onCardClick}
|
||||
disableEvents={disableEvents}
|
||||
disableHover={disableHover}
|
||||
href={href}
|
||||
{...htmlProps}
|
||||
>
|
||||
<CardInner href={href}>
|
||||
{figure}
|
||||
<div className={styles.inner}>
|
||||
<div className={styles.info}>
|
||||
<div>
|
||||
<div className={styles.heading} role="heading">
|
||||
{heading}
|
||||
</div>
|
||||
{meta}
|
||||
{description && <p className={styles.description}>{description}</p>}
|
||||
{figure}
|
||||
<div className={styles.inner}>
|
||||
<div className={styles.info}>
|
||||
<div>
|
||||
<div className={styles.heading} role="heading">
|
||||
{heading}
|
||||
</div>
|
||||
{tags}
|
||||
{meta}
|
||||
{description && <p className={styles.description}>{description}</p>}
|
||||
</div>
|
||||
{hasActions && (
|
||||
<div className={styles.actionRow}>
|
||||
{actions}
|
||||
{secondaryActions}
|
||||
</div>
|
||||
)}
|
||||
{tags}
|
||||
</div>
|
||||
</CardInner>
|
||||
{hasActions && (
|
||||
<div className={styles.actionRow}>
|
||||
{actions}
|
||||
{secondaryActions}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const getContainerStyles = stylesFactory((theme: GrafanaThemeV2, disabled = false, disableHover = false) => {
|
||||
return css({
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
background: theme.colors.background.secondary,
|
||||
borderRadius: theme.shape.borderRadius(),
|
||||
position: 'relative',
|
||||
pointerEvents: disabled ? 'none' : 'auto',
|
||||
marginBottom: theme.spacing(1),
|
||||
transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
...(!disableHover && {
|
||||
'&:hover': {
|
||||
background: theme.colors.emphasize(theme.colors.background.secondary, 0.03),
|
||||
cursor: 'pointer',
|
||||
zIndex: 1,
|
||||
},
|
||||
'&:focus': styleMixins.getFocusStyles(theme),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -245,11 +181,6 @@ export const getCardStyles = stylesFactory((theme: GrafanaThemeV2) => {
|
||||
separator: css`
|
||||
margin: 0 ${theme.spacing(1)};
|
||||
`,
|
||||
innerLink: css`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: ${theme.spacing(2)};
|
||||
`,
|
||||
tagList: css`
|
||||
max-width: 50%;
|
||||
`,
|
||||
|
84
packages/grafana-ui/src/components/Card/CardContainer.tsx
Normal file
84
packages/grafana-ui/src/components/Card/CardContainer.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import React, { HTMLAttributes, ReactNode } from 'react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaThemeV2 } from '@grafana/data';
|
||||
import { styleMixins, stylesFactory, useTheme2 } from '../../themes';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface CardInnerProps {
|
||||
href?: string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const CardInner = ({ children, href }: CardInnerProps) => {
|
||||
const theme = useTheme2();
|
||||
const { inner } = getCardContainerStyles(theme);
|
||||
return href ? (
|
||||
<a className={inner} href={href}>
|
||||
{children}
|
||||
</a>
|
||||
) : (
|
||||
<div className={inner}>{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface CardContainerProps extends HTMLAttributes<HTMLOrSVGElement>, CardInnerProps {
|
||||
/** Disable pointer events for the Card, e.g. click events */
|
||||
disableEvents?: boolean;
|
||||
/** No style change on hover */
|
||||
disableHover?: boolean;
|
||||
/** Custom container styles */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const CardContainer = ({
|
||||
href,
|
||||
children,
|
||||
disableEvents,
|
||||
disableHover,
|
||||
className,
|
||||
...props
|
||||
}: CardContainerProps) => {
|
||||
const theme = useTheme2();
|
||||
const { container } = getCardContainerStyles(theme, disableEvents, disableHover);
|
||||
return (
|
||||
<div {...props} className={cx(container, className)}>
|
||||
<CardInner href={href}>{children}</CardInner>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getCardContainerStyles = stylesFactory((theme: GrafanaThemeV2, disabled = false, disableHover = false) => {
|
||||
return {
|
||||
container: css({
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
background: theme.colors.background.secondary,
|
||||
borderRadius: theme.shape.borderRadius(),
|
||||
position: 'relative',
|
||||
pointerEvents: disabled ? 'none' : 'auto',
|
||||
marginBottom: theme.spacing(1),
|
||||
transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
...(!disableHover && {
|
||||
'&:hover': {
|
||||
background: theme.colors.emphasize(theme.colors.background.secondary, 0.03),
|
||||
cursor: 'pointer',
|
||||
zIndex: 1,
|
||||
},
|
||||
'&:focus': styleMixins.getFocusStyles(theme),
|
||||
}),
|
||||
}),
|
||||
inner: css({
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
padding: theme.spacing(2),
|
||||
}),
|
||||
};
|
||||
});
|
@ -189,7 +189,8 @@ export { Checkbox } from './Forms/Checkbox';
|
||||
export { TextArea } from './TextArea/TextArea';
|
||||
export { FileUpload } from './FileUpload/FileUpload';
|
||||
export { TimeRangeInput } from './TimePicker/TimeRangeInput';
|
||||
export { Card, Props as CardProps, ContainerProps, CardInnerProps, getCardStyles } from './Card/Card';
|
||||
export { Card, Props as CardProps, getCardStyles } from './Card/Card';
|
||||
export { CardContainer, CardContainerProps } from './Card/CardContainer';
|
||||
export { FormattedValueDisplay } from './FormattedValueDisplay/FormattedValueDisplay';
|
||||
|
||||
export { ButtonSelect } from './Dropdown/ButtonSelect';
|
||||
|
Loading…
Reference in New Issue
Block a user