Compare commits

..

No commits in common. "fdb304505353a013dbd0a85627d5fd38c9445127" and "8ab2e057bbe6bccc7164277fd137a0d5036b1a59" have entirely different histories.

6 changed files with 53 additions and 157 deletions

View File

@ -361,16 +361,6 @@ code {
padding: 8px !important;
}
.cursor-tooltip {
opacity: 0;
transition: opacity 0.25s 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),
@ -1558,8 +1548,3 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
.ant-splitter-bar-dragger::after {
content: none;
}
.dashboard-splitter.farmcontrol-splitter
.ant-splitter-panel.dashboard-splitter-content-panel {
flex-grow: 1 !important;
}

View File

@ -15,7 +15,7 @@ const getTooltipRoot = () => {
return root
}
const CursorTooltip = ({ content, visible, pointRef }) => {
const CursorTooltip = ({ content, pointRef }) => {
const tooltipRef = useRef(null)
const sizeRef = useRef({ width: 0, height: 0 })
const frameRef = useRef(null)
@ -94,19 +94,23 @@ const CursorTooltip = ({ content, visible, pointRef }) => {
}
}, [applyPosition, root, schedulePosition])
const visible = content != null && content !== false && content !== ''
if (!root) return null
return createPortal(
<div
ref={tooltipRef}
className={`cursor-tooltip${visible ? ' is-visible' : ''}`}
className='cursor-tooltip'
style={{
position: 'fixed',
top: 0,
left: 0,
zIndex: 1100,
pointerEvents: 'none',
willChange: 'transform, opacity'
visibility: visible ? 'visible' : 'hidden',
opacity: visible ? 1 : 0,
willChange: 'transform'
}}
>
<Card
@ -127,7 +131,6 @@ const CursorTooltip = ({ content, visible, pointRef }) => {
CursorTooltip.propTypes = {
content: PropTypes.node,
visible: PropTypes.bool,
pointRef: PropTypes.shape({
current: PropTypes.shape({
x: PropTypes.number,

View File

@ -1,10 +1,4 @@
import {
cloneElement,
isValidElement,
useState,
useEffect,
useContext
} from 'react'
import { cloneElement, isValidElement, useState, useEffect, useContext } from 'react'
import { Layout, Menu, Flex, Button } from 'antd'
import { CaretDownFilled } from '@ant-design/icons'
import CollapseSidebarIcon from '../../Icons/CollapseSidebarIcon'
@ -29,7 +23,7 @@ const CollapsedItemIcon = ({ className, icon, title }) => {
: icon
return (
<Tooltip title={title} listenParents={1}>
<Tooltip title={title}>
{iconNode ?? <span className={className} />}
</Tooltip>
)

View File

@ -208,9 +208,7 @@ const DashboardSidebarSplitter = ({ sidebar, children }) => {
>
{sidebarNode}
</Splitter.Panel>
<Splitter.Panel min={320} className='dashboard-splitter-content-panel'>
{children}
</Splitter.Panel>
<Splitter.Panel min={320}>{children}</Splitter.Panel>
</Splitter>
</Layout>
)

View File

@ -13,15 +13,11 @@ const mergeHandler = (original, next) => (event) => {
original?.(event)
}
const Tooltip = ({ children, title, content, listenParents = 0 }) => {
const Tooltip = ({ children, title, content }) => {
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)
tooltipContentRef.current = tooltipContent
useEffect(() => {
return () => hideTooltip(id)
@ -34,86 +30,43 @@ const Tooltip = ({ children, title, content, listenParents = 0 }) => {
}, [id, showTooltip, tooltipContent])
const onMouseEnter = (event) => {
hoveredTargetsRef.current.add(event.currentTarget)
hoveringRef.current = true
showTooltip(id, tooltipContentRef.current, event.clientX, event.clientY)
showTooltip(id, tooltipContent, event.clientX, event.clientY)
}
const onMouseLeave = (event) => {
hoveredTargetsRef.current.delete(event.currentTarget)
if (hoveredTargetsRef.current.size > 0) return
const onMouseLeave = () => {
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 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)
})
hoveredTargetsRef.current.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 (
<span onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
{trigger}
</span>
)
}
return trigger
}
return wrapWithSpan(children)
return (
<span onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
{children}
</span>
)
}
Tooltip.propTypes = {
children: PropTypes.node.isRequired,
title: PropTypes.node,
content: PropTypes.node,
listenParents: PropTypes.number
content: PropTypes.node
}
export default Tooltip

View File

@ -11,31 +11,11 @@ import CursorTooltip from '../common/CursorTooltip'
const TooltipContext = createContext(null)
const HIDE_DELAY_MS = 10
const FADE_OUT_MS = 250
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) => {
@ -45,8 +25,7 @@ export const TooltipProvider = ({ children }) => {
return () => window.removeEventListener('mousemove', onMove)
}, [])
const showTooltip = useCallback(
(id, nextContent, x, y) => {
const showTooltip = useCallback((id, nextContent, x, y) => {
if (nextContent == null || nextContent === false || nextContent === '') {
return
}
@ -55,52 +34,36 @@ export const TooltipProvider = ({ children }) => {
pointRef.current = { x, y }
}
clearTimers()
if (hideTimerRef.current != null) {
window.clearTimeout(hideTimerRef.current)
hideTimerRef.current = null
}
stackRef.current = [
...stackRef.current.filter((entry) => entry.id !== id),
{ id, content: nextContent }
]
setContent(nextContent)
}, [])
if (!visibleRef.current) {
window.requestAnimationFrame(() => setVisible(true))
} else {
setVisible(true)
}
},
[clearTimers]
)
const hideTooltip = useCallback(
(id) => {
const hideTooltip = useCallback((id) => {
stackRef.current = stackRef.current.filter((entry) => entry.id !== id)
const last = stackRef.current[stackRef.current.length - 1]
clearTimers()
if (last) {
setContent(last.content)
setVisible(true)
return
if (hideTimerRef.current != null) {
window.clearTimeout(hideTimerRef.current)
}
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]
)
setContent(last?.content ?? null)
}, 80)
}, [])
return (
<TooltipContext.Provider value={{ showTooltip, hideTooltip }}>
{children}
<CursorTooltip content={content} visible={visible} pointRef={pointRef} />
<CursorTooltip content={content} pointRef={pointRef} />
</TooltipContext.Provider>
)
}