100 lines
2.5 KiB
TypeScript

import {forwardRef} from "@nextui-org/system";
import {useMemo} from "react";
import {OverlayContainer} from "@react-aria/overlays";
import {AnimatePresence, motion} from "framer-motion";
import {TRANSITION_VARIANTS} from "@nextui-org/framer-transitions";
import {warn} from "@nextui-org/shared-utils";
import {Children, cloneElement} from "react";
import {getTransformOrigins} from "@nextui-org/aria-utils";
import {UseTooltipProps, useTooltip} from "./use-tooltip";
export interface TooltipProps extends Omit<UseTooltipProps, "ref"> {}
const Tooltip = forwardRef<TooltipProps, "div">((props, ref) => {
const {
Component,
children,
content,
isOpen,
placement,
disableAnimation,
motionProps,
showArrow,
getTriggerProps,
getTooltipProps,
getArrowProps,
} = useTooltip({
ref,
...props,
});
let trigger: React.ReactElement;
try {
/**
* Ensure tooltip has only one child node
*/
const child = Children.only(children) as React.ReactElement & {
ref?: React.Ref<any>;
};
trigger = cloneElement(child, getTriggerProps(child.props, child.ref));
} catch (error) {
trigger = <span />;
warn("Tooltip must have only one child node. Please, check your code.");
}
const arrowContent = useMemo(() => {
if (!showArrow) return null;
return <span {...getArrowProps()} />;
}, [showArrow, getArrowProps]);
const animatedContent = useMemo(() => {
const {className, ...otherTooltipProps} = getTooltipProps();
return (
<div {...otherTooltipProps}>
<motion.div
animate="enter"
exit="exit"
initial="exit"
style={{
...getTransformOrigins(placement),
}}
variants={TRANSITION_VARIANTS.scaleSpring}
{...motionProps}
>
<Component className={className}>
{content}
{arrowContent}
</Component>
</motion.div>
</div>
);
}, [getTooltipProps, placement, motionProps, Component, content, arrowContent]);
return (
<>
{trigger}
{disableAnimation && isOpen ? (
<OverlayContainer>
<Component {...getTooltipProps()}>
{content}
{arrowContent}
</Component>
</OverlayContainer>
) : (
<AnimatePresence initial={false}>
{isOpen ? <OverlayContainer>{animatedContent}</OverlayContainer> : null}
</AnimatePresence>
)}
</>
);
});
Tooltip.displayName = "NextUI.Tooltip";
export default Tooltip;