mirror of
https://github.com/grafana/grafana.git
synced 2025-09-19 21:24:56 +08:00

* 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>
138 lines
3.8 KiB
TypeScript
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};
|
|
}
|
|
`;
|
|
},
|
|
});
|