Skip to content

Commit 9893ea2

Browse files
authored
Merge pull request #386 from mijinummi/feat/smart-tooltip-component
Feat/smart tooltip component
2 parents 6cf7fce + 46953f9 commit 9893ea2

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React, { useState, useRef, useEffect } from 'react';
2+
import clsx from 'clsx';
3+
4+
export default function SmartTooltip({
5+
children,
6+
content,
7+
trigger = 'hover', // 'hover' or 'click'
8+
delay = 200,
9+
}) {
10+
const [visible, setVisible] = useState(false);
11+
const [position, setPosition] = useState('top');
12+
const timeoutRef = useRef(null);
13+
const wrapperRef = useRef(null);
14+
15+
const show = () => {
16+
timeoutRef.current = setTimeout(() => setVisible(true), delay);
17+
};
18+
19+
const hide = () => {
20+
clearTimeout(timeoutRef.current);
21+
setVisible(false);
22+
};
23+
24+
const toggle = () => setVisible((v) => !v);
25+
26+
useEffect(() => {
27+
if (visible && wrapperRef.current) {
28+
const rect = wrapperRef.current.getBoundingClientRect();
29+
const viewportHeight = window.innerHeight;
30+
setPosition(rect.top < viewportHeight / 2 ? 'bottom' : 'top');
31+
}
32+
}, [visible]);
33+
34+
const triggerProps =
35+
trigger === 'hover'
36+
? { onMouseEnter: show, onMouseLeave: hide }
37+
: { onClick: toggle };
38+
39+
return (
40+
<span className="relative inline-block" ref={wrapperRef} {...triggerProps}>
41+
{children}
42+
{visible && (
43+
<div
44+
role="tooltip"
45+
className={clsx(
46+
"absolute z-50 px-3 py-2 text-sm rounded shadow-lg bg-gray-800 text-white",
47+
position === 'top' ? "bottom-full mb-2" : "top-full mt-2"
48+
)}
49+
>
50+
{content}
51+
</div>
52+
)}
53+
</span>
54+
);
55+
}

0 commit comments

Comments
 (0)