- Introduced DashboardObjectToolsContext and DashboardObjectToolsProvider for managing object tools state within the dashboard. - Added ChevronLeftIcon and ChevronRightIcon components for navigation buttons, enhancing user interface consistency. - Updated ObjectTableNavigationButtons to utilize new chevron icons and improved layout for better user experience. - Refactored KeyboardShortcut and Tooltip components for cleaner code and improved functionality.
122 lines
3.2 KiB
JavaScript
122 lines
3.2 KiB
JavaScript
import { cloneElement, isValidElement, useEffect, useId, useRef } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import { useTooltipContext } from '../context/TooltipContext'
|
|
|
|
const mergeHandler = (original, next) => (event) => {
|
|
next(event)
|
|
original?.(event)
|
|
}
|
|
|
|
const mergeRefs = (...refs) => (node) => {
|
|
refs.forEach((ref) => {
|
|
if (typeof ref === 'function') {
|
|
ref(node)
|
|
} else if (ref) {
|
|
ref.current = node
|
|
}
|
|
})
|
|
}
|
|
|
|
const Tooltip = ({
|
|
children,
|
|
title,
|
|
content,
|
|
listenParents = 0,
|
|
hideBorder = false
|
|
}) => {
|
|
const { showTooltip, hideTooltip } = useTooltipContext()
|
|
const id = useId()
|
|
const tooltipContent = title ?? content
|
|
const childRef = useRef(null)
|
|
const hoveredTargetsRef = useRef(new Set())
|
|
const hoveringRef = useRef(false)
|
|
const tooltipContentRef = useRef(tooltipContent)
|
|
const hideBorderRef = useRef(hideBorder)
|
|
tooltipContentRef.current = tooltipContent
|
|
hideBorderRef.current = hideBorder
|
|
|
|
useEffect(() => {
|
|
return () => hideTooltip(id)
|
|
}, [hideTooltip, id])
|
|
|
|
useEffect(() => {
|
|
if (hoveringRef.current) {
|
|
showTooltip(id, tooltipContent, undefined, undefined, hideBorder)
|
|
}
|
|
}, [id, showTooltip, tooltipContent, hideBorder])
|
|
|
|
const onMouseEnter = (event) => {
|
|
hoveredTargetsRef.current.add(event.currentTarget)
|
|
hoveringRef.current = true
|
|
showTooltip(
|
|
id,
|
|
tooltipContentRef.current,
|
|
event.clientX,
|
|
event.clientY,
|
|
hideBorderRef.current
|
|
)
|
|
}
|
|
|
|
const onMouseLeave = (event) => {
|
|
hoveredTargetsRef.current.delete(event.currentTarget)
|
|
if (hoveredTargetsRef.current.size > 0) return
|
|
hoveringRef.current = false
|
|
hideTooltip(id)
|
|
}
|
|
|
|
const onMouseEnterRef = useRef(onMouseEnter)
|
|
const onMouseLeaveRef = useRef(onMouseLeave)
|
|
onMouseEnterRef.current = onMouseEnter
|
|
onMouseLeaveRef.current = onMouseLeave
|
|
|
|
useEffect(() => {
|
|
const child = childRef.current
|
|
if (!child || listenParents < 1) return
|
|
|
|
const hoveredTargets = hoveredTargetsRef.current
|
|
|
|
const handleEnter = (event) => onMouseEnterRef.current(event)
|
|
const handleLeave = (event) => onMouseLeaveRef.current(event)
|
|
|
|
const parents = []
|
|
let current = child.parentElement
|
|
for (let i = 0; i < listenParents && current; i += 1) {
|
|
parents.push(current)
|
|
current = current.parentElement
|
|
}
|
|
|
|
parents.forEach((parent) => {
|
|
parent.addEventListener('mouseenter', handleEnter)
|
|
parent.addEventListener('mouseleave', handleLeave)
|
|
})
|
|
|
|
return () => {
|
|
parents.forEach((parent) => {
|
|
parent.removeEventListener('mouseenter', handleEnter)
|
|
parent.removeEventListener('mouseleave', handleLeave)
|
|
})
|
|
hoveredTargets.clear()
|
|
}
|
|
}, [listenParents])
|
|
|
|
if (!isValidElement(children)) {
|
|
return children
|
|
}
|
|
|
|
return cloneElement(children, {
|
|
ref: mergeRefs(children.ref, childRef),
|
|
onMouseEnter: mergeHandler(children.props.onMouseEnter, onMouseEnter),
|
|
onMouseLeave: mergeHandler(children.props.onMouseLeave, onMouseLeave)
|
|
})
|
|
}
|
|
|
|
Tooltip.propTypes = {
|
|
children: PropTypes.node.isRequired,
|
|
title: PropTypes.node,
|
|
content: PropTypes.node,
|
|
listenParents: PropTypes.number,
|
|
hideBorder: PropTypes.bool
|
|
}
|
|
|
|
export default Tooltip
|