|
1 | 1 | import { useState, useRef, useEffect, CSSProperties } from 'react'; |
2 | 2 | import Portal from './Portal'; // Import your Portal component |
3 | 3 |
|
4 | | -export const Tooltip = ({ children, content, verticalOffset = 12, position: positionProp }: Tooltip) => { |
| 4 | +export const Tooltip = ({ children, content, verticalOffset = 12 }: Tooltip) => { |
5 | 5 | const [show, setShow] = useState<boolean>(false); |
6 | 6 | const [position, setPosition] = useState<CSSProperties>({}); |
7 | 7 | const tooltipRef = useRef(null); |
8 | 8 | const contentRef = useRef(null); // Ref for the tooltip content |
9 | 9 |
|
10 | 10 | useEffect(() => { |
11 | 11 | if (tooltipRef.current && contentRef.current && show) { |
12 | | - // Use requestAnimationFrame to ensure tooltip is rendered and measured correctly |
13 | | - requestAnimationFrame(() => { |
14 | | - if (tooltipRef.current && contentRef.current) { |
15 | | - const targetRect = tooltipRef.current.getBoundingClientRect(); |
16 | | - const tooltipRect = contentRef.current.getBoundingClientRect(); |
17 | | - |
18 | | - let left: number; |
19 | | - let top: number; |
20 | | - |
21 | | - // If position prop is 'right', position to the right of the element |
22 | | - if (positionProp === 'right') { |
23 | | - left = targetRect.right + window.scrollX + verticalOffset; |
24 | | - top = targetRect.top + window.scrollY + (targetRect.height / 2) - (tooltipRect.height / 2); |
25 | | - |
26 | | - // Check if the tooltip is going off the right side of the screen |
27 | | - if (left + tooltipRect.width > window.innerWidth + window.scrollX) { |
28 | | - // If it goes off right, position it to the left of the element instead |
29 | | - left = targetRect.left + window.scrollX - tooltipRect.width - verticalOffset; |
30 | | - } |
31 | | - } else { |
32 | | - // Default: position tooltip below the element (centered) |
33 | | - left = targetRect.left + window.scrollX + (targetRect.width / 2); |
34 | | - top = targetRect.bottom + window.scrollY + verticalOffset; |
35 | | - |
36 | | - // Check if the tooltip is going off the right side of the screen |
37 | | - if (left + tooltipRect.width / 2 > window.innerWidth + window.scrollX) { |
38 | | - left = window.innerWidth + window.scrollX - tooltipRect.width / 2 - 10; |
39 | | - } |
40 | | - // Check if the tooltip is going off the left side of the screen |
41 | | - if (left - tooltipRect.width / 2 < window.scrollX) { |
42 | | - left = window.scrollX + tooltipRect.width / 2 + 10; |
43 | | - } |
44 | | - } |
45 | | - |
46 | | - // Check if the tooltip is going off the top of the screen |
47 | | - if (top < window.scrollY) { |
48 | | - top = window.scrollY + 10; |
49 | | - } |
50 | | - // Check if the tooltip is going off the bottom of the screen |
51 | | - if (top + tooltipRect.height > window.innerHeight + window.scrollY) { |
52 | | - top = window.innerHeight + window.scrollY - tooltipRect.height - 10; |
53 | | - } |
54 | | - |
55 | | - setPosition({ |
56 | | - top: top, |
57 | | - left: left, |
58 | | - position: 'absolute', |
59 | | - // For default positioning (below), center using transform |
60 | | - transform: positionProp === 'right' ? 'none' : 'translateX(-50%)' |
61 | | - }); |
62 | | - } |
| 12 | + const targetRect = tooltipRef.current.getBoundingClientRect(); |
| 13 | + const tooltipRect = contentRef.current.getBoundingClientRect(); |
| 14 | + |
| 15 | + let left = targetRect.left + window.scrollX + (targetRect.width / 2); // Center align |
| 16 | + const top = targetRect.bottom + window.scrollY + verticalOffset; |
| 17 | + |
| 18 | + // Check if the tooltip is going off the right side of the screen |
| 19 | + if (left + tooltipRect.width > window.innerWidth) { |
| 20 | + left = window.innerWidth - tooltipRect.width / 2 - 10; // Adjust to keep it on screen |
| 21 | + } |
| 22 | + // Check if the tooltip is going off the left side of the screen |
| 23 | + if (left - tooltipRect.width / 2 < 0) { |
| 24 | + left += 10; // Adjust to keep it on screen |
| 25 | + } |
| 26 | + |
| 27 | + setPosition({ |
| 28 | + top: top, |
| 29 | + left: left, |
| 30 | + position: 'absolute' |
63 | 31 | }); |
64 | 32 | } |
65 | | - }, [show, content, verticalOffset, positionProp]); |
| 33 | + }, [show, content, verticalOffset]); // Added 'content' to dependencies array |
66 | 34 |
|
67 | 35 | return ( |
68 | | - <span className="tooltip-wrapper" |
| 36 | + <span className="tooltip-wrapper" |
69 | 37 | onMouseEnter={() => setShow(true)} |
70 | 38 | onMouseLeave={() => setShow(false)} |
71 | 39 | ref={tooltipRef}> |
72 | 40 | {children} |
73 | 41 | {show && ( |
74 | 42 | <Portal> |
75 | | - <div className={`tooltip-box ${show ? 'show' : ''} ${positionProp === 'right' ? 'arrow-left' : ''}`} ref={contentRef} style={position}> |
| 43 | + <div className={`tooltip-box ${show ? 'show' : ''}`} ref={contentRef} style={position}> |
76 | 44 | <div className="tooltip-arrow" /> |
77 | 45 | <div style={{ whiteSpace: 'pre-line' }}>{content}</div> |
78 | 46 | </div> |
|
0 commit comments