import { useContext, useRef } from "react"; import { Overlay, useOverlayPosition, AriaPositionProps, PositionProps, } from "@react-aria/overlays"; import { useTooltip } from "@react-aria/tooltip"; import { OverlayTriggerProps } from "react-stately"; import { Transition } from "react-transition-group"; import { ToolTipArrow, ToolTipOverlay } from "./ToolTip.styles"; import { RenderBaseProps } from "../../../types"; import { TooltipContext, TooltipStateContext } from "./ToolTip.context"; import { useContextProps } from "../../../hooks/useContextProps"; import { mergeProps } from "@react-aria/utils"; import { useRenderProps } from "@hooks"; export interface ToolTipProps extends PositionProps, Pick, OverlayTriggerProps, RenderBaseProps { /** * The ref for the element which the tooltip positions itself with respect to. * * When used within a TooltipTrigger this is set automatically. It is only required when used standalone. */ triggerRef?: React.RefObject; /* Placement of the tooltip relative to the target element */ placement?: "right" | "left" | "top" | "bottom"; /* Time in milliseconds for the tooltip to fade in and out */ transitionDuration?: number; } /** A ToolTip component displays a popup with additional information when a user hovers over or focuses on an element. */ export function ToolTip(props: ToolTipProps) { let ref = useRef(null); [props, ref] = useContextProps(TooltipContext, props, ref); const { triggerRef, transitionDuration = 300, ...rest } = props; const state = useContext(TooltipStateContext); const { tooltipProps } = useTooltip({ ...rest }, state); const { overlayProps, arrowProps, placement } = useOverlayPosition({ targetRef: triggerRef!, overlayRef: ref, isOpen: state.isOpen, placement: props.placement || "top", offset: props.offset ?? 2, crossOffset: props.crossOffset, arrowBoundaryOffset: props.arrowBoundaryOffset, shouldFlip: props.shouldFlip, }); const renderProps = useRenderProps({ componentClassName: "aje-tooltip", ...props, }); const mergedProps = mergeProps(overlayProps, tooltipProps, renderProps); return ( {(state) => ( {renderProps.children} )} ); }