|
| 1 | +import { useState } from 'react'; |
| 2 | +import PropTypes from 'prop-types'; |
| 3 | +const Tooltip = ({ |
| 4 | + children, |
| 5 | + content, |
| 6 | + position = 'bottom', |
| 7 | + delay = 300, |
| 8 | + className = '', |
| 9 | +}) => { |
| 10 | + const [isVisible, setIsVisible] = useState(false); |
| 11 | + const [isDelayed, setIsDelayed] = useState(false); |
| 12 | + const showTooltip = () => { |
| 13 | + const timer = setTimeout(() => { |
| 14 | + setIsDelayed(true); |
| 15 | + }, delay); |
| 16 | + setIsVisible(true); |
| 17 | + return () => clearTimeout(timer); |
| 18 | + }; |
| 19 | + const hideTooltip = () => { |
| 20 | + setIsVisible(false); |
| 21 | + setIsDelayed(false); |
| 22 | + }; |
| 23 | + // Position classes - increase the margins to create more space |
| 24 | + const positions = { |
| 25 | + top: 'bottom-full left-1/2 -translate-x-1/2 mb-8', |
| 26 | + bottom: 'top-full left-1/2 -translate-x-1/2 mt-10', |
| 27 | + left: 'right-full top-1/2 -translate-y-1/2 mr-8', |
| 28 | + right: 'left-full top-1/2 -translate-y-1/2 ml-8', |
| 29 | + }; |
| 30 | + // Custom background color for both tooltip and triangle |
| 31 | + const bgColor = '#526B78'; |
| 32 | + return ( |
| 33 | + <div |
| 34 | + className={`relative ${className}`} |
| 35 | + onMouseEnter={showTooltip} |
| 36 | + onMouseLeave={hideTooltip} |
| 37 | + onFocus={showTooltip} |
| 38 | + onBlur={hideTooltip} |
| 39 | + > |
| 40 | + {children} |
| 41 | + {isVisible && ( |
| 42 | + <div |
| 43 | + className={` |
| 44 | + absolute z-[9999] |
| 45 | + ${positions[position]} |
| 46 | + ${isDelayed ? 'opacity-100' : 'opacity-0'} |
| 47 | + transition-opacity duration-200 |
| 48 | + pointer-events-none |
| 49 | + `} |
| 50 | + > |
| 51 | + <div |
| 52 | + className="text-white text-xs font-medium p-10 rounded-md whitespace-nowrap shadow-xl" |
| 53 | + style={{ backgroundColor: bgColor }} |
| 54 | + > |
| 55 | + {content} |
| 56 | + {/* Triangle/Arrow - Reduced size */} |
| 57 | + {position === 'top' && ( |
| 58 | + <div |
| 59 | + className="absolute top-full left-1/2 -translate-x-1/2 border-solid border-l-[6px] border-r-[6px] border-t-[6px] border-l-transparent border-r-transparent" |
| 60 | + style={{ borderTopColor: bgColor }} |
| 61 | + ></div> |
| 62 | + )} |
| 63 | + {position === 'bottom' && ( |
| 64 | + <div |
| 65 | + className="absolute -top-[6px] left-1/2 -translate-x-1/2 border-solid border-l-[6px] border-r-[6px] border-b-[6px] border-l-transparent border-r-transparent" |
| 66 | + style={{ borderBottomColor: bgColor }} |
| 67 | + ></div> |
| 68 | + )} |
| 69 | + {position === 'left' && ( |
| 70 | + <div |
| 71 | + className="absolute top-1/2 -translate-y-1/2 right-[-6px] border-solid border-t-[6px] border-b-[6px] border-l-[6px] border-t-transparent border-b-transparent" |
| 72 | + style={{ borderLeftColor: bgColor }} |
| 73 | + ></div> |
| 74 | + )} |
| 75 | + {position === 'right' && ( |
| 76 | + <div |
| 77 | + className="absolute top-1/2 -translate-y-1/2 left-[-6px] border-solid border-t-[6px] border-b-[6px] border-r-[6px] border-t-transparent border-b-transparent" |
| 78 | + style={{ borderRightColor: bgColor }} |
| 79 | + ></div> |
| 80 | + )} |
| 81 | + </div> |
| 82 | + </div> |
| 83 | + )} |
| 84 | + </div> |
| 85 | + ); |
| 86 | +}; |
| 87 | + |
| 88 | +Tooltip.propTypes = { |
| 89 | + children: PropTypes.node.isRequired, |
| 90 | + content: PropTypes.node.isRequired, |
| 91 | + position: PropTypes.oneOf(['top', 'right', 'bottom', 'left']), |
| 92 | + delay: PropTypes.number, |
| 93 | + className: PropTypes.string, |
| 94 | +}; |
| 95 | + |
| 96 | +export default Tooltip; |
0 commit comments