From c557a3722fb7b08bd0f612c44ed72e91dc4ff0b6 Mon Sep 17 00:00:00 2001 From: Jean Brito Date: Wed, 14 Aug 2024 16:20:02 -0300 Subject: [PATCH] fix tooltip being stuck --- src/ui/components/SideBar/ServerButton.tsx | 2 +- src/ui/components/utils/TooltipProvider.tsx | 71 ++++++++++++++++----- src/ui/reducers/currentView.ts | 1 - 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/ui/components/SideBar/ServerButton.tsx b/src/ui/components/SideBar/ServerButton.tsx index 249eb0dd9..4f4e290b9 100644 --- a/src/ui/components/SideBar/ServerButton.tsx +++ b/src/ui/components/SideBar/ServerButton.tsx @@ -115,7 +115,7 @@ const ServerButton = ({ }` : '' } - ${!userLoggedIn ? 'User not logged in' : ''} + ${!userLoggedIn ? t('sidebar.tooltips.userNotLoggedIn') : ''} `.trim(); return ( diff --git a/src/ui/components/utils/TooltipProvider.tsx b/src/ui/components/utils/TooltipProvider.tsx index f923c8b04..808e6f3c3 100644 --- a/src/ui/components/utils/TooltipProvider.tsx +++ b/src/ui/components/utils/TooltipProvider.tsx @@ -1,6 +1,6 @@ import { useDebouncedState, useMediaQuery } from '@rocket.chat/fuselage-hooks'; import type { ReactNode } from 'react'; -import { useEffect, useMemo, useRef, memo, useCallback } from 'react'; +import { useEffect, useMemo, useRef, memo, useCallback, useState } from 'react'; import { TooltipComponent } from './TooltipComponent'; import { TooltipContext } from './TooltipContext'; @@ -11,7 +11,7 @@ type TooltipProviderProps = { }; const TooltipProvider = ({ children }: TooltipProviderProps) => { - const lastAnchor = useRef(null); + const lastAnchor = useRef(); const hasHover = !useMediaQuery('(hover: none)'); const [tooltip, setTooltip] = useDebouncedState(null, 300); @@ -26,7 +26,7 @@ const TooltipProvider = ({ children }: TooltipProviderProps) => { ); previousAnchor.removeAttribute('data-title'); } - }, 0); + }, 100); }, [] ); @@ -60,11 +60,13 @@ const TooltipProvider = ({ children }: TooltipProviderProps) => { close: (): void => { const previousAnchor = lastAnchor.current; setTooltip(null); - lastAnchor.current = null; + setTooltip.flush(); + lastAnchor.current = undefined; previousAnchor && restoreTitle(previousAnchor); }, dismiss: (): void => { setTooltip(null); + setTooltip.flush(); }, }), [setTooltip, restoreTitle] @@ -101,14 +103,55 @@ const TooltipProvider = ({ children }: TooltipProviderProps) => { return; } - contextValue.open(title, anchor); - }; - - const handleMouseLeave = (e: MouseEvent): void => { - const anchor = lastAnchor.current; - if (anchor && !anchor.contains(e.relatedTarget as Node)) { - contextValue.close(); - } + // eslint-disable-next-line react/no-multi-comp + const Handler = () => { + const [state, setState] = useState(title.split('\n')); + useEffect(() => { + const close = (): void => contextValue.close(); + // store the title in a data attribute + anchor.setAttribute('data-title', title); + // Removes the title attribute to prevent the browser's tooltip from showing + anchor.setAttribute('title', ''); + + anchor.addEventListener('mouseleave', close); + + const observer = new MutationObserver(() => { + const updatedTitle = + anchor.getAttribute('title') ?? + anchor.getAttribute('data-tooltip') ?? + ''; + + if (updatedTitle === '') { + return; + } + + // store the title in a data attribute + anchor.setAttribute('data-title', updatedTitle); + // Removes the title attribute to prevent the browser's tooltip from showing + anchor.setAttribute('title', ''); + + setState(updatedTitle.split('\n')); + }); + + observer.observe(anchor, { + attributes: true, + attributeFilter: ['title', 'data-tooltip'], + }); + + return () => { + anchor.removeEventListener('mouseleave', close); + observer.disconnect(); + }; + }, []); + return ( + <> + {state.map((line, index) => ( +
{line}
+ ))} + + ); + }; + contextValue.open(, anchor); }; const dismissOnClick = (): void => { @@ -118,15 +161,11 @@ const TooltipProvider = ({ children }: TooltipProviderProps) => { document.body.addEventListener('mouseover', handleMouseOver, { passive: true, }); - document.body.addEventListener('mouseleave', handleMouseLeave, { - passive: true, - }); document.body.addEventListener('click', dismissOnClick, { capture: true }); return (): void => { contextValue.close(); document.body.removeEventListener('mouseover', handleMouseOver); - document.body.removeEventListener('mouseleave', handleMouseLeave); document.body.removeEventListener('click', dismissOnClick); }; }, [contextValue, setTooltip, hasHover]); diff --git a/src/ui/reducers/currentView.ts b/src/ui/reducers/currentView.ts index a5676e12a..dd9f0f1ab 100644 --- a/src/ui/reducers/currentView.ts +++ b/src/ui/reducers/currentView.ts @@ -48,7 +48,6 @@ export const currentView = ( state: CurrentViewState = 'add-new-server', action: CurrentViewAction ): CurrentViewState => { - console.log(action.type); switch (action.type) { case ADD_SERVER_VIEW_SERVER_ADDED: case DEEP_LINKS_SERVER_ADDED: