From ce1cfc609423c79bcdc27ad4123f896bd1d2e0cc Mon Sep 17 00:00:00 2001 From: bluestreak Date: Sun, 11 Jan 2026 23:02:22 +0000 Subject: [PATCH] fix: resolve news image zoom flickering on hover The hover timeout variable was declared as a local variable inside the component function, causing it to reset on every re-render. When the zoom overlay appeared, it intercepted mouse events, triggering onMouseOut on the thumbnail, which then dismissed the zoom and caused flickering. Changes: - Use useRef for hover timeout to persist across re-renders - Track imageToZoom state with a ref to prevent dismiss when zoom is visible - Add click-to-dismiss on both overlay and zoomed image - Add cursor: pointer for better UX Co-Authored-By: Claude Opus 4.5 --- src/scenes/News/image-zoom.tsx | 9 +++++++-- src/scenes/News/index.tsx | 24 +++++++++++++++--------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/scenes/News/image-zoom.tsx b/src/scenes/News/image-zoom.tsx index 5427b37f4..0973fd081 100644 --- a/src/scenes/News/image-zoom.tsx +++ b/src/scenes/News/image-zoom.tsx @@ -26,10 +26,12 @@ const Overlay = styled.div<{ visible: boolean }>` opacity: ${({ visible }) => (visible ? 1 : 0)}; pointer-events: ${({ visible }) => (visible ? "auto" : "none")}; transition: opacity 0.2s ease-in-out; + cursor: pointer; ` const Wrapper = styled.div` z-index: 1001; + cursor: pointer; img { border: 1px solid ${({ theme }) => theme.color.offWhite}; @@ -72,9 +74,12 @@ export const ImageZoom = () => { return ( - + dispatch(actions.console.setImageToZoom(undefined))} + /> {imageToZoom && ( - + dispatch(actions.console.setImageToZoom(undefined))}> { // This boolean is to animate the bell icon and display a bullet indicator const [hasUnreadNews, setHasUnreadNews] = useState(false) const activeSidebar = useSelector(selectors.console.getActiveSidebar) + const imageToZoom = useSelector(selectors.console.getImageToZoom) - let hoverTimeout: ReturnType + const hoverTimeoutRef = useRef>() + const imageToZoomRef = useRef(imageToZoom) + imageToZoomRef.current = imageToZoom const getEnterpriseNews = async () => { setIsLoading(true) @@ -248,7 +251,7 @@ const News = () => { ? { onMouseOver: () => { if (newsItem.thumbnail) { - hoverTimeout = setTimeout(() => { + hoverTimeoutRef.current = setTimeout(() => { if (newsItem && newsItem.thumbnail) { dispatch( actions.console.setImageToZoom({ @@ -268,12 +271,15 @@ const News = () => { } }, onMouseOut: () => { - clearTimeout(hoverTimeout) - setTimeout(() => { - dispatch( - actions.console.setImageToZoom(undefined), - ) - }, 250) + clearTimeout(hoverTimeoutRef.current) + // Only dismiss if zoom isn't visible (overlay intercepts mouse when visible) + if (!imageToZoomRef.current) { + setTimeout(() => { + dispatch( + actions.console.setImageToZoom(undefined), + ) + }, 250) + } }, } : {})}