Files
Virginia Cepeda 471a03328b Alerting: Allow to tab onto elements for a11y (#67684)
* Make search popover be tabbed onto

Co-Authored-By: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>

* Allow tokens in rule description to be tabbed onto

Co-Authored-By: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>

---------

Co-authored-by: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>
2023-05-03 09:37:42 -03:00

138 lines
3.8 KiB
TypeScript

import { css } from '@emotion/css';
import { Placement } from '@popperjs/core';
import classnames from 'classnames';
import React, { ReactElement, ReactNode, useRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { Popover as GrafanaPopover, PopoverController, useStyles2 } from '@grafana/ui';
export interface HoverCardProps {
children: ReactElement;
header?: ReactNode;
content: ReactElement;
footer?: ReactNode;
wrapperClassName?: string;
placement?: Placement;
disabled?: boolean;
showAfter?: number;
arrow?: boolean;
}
export const HoverCard = ({
children,
header,
content,
footer,
arrow,
showAfter = 300,
wrapperClassName,
disabled = false,
...rest
}: HoverCardProps) => {
const popoverRef = useRef<HTMLElement>(null);
const styles = useStyles2(getStyles);
if (disabled) {
return children;
}
const body = (
<Stack direction="column" gap={0}>
{header && <div className={styles.card.header}>{header}</div>}
<div className={styles.card.body}>{content}</div>
{footer && <div className={styles.card.footer}>{footer}</div>}
</Stack>
);
return (
<PopoverController content={body} hideAfter={100}>
{(showPopper, hidePopper, popperProps) => {
return (
<>
{popoverRef.current && (
<GrafanaPopover
{...popperProps}
{...rest}
wrapperClassName={classnames(styles.popover(arrow ? 1.25 : 0), wrapperClassName)}
onMouseLeave={hidePopper}
onMouseEnter={showPopper}
onFocus={showPopper}
onBlur={hidePopper}
referenceElement={popoverRef.current}
renderArrow={
arrow
? ({ arrowProps, placement }) => <div className={styles.arrow(placement)} {...arrowProps} />
: () => <></>
}
/>
)}
{React.cloneElement(children, {
ref: popoverRef,
onMouseEnter: showPopper,
onMouseLeave: hidePopper,
onFocus: showPopper,
onBlur: hidePopper,
})}
</>
);
}}
</PopoverController>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
popover: (offset: number) => css`
border-radius: ${theme.shape.borderRadius()};
box-shadow: ${theme.shadows.z3};
background: ${theme.colors.background.primary};
border: 1px solid ${theme.colors.border.medium};
margin-bottom: ${theme.spacing(offset)};
`,
card: {
body: css`
padding: ${theme.spacing(1)};
`,
header: css`
padding: ${theme.spacing(1)};
background: ${theme.colors.background.secondary};
border-bottom: solid 1px ${theme.colors.border.medium};
`,
footer: css`
padding: ${theme.spacing(0.5)} ${theme.spacing(1)};
background: ${theme.colors.background.secondary};
border-top: solid 1px ${theme.colors.border.medium};
`,
},
// TODO currently only works with bottom placement
arrow: (placement: string) => {
const ARROW_SIZE = '9px';
return css`
width: 0;
height: 0;
border-left: ${ARROW_SIZE} solid transparent;
border-right: ${ARROW_SIZE} solid transparent;
/* using hex colors here because the border colors use alpha transparency */
border-top: ${ARROW_SIZE} solid ${theme.isLight ? '#d2d3d4' : '#2d3037'};
&:after {
content: '';
position: absolute;
border: ${ARROW_SIZE} solid ${theme.colors.background.primary};
border-bottom: 0;
border-left-color: transparent;
border-right-color: transparent;
margin-top: 1px;
bottom: 1px;
left: -${ARROW_SIZE};
}
`;
},
});