mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tags: Make Tags component more a11y-friendly (#43808)
This commit is contained in:
parent
d1a94c1fa2
commit
cc9e70be5c
@ -22,19 +22,20 @@ export const Tag = forwardRef<HTMLElement, Props>(({ name, onClick, className, c
|
||||
const styles = getTagStyles(theme, name, colorIndex);
|
||||
|
||||
const onTagClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
if (onClick) {
|
||||
onClick(name, event);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
onClick?.(name, event);
|
||||
};
|
||||
|
||||
return (
|
||||
<span
|
||||
key={name}
|
||||
ref={ref}
|
||||
onClick={onTagClick}
|
||||
className={cx(styles.wrapper, className, onClick && styles.hover)}
|
||||
{...rest}
|
||||
>
|
||||
const classes = cx(styles.wrapper, className, { [styles.hover]: onClick !== undefined });
|
||||
|
||||
return onClick ? (
|
||||
<button {...rest} className={classes} onClick={onTagClick} ref={ref as React.ForwardedRef<HTMLButtonElement>}>
|
||||
{name}
|
||||
</button>
|
||||
) : (
|
||||
<span {...rest} className={classes} ref={ref}>
|
||||
{name}
|
||||
</span>
|
||||
);
|
||||
@ -51,6 +52,8 @@ const getTagStyles = (theme: GrafanaTheme, name: string, colorIndex?: number) =>
|
||||
}
|
||||
return {
|
||||
wrapper: css`
|
||||
appearance: none;
|
||||
border-style: none;
|
||||
font-weight: ${theme.typography.weight.semibold};
|
||||
font-size: ${theme.typography.size.sm};
|
||||
line-height: ${theme.typography.lineHeight.xs};
|
||||
|
@ -10,21 +10,24 @@ export interface Props {
|
||||
onClick?: OnTagClick;
|
||||
/** Custom styles for the wrapper component */
|
||||
className?: string;
|
||||
/** aria-label for the `i`-th Tag component */
|
||||
getAriaLabel?: (name: string, i: number) => string;
|
||||
}
|
||||
|
||||
export const TagList: FC<Props> = memo(({ displayMax, tags, onClick, className }) => {
|
||||
export const TagList: FC<Props> = memo(({ displayMax, tags, onClick, className, getAriaLabel }) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme, Boolean(displayMax && displayMax > 0));
|
||||
const numTags = tags.length;
|
||||
const tagsToDisplay = displayMax ? tags.slice(0, displayMax) : tags;
|
||||
|
||||
return (
|
||||
<span className={cx(styles.wrapper, className)}>
|
||||
{tagsToDisplay.map((tag) => (
|
||||
<Tag key={tag} name={tag} onClick={onClick} />
|
||||
<ul className={cx(styles.wrapper, className)} aria-label="Tags">
|
||||
{tagsToDisplay.map((tag, i) => (
|
||||
<li className={styles.li} key={tag}>
|
||||
<Tag name={tag} onClick={onClick} aria-label={getAriaLabel?.(tag, i)} />
|
||||
</li>
|
||||
))}
|
||||
{displayMax && displayMax > 0 && numTags - 1 > 0 && <span className={styles.moreTagsLabel}>+ {numTags - 1}</span>}
|
||||
</span>
|
||||
</ul>
|
||||
);
|
||||
});
|
||||
|
||||
@ -33,6 +36,7 @@ TagList.displayName = 'TagList';
|
||||
const getStyles = (theme: GrafanaTheme2, isTruncated: boolean) => {
|
||||
return {
|
||||
wrapper: css`
|
||||
position: relative;
|
||||
align-items: ${isTruncated ? 'center' : 'unset'};
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
@ -45,5 +49,8 @@ const getStyles = (theme: GrafanaTheme2, isTruncated: boolean) => {
|
||||
color: ${theme.colors.text.secondary};
|
||||
font-size: ${theme.typography.size.sm};
|
||||
`,
|
||||
li: css({
|
||||
listStyle: 'none',
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
@ -78,7 +78,7 @@ export const SearchItem: FC<Props> = ({ item, editable, onToggleChecked, onTagSe
|
||||
)}
|
||||
</Card.Meta>
|
||||
<Card.Tags>
|
||||
<TagList tags={item.tags} onClick={tagSelected} />
|
||||
<TagList tags={item.tags} onClick={tagSelected} getAriaLabel={(tag) => `Filter by tag "${tag}"`} />
|
||||
</Card.Tags>
|
||||
</Card>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user