+
Heading
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
+ eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+ ),
+ },
+};
diff --git a/packages/react/src/components/Tooltip/index.tsx b/packages/react/src/components/Tooltip/index.tsx
new file mode 100644
index 0000000..cce14a0
--- /dev/null
+++ b/packages/react/src/components/Tooltip/index.tsx
@@ -0,0 +1,109 @@
+import React, { PropsWithChildren, ReactElement, ReactNode } from "react";
+import { OverlayArrow } from "react-aria-components";
+import {
+ mergeProps,
+ useOverlayPosition,
+ useTooltip,
+ useTooltipTrigger,
+} from "react-aria";
+import { useTooltipTriggerState } from "react-stately";
+import classNames from "classnames";
+
+const ANIMATION_DURATION = 200;
+
+export interface TooltipProps extends PropsWithChildren {
+ placement?: "top" | "bottom" | "left" | "right";
+ content: ReactNode;
+ closeDelay?: number;
+ className?: string;
+}
+
+export const Tooltip = ({
+ placement = "bottom",
+ content,
+ closeDelay = 150,
+ className,
+ ...props
+}: TooltipProps) => {
+ const ref = React.useRef(null);
+ const overlayRef = React.useRef(null);
+ const [isExiting, setIsExiting] = React.useState(false);
+ const [isEntering, setIsEntering] = React.useState(false);
+ const state = useTooltipTriggerState({
+ delay: 0,
+ closeDelay,
+ onOpenChange: (isOpen) => {
+ if (isOpen) {
+ setIsEntering(true);
+ setTimeout(() => {
+ setIsEntering(false);
+ }, ANIMATION_DURATION);
+ } else {
+ setIsExiting(true);
+ setTimeout(() => {
+ setIsExiting(false);
+ }, ANIMATION_DURATION);
+ }
+ },
+ });
+
+ // Get props for the trigger and its tooltip
+ const useTooltipTriggerRes = useTooltipTrigger({}, state, ref);
+
+ // overlayPosition.placement can be difference than placement, based on available screen space.
+ const overlayPosition = useOverlayPosition({
+ targetRef: ref,
+ overlayRef,
+ placement,
+ isOpen: state.isOpen,
+ });
+
+ const { tooltipProps: tooltipProps2 } = useTooltip(
+ useTooltipTriggerRes.tooltipProps,
+ state,
+ );
+
+ const arrowProps = {
+ placement: overlayPosition.placement,
+ };
+
+ const showTooltip = state.isOpen || isExiting;
+
+ return (
+ <>
+ {React.cloneElement(
+ React.Children.toArray(props.children)[0] as ReactElement,
+ {
+ ref,
+ ...useTooltipTriggerRes.triggerProps,
+ },
+ )}
+
+ {showTooltip && (
+