mirror of
https://git.meshkee.com/Meshkee/dashboards.git
synced 2026-08-11 22:30:58 +04:30
Add customer and business user-product flows across dashboards.
Ship my-products / customer-products UI with gallery uploads, status controls, module gating, and related shared UI polish. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
c5bdaad16b
commit
1271d96539
@@ -1,4 +1,5 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import { useEffect, useRef, useState, type ReactElement } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import styles from './Tooltip.module.css'
|
||||
|
||||
interface TooltipProps {
|
||||
@@ -7,12 +8,70 @@ interface TooltipProps {
|
||||
}
|
||||
|
||||
export function Tooltip({ label, children }: TooltipProps) {
|
||||
const wrapRef = useRef<HTMLSpanElement>(null)
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [coords, setCoords] = useState({ top: 0, left: 0 })
|
||||
|
||||
function updatePosition() {
|
||||
const el = wrapRef.current
|
||||
if (!el) return
|
||||
const rect = el.getBoundingClientRect()
|
||||
setCoords({
|
||||
top: rect.top - 8,
|
||||
left: rect.left + rect.width / 2,
|
||||
})
|
||||
}
|
||||
|
||||
function show() {
|
||||
updatePosition()
|
||||
setVisible(true)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
setVisible(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible) return
|
||||
|
||||
function onReposition() {
|
||||
updatePosition()
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', onReposition, true)
|
||||
window.addEventListener('resize', onReposition)
|
||||
return () => {
|
||||
window.removeEventListener('scroll', onReposition, true)
|
||||
window.removeEventListener('resize', onReposition)
|
||||
}
|
||||
}, [visible])
|
||||
|
||||
return (
|
||||
<span className={styles.wrap}>
|
||||
<span
|
||||
ref={wrapRef}
|
||||
className={styles.wrap}
|
||||
onMouseEnter={show}
|
||||
onMouseLeave={hide}
|
||||
onFocusCapture={show}
|
||||
onBlurCapture={(e) => {
|
||||
if (!wrapRef.current?.contains(e.relatedTarget as Node | null)) {
|
||||
hide()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<span className={styles.tip} role="tooltip">
|
||||
{label}
|
||||
</span>
|
||||
{visible
|
||||
? createPortal(
|
||||
<span
|
||||
className={`${styles.tip} ${styles.tipVisible}`}
|
||||
role="tooltip"
|
||||
style={{ top: coords.top, left: coords.left }}
|
||||
>
|
||||
{label}
|
||||
</span>,
|
||||
document.body,
|
||||
)
|
||||
: null}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user