Enhance CursorTooltip with Visibility Control and CSS Transitions
- Updated the CursorTooltip component to accept a new `visible` prop, allowing for better control over tooltip visibility. - Refactored tooltip rendering logic to utilize CSS transitions for smoother fade-in and fade-out effects, improving user experience. - Enhanced TooltipContext to manage tooltip visibility state and timing, ensuring consistent behavior during interactions. - Updated CSS styles for the cursor tooltip to support new visibility transitions, enhancing visual feedback.
This commit is contained in:
parent
ef57837371
commit
80ac635bf9
@ -361,6 +361,16 @@ code {
|
||||
padding: 8px !important;
|
||||
}
|
||||
|
||||
.cursor-tooltip {
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.cursor-tooltip.is-visible {
|
||||
opacity: 1;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
.cursor-tooltip .ant-card {
|
||||
box-shadow:
|
||||
0 6px 16px 0 rgba(0, 0, 0, 0.08),
|
||||
|
||||
@ -15,7 +15,7 @@ const getTooltipRoot = () => {
|
||||
return root
|
||||
}
|
||||
|
||||
const CursorTooltip = ({ content, pointRef }) => {
|
||||
const CursorTooltip = ({ content, visible, pointRef }) => {
|
||||
const tooltipRef = useRef(null)
|
||||
const sizeRef = useRef({ width: 0, height: 0 })
|
||||
const frameRef = useRef(null)
|
||||
@ -94,23 +94,19 @@ const CursorTooltip = ({ content, pointRef }) => {
|
||||
}
|
||||
}, [applyPosition, root, schedulePosition])
|
||||
|
||||
const visible = content != null && content !== false && content !== ''
|
||||
|
||||
if (!root) return null
|
||||
|
||||
return createPortal(
|
||||
<div
|
||||
ref={tooltipRef}
|
||||
className='cursor-tooltip'
|
||||
className={`cursor-tooltip${visible ? ' is-visible' : ''}`}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1100,
|
||||
pointerEvents: 'none',
|
||||
visibility: visible ? 'visible' : 'hidden',
|
||||
opacity: visible ? 1 : 0,
|
||||
willChange: 'transform'
|
||||
willChange: 'transform, opacity'
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
@ -131,6 +127,7 @@ const CursorTooltip = ({ content, pointRef }) => {
|
||||
|
||||
CursorTooltip.propTypes = {
|
||||
content: PropTypes.node,
|
||||
visible: PropTypes.bool,
|
||||
pointRef: PropTypes.shape({
|
||||
current: PropTypes.shape({
|
||||
x: PropTypes.number,
|
||||
|
||||
@ -11,11 +11,31 @@ import CursorTooltip from '../common/CursorTooltip'
|
||||
|
||||
const TooltipContext = createContext(null)
|
||||
|
||||
const HIDE_DELAY_MS = 100
|
||||
const FADE_OUT_MS = 500
|
||||
|
||||
export const TooltipProvider = ({ children }) => {
|
||||
const [content, setContent] = useState(null)
|
||||
const [visible, setVisible] = useState(false)
|
||||
const stackRef = useRef([])
|
||||
const hideTimerRef = useRef(null)
|
||||
const fadeTimerRef = useRef(null)
|
||||
const pointRef = useRef({ x: 0, y: 0 })
|
||||
const visibleRef = useRef(false)
|
||||
visibleRef.current = visible
|
||||
|
||||
const clearTimers = useCallback(() => {
|
||||
if (hideTimerRef.current != null) {
|
||||
window.clearTimeout(hideTimerRef.current)
|
||||
hideTimerRef.current = null
|
||||
}
|
||||
if (fadeTimerRef.current != null) {
|
||||
window.clearTimeout(fadeTimerRef.current)
|
||||
fadeTimerRef.current = null
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => () => clearTimers(), [clearTimers])
|
||||
|
||||
useEffect(() => {
|
||||
const onMove = (event) => {
|
||||
@ -25,45 +45,62 @@ export const TooltipProvider = ({ children }) => {
|
||||
return () => window.removeEventListener('mousemove', onMove)
|
||||
}, [])
|
||||
|
||||
const showTooltip = useCallback((id, nextContent, x, y) => {
|
||||
if (nextContent == null || nextContent === false || nextContent === '') {
|
||||
return
|
||||
}
|
||||
const showTooltip = useCallback(
|
||||
(id, nextContent, x, y) => {
|
||||
if (nextContent == null || nextContent === false || nextContent === '') {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof x === 'number' && typeof y === 'number') {
|
||||
pointRef.current = { x, y }
|
||||
}
|
||||
if (typeof x === 'number' && typeof y === 'number') {
|
||||
pointRef.current = { x, y }
|
||||
}
|
||||
|
||||
if (hideTimerRef.current != null) {
|
||||
window.clearTimeout(hideTimerRef.current)
|
||||
hideTimerRef.current = null
|
||||
}
|
||||
clearTimers()
|
||||
|
||||
stackRef.current = [
|
||||
...stackRef.current.filter((entry) => entry.id !== id),
|
||||
{ id, content: nextContent }
|
||||
]
|
||||
setContent(nextContent)
|
||||
}, [])
|
||||
stackRef.current = [
|
||||
...stackRef.current.filter((entry) => entry.id !== id),
|
||||
{ id, content: nextContent }
|
||||
]
|
||||
setContent(nextContent)
|
||||
|
||||
const hideTooltip = useCallback((id) => {
|
||||
stackRef.current = stackRef.current.filter((entry) => entry.id !== id)
|
||||
const last = stackRef.current[stackRef.current.length - 1]
|
||||
if (!visibleRef.current) {
|
||||
window.requestAnimationFrame(() => setVisible(true))
|
||||
} else {
|
||||
setVisible(true)
|
||||
}
|
||||
},
|
||||
[clearTimers]
|
||||
)
|
||||
|
||||
if (hideTimerRef.current != null) {
|
||||
window.clearTimeout(hideTimerRef.current)
|
||||
}
|
||||
const hideTooltip = useCallback(
|
||||
(id) => {
|
||||
stackRef.current = stackRef.current.filter((entry) => entry.id !== id)
|
||||
const last = stackRef.current[stackRef.current.length - 1]
|
||||
|
||||
hideTimerRef.current = window.setTimeout(() => {
|
||||
hideTimerRef.current = null
|
||||
setContent(last?.content ?? null)
|
||||
}, 80)
|
||||
}, [])
|
||||
clearTimers()
|
||||
|
||||
if (last) {
|
||||
setContent(last.content)
|
||||
setVisible(true)
|
||||
return
|
||||
}
|
||||
|
||||
hideTimerRef.current = window.setTimeout(() => {
|
||||
hideTimerRef.current = null
|
||||
setVisible(false)
|
||||
fadeTimerRef.current = window.setTimeout(() => {
|
||||
fadeTimerRef.current = null
|
||||
setContent(null)
|
||||
}, FADE_OUT_MS)
|
||||
}, HIDE_DELAY_MS)
|
||||
},
|
||||
[clearTimers]
|
||||
)
|
||||
|
||||
return (
|
||||
<TooltipContext.Provider value={{ showTooltip, hideTooltip }}>
|
||||
{children}
|
||||
<CursorTooltip content={content} pointRef={pointRef} />
|
||||
<CursorTooltip content={content} visible={visible} pointRef={pointRef} />
|
||||
</TooltipContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user