{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "tooltip", "type": "registry:ui", "title": "Tooltip", "description": "A tooltip component that can be used to display additional information.", "dependencies": [ "class-variance-authority" ], "files": [ { "path": "registry/tra-kit/components/tooltip.tsx", "content": "import { cva } from 'class-variance-authority';\r\nimport React, { useEffect, useRef, useState } from 'react';\r\n\r\ntype TooltipPosition = 'top' | 'right' | 'bottom' | 'left';\r\n\r\ninterface ITooltip {\r\n content: string | Array;\r\n position?: TooltipPosition;\r\n children: React.ReactNode;\r\n delay?: number;\r\n className?: string;\r\n contentClassName?: string;\r\n arrow?: boolean;\r\n}\r\n\r\nconst arrowVariants = cva('absolute size-0 border-[5px] border-transparent', {\r\n variants: {\r\n tooltipPosition: {\r\n top: 'left-1/2 top-full -translate-x-1/2 border-t-neutral-black',\r\n bottom: 'bottom-full left-1/2 -translate-x-1/2 border-b-neutral-black',\r\n left: 'left-full top-1/2 -translate-y-1/2 border-l-neutral-black',\r\n right: 'right-full top-1/2 -translate-y-1/2 border-r-neutral-black',\r\n },\r\n },\r\n});\r\n\r\nconst Tooltip: React.FC = ({\r\n content,\r\n position = 'top',\r\n children,\r\n delay = 200,\r\n className = '',\r\n contentClassName = '',\r\n arrow = true,\r\n}) => {\r\n const [isVisible, setIsVisible] = useState(false);\r\n const [tooltipPosition, setTooltipPosition] = useState(position);\r\n const [tooltipStyle, setTooltipStyle] = useState({});\r\n const tooltipRef = useRef(null);\r\n const targetRef = useRef(null);\r\n const timeoutId = useRef | null>(null);\r\n\r\n const showTooltip = () => {\r\n timeoutId.current = setTimeout(() => setIsVisible(true), delay);\r\n };\r\n\r\n const hideTooltip = () => {\r\n if (timeoutId.current !== null) clearTimeout(timeoutId.current);\r\n setIsVisible(false);\r\n };\r\n\r\n useEffect(() => {\r\n const updatePosition = () => {\r\n if (tooltipRef.current && targetRef.current) {\r\n const targetRect = targetRef.current.getBoundingClientRect();\r\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\r\n const { innerHeight, innerWidth } = window;\r\n\r\n let newPosition = position;\r\n if (position === 'bottom' && targetRect.bottom + tooltipRect.height > innerHeight) {\r\n newPosition = 'top';\r\n } else if (position === 'top' && targetRect.top - tooltipRect.height < 0) {\r\n newPosition = 'bottom';\r\n } else if (position === 'right' && targetRect.right + tooltipRect.width > innerWidth) {\r\n newPosition = 'left';\r\n } else if (position === 'left' && targetRect.left - tooltipRect.width < 0) {\r\n newPosition = 'right';\r\n }\r\n\r\n setTooltipPosition(newPosition);\r\n }\r\n };\r\n\r\n if (isVisible) {\r\n updatePosition();\r\n window.addEventListener('resize', updatePosition);\r\n window.addEventListener('scroll', updatePosition);\r\n }\r\n\r\n return () => {\r\n window.removeEventListener('resize', updatePosition);\r\n window.removeEventListener('scroll', updatePosition);\r\n };\r\n }, [isVisible, position]);\r\n\r\n useEffect(() => {\r\n if (isVisible && tooltipRef.current && targetRef.current) {\r\n const targetRect = targetRef.current.getBoundingClientRect();\r\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\r\n\r\n let top = 0;\r\n let left = 0;\r\n\r\n switch (tooltipPosition) {\r\n case 'top':\r\n top = -tooltipRect.height - 10;\r\n left = targetRect.width / 2 - tooltipRect.width / 2;\r\n break;\r\n case 'bottom':\r\n top = targetRect.height + 10;\r\n left = targetRect.width / 2 - tooltipRect.width / 2;\r\n break;\r\n case 'left':\r\n top = targetRect.height / 2 - tooltipRect.height / 2;\r\n left = -tooltipRect.width - 10;\r\n break;\r\n case 'right':\r\n top = targetRect.height / 2 - tooltipRect.height / 2;\r\n left = targetRect.width + 10;\r\n break;\r\n default:\r\n break;\r\n }\r\n\r\n setTooltipStyle({ top: `${top}px`, left: `${left}px` });\r\n }\r\n }, [isVisible, tooltipPosition]);\r\n\r\n return (\r\n \r\n {children}\r\n {isVisible && (\r\n \r\n {Array.isArray(content) ? (\r\n
    \r\n {content.map((item, index) => (\r\n \r\n {item}\r\n \r\n ))}\r\n
\r\n ) : (\r\n content\r\n )}\r\n {arrow &&
}\r\n
\r\n )}\r\n \r\n );\r\n};\r\n\r\nexport default Tooltip;\r\n", "type": "registry:ui" } ] }