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(null); const styles = useStyles2(getStyles); if (disabled) { return children; } const body = ( {header &&
{header}
}
{content}
{footer &&
{footer}
}
); return ( {(showPopper, hidePopper, popperProps) => { return ( <> {popoverRef.current && (
: () => <> } /> )} {React.cloneElement(children, { ref: popoverRef, onMouseEnter: showPopper, onMouseLeave: hidePopper, onFocus: showPopper, onBlur: hidePopper, })} ); }} ); }; 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}; } `; }, });