All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Added a new KeyboardKey component for consistent keyboard key styling across the application. - Introduced KeyboardShortcut component to wrap buttons with keyboard shortcut hints, improving user accessibility. - Enhanced Tooltip and CursorTooltip components to support a hideBorder prop, allowing for customizable tooltip appearances. - Updated CSS styles for keyboard keys in light and dark modes, ensuring visual consistency and improved user experience.
127 lines
3.3 KiB
JavaScript
127 lines
3.3 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 Tooltip = ({
|
|
children,
|
|
title,
|
|
content,
|
|
listenParents = 0,
|
|
hideBorder = false
|
|
}) => {
|
|
const { showTooltip, hideTooltip } = useTooltipContext()
|
|
const id = useId()
|
|
const tooltipContent = title ?? content
|
|
const spanRef = 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 span = spanRef.current
|
|
if (!span || listenParents < 1) return
|
|
|
|
const hoveredTargets = hoveredTargetsRef.current
|
|
|
|
const handleEnter = (event) => onMouseEnterRef.current(event)
|
|
const handleLeave = (event) => onMouseLeaveRef.current(event)
|
|
|
|
const parents = []
|
|
let current = span.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])
|
|
|
|
const wrapWithSpan = (node) => (
|
|
<span ref={spanRef} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
|
{node}
|
|
</span>
|
|
)
|
|
|
|
if (isValidElement(children)) {
|
|
const trigger = cloneElement(children, {
|
|
onMouseEnter: mergeHandler(children.props.onMouseEnter, onMouseEnter),
|
|
onMouseLeave: mergeHandler(children.props.onMouseLeave, onMouseLeave)
|
|
})
|
|
|
|
if (listenParents > 0) {
|
|
return wrapWithSpan(children)
|
|
}
|
|
|
|
if (children.props.disabled) {
|
|
return wrapWithSpan(trigger)
|
|
}
|
|
|
|
return trigger
|
|
}
|
|
|
|
return wrapWithSpan(children)
|
|
}
|
|
|
|
Tooltip.propTypes = {
|
|
children: PropTypes.node.isRequired,
|
|
title: PropTypes.node,
|
|
content: PropTypes.node,
|
|
listenParents: PropTypes.number,
|
|
hideBorder: PropTypes.bool
|
|
}
|
|
|
|
export default Tooltip
|