import { css } from '@emotion/css'; import { CSSProperties, ReactNode, useMemo } from 'react'; import tinycolor2 from 'tinycolor2'; import { GrafanaTheme2, IconName } from '@grafana/data'; import { Icon, Stack, useStyles2 } from '@grafana/ui'; export type LabelSize = 'md' | 'sm' | 'xs'; interface Props { icon?: IconName; label?: ReactNode; value: ReactNode; color?: string; size?: LabelSize; onClick?: (label: string, value: string) => void; } // TODO allow customization with color prop const Label = ({ label, value, icon, color, size = 'md', onClick }: Props) => { const styles = useStyles2(getStyles, color, size); const ariaLabel = `${label}: ${value}`; const labelStr = label?.toString() ?? ''; const valueStr = value?.toString() ?? ''; const innerLabel = useMemo( () => (
{icon && } {label && ( {label ?? ''} )}
{value ?? '-'}
), [icon, label, value, styles] ); return (
{onClick ? (
onClick(labelStr, valueStr)} onKeyDown={(e) => { // needed for accessiblity: handle keyboard navigation if (e.key === 'Enter') { onClick(labelStr, valueStr); e.preventDefault(); } }} > {innerLabel}
) : ( innerLabel )}
); }; const getStyles = (theme: GrafanaTheme2, color?: string, size?: string) => { const backgroundColor = color ?? theme.colors.secondary.main; const borderColor = theme.isDark ? tinycolor2(backgroundColor).lighten(5).toString() : tinycolor2(backgroundColor).darken(5).toString(); const valueBackgroundColor = theme.isDark ? tinycolor2(backgroundColor).darken(5).toString() : tinycolor2(backgroundColor).lighten(5).toString(); const fontColor = color ? tinycolor2.mostReadable(backgroundColor, ['#000', '#fff']).toString() : theme.colors.text.primary; let padding: CSSProperties['padding'] = theme.spacing(0.33, 1); switch (size) { case 'sm': padding = theme.spacing(0.2, 0.6); break; case 'xs': padding = theme.spacing(0, 0.5); break; default: break; } return { wrapper: css({ color: fontColor, fontSize: theme.typography.bodySmall.fontSize, borderRadius: theme.shape.borderRadius(2), }), labelText: css({ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '300px', }), label: css({ display: 'flex', alignItems: 'center', color: 'inherit', padding: padding, background: backgroundColor, border: `solid 1px ${borderColor}`, borderTopLeftRadius: theme.shape.borderRadius(2), borderBottomLeftRadius: theme.shape.borderRadius(2), }), clickable: css({ '&:hover': { opacity: 0.8, cursor: 'pointer', }, }), value: css({ color: 'inherit', padding: padding, background: valueBackgroundColor, border: `solid 1px ${borderColor}`, borderLeft: 'none', borderTopRightRadius: theme.shape.borderRadius(2), borderBottomRightRadius: theme.shape.borderRadius(2), whiteSpace: 'pre', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '300px', }), }; }; export { Label };