Skip to content

Commit

Permalink
[GEN-1782]: fix tooltip UI & behavior (#1849)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenElferink authored Nov 25, 2024
1 parent 186b890 commit 6cda9b3
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,8 @@ export const ConfiguredFields: React.FC<ConfiguredFieldsProps> = ({ details }) =
<ListContainer>
{details.map((detail, index) => (
<ListItem key={index}>
<Tooltip text={detail.tooltip || ''}>
<Tooltip text={detail.tooltip || ''} withIcon>
<ItemTitle>{detail.title}</ItemTitle>
{detail.tooltip && <Image src='/icons/common/info.svg' alt='Info' width={12} height={12} style={{ marginLeft: 4 }} />}
</Tooltip>

{detail.title === 'Status' ? <Status isActive={detail.value == 'true'} withIcon withBorder withSmaller withSpecialFont /> : <ItemValue>{parseValue(detail.value)}</ItemValue>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,9 @@ const DrawerHeader = forwardRef<DrawerHeaderRef, DrawerHeaderProps>(({ title, ti
<Image src={imageUri} alt='Drawer Item' width={16} height={16} />
</DrawerItemImageWrapper>
{!isEdit && (
<>
<Tooltip text={titleTooltip} withIcon>
<Title>{title}</Title>
{!!titleTooltip && (
<Tooltip text={titleTooltip}>
<Image src='/icons/common/info.svg' alt='Info' width={16} height={16} />
</Tooltip>
)}
</>
</Tooltip>
)}
</SectionItemsWrapper>

Expand Down
12 changes: 5 additions & 7 deletions frontend/webapp/reuseable-components/checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,12 @@ const Checkbox: React.FC<CheckboxProps> = ({ title, titleColor, tooltip, initial
<CheckboxWrapper $isChecked={isChecked} $disabled={disabled}>
{isChecked && <Image src='/icons/common/check.svg' alt='' width={12} height={12} />}
</CheckboxWrapper>

{title && (
<Text size={12} color={titleColor || theme.text.grey} style={{ maxWidth: '90%' }}>
{title}
</Text>
)}
{tooltip && (
<Tooltip text={tooltip || ''}>
<Image src='/icons/common/info.svg' alt='' width={16} height={16} />
<Tooltip text={tooltip} withIcon>
<Text size={12} color={titleColor || theme.text.grey} style={{ maxWidth: '90%' }}>
{title}
</Text>
</Tooltip>
)}
</Container>
Expand Down
16 changes: 6 additions & 10 deletions frontend/webapp/reuseable-components/field-label/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import Image from 'next/image';
import { Text } from '../text';
import { Tooltip } from '../tooltip';
import styled from 'styled-components';
Expand Down Expand Up @@ -30,15 +29,12 @@ const FieldLabel = ({ title, required, tooltip, style }: { title?: string; requi
if (!title) return null;

return (
<Wrapper style={style}>
<Title>{title}</Title>
{!required && <OptionalText>(optional)</OptionalText>}
{tooltip && (
<Tooltip text={tooltip || ''}>
<Image src='/icons/common/info.svg' alt='' width={16} height={16} style={{ marginBottom: 4 }} />
</Tooltip>
)}
</Wrapper>
<Tooltip text={tooltip} withIcon>
<Wrapper style={style}>
<Title>{title}</Title>
{!required && <OptionalText>(optional)</OptionalText>}
</Wrapper>
</Tooltip>
);
};

Expand Down
2 changes: 1 addition & 1 deletion frontend/webapp/reuseable-components/tab-list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const TabListContainer = styled.div`
// Tab component
const Tab: React.FC<TabProps> = ({ title, tooltip, icon, selected, disabled, onClick }) => {
return (
<Tooltip text={tooltip || ''}>
<Tooltip text={tooltip}>
<TabContainer $selected={selected} $disabled={disabled} onClick={onClick}>
<Image src={icon} width={14} height={14} alt={title} />
<Text size={14}>{title}</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const ToggleButtons: React.FC<ToggleProps> = ({ activeText = 'Active', inactiveT
};

return (
<Tooltip text={tooltip || ''}>
<Tooltip text={tooltip}>
<Container>
<ActiveButton className={isActive ? 'colored' : ''} onClick={() => handleToggle(true)} disabled={disabled}>
<Image src='/icons/common/circled-check.svg' alt='' width={16} height={16} />
Expand All @@ -88,8 +88,6 @@ const ToggleButtons: React.FC<ToggleProps> = ({ activeText = 'Active', inactiveT
{inactiveText}
</InactiveButton>
</Container>

{tooltip && <Image src='/icons/common/info.svg' alt='' width={16} height={16} style={{ margin: '0 8px' }} />}
</Tooltip>
);
};
Expand Down
12 changes: 5 additions & 7 deletions frontend/webapp/reuseable-components/toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,12 @@ const Toggle: React.FC<ToggleProps> = ({ title, tooltip, initialValue = false, o
};

return (
<Tooltip text={tooltip || ''}>
<Container $disabled={disabled} onClick={handleToggle}>
<ToggleSwitch $disabled={disabled} $isActive={isActive} />
<Container $disabled={disabled} onClick={handleToggle}>
<ToggleSwitch $disabled={disabled} $isActive={isActive} />
<Tooltip text={tooltip} withIcon>
<Text size={14}>{title}</Text>
</Container>

{tooltip && <Image src='/icons/common/info.svg' alt='' width={16} height={16} />}
</Tooltip>
</Tooltip>
</Container>
);
};

Expand Down
104 changes: 51 additions & 53 deletions frontend/webapp/reuseable-components/tooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,71 @@
import React, { useState, useRef, ReactNode, useEffect } from 'react';
import { Text } from '../text';
import React, { useState, PropsWithChildren } from 'react';
import Image from 'next/image';
import ReactDOM from 'react-dom';
import { Text } from '../text';
import styled from 'styled-components';

interface TooltipProps {
text: ReactNode;
children: ReactNode;
interface Position {
top: number;
left: number;
}

const TooltipWrapper = styled.div`
display: flex;
interface TooltipProps extends PropsWithChildren {
text?: string;
withIcon?: boolean;
}

interface PopupProps extends PropsWithChildren, Position {}

const TooltipContainer = styled.div`
position: relative;
display: flex;
align-items: center;
gap: 4px;
`;

const TooltipContent = styled.div<{ $top: number; $left: number }>`
position: absolute;
top: ${({ $top }) => $top}px;
left: ${({ $left }) => $left}px;
border-radius: 32px;
background-color: ${({ theme }) => theme.colors.dark_grey};
border: 1px solid ${({ theme }) => theme.colors.border};
color: ${({ theme }) => theme.text.primary};
padding: 16px;
z-index: 9999;
pointer-events: none;
max-width: 300px;
`;

const Tooltip: React.FC<TooltipProps> = ({ text, children }) => {
export const Tooltip: React.FC<TooltipProps> = ({ text, withIcon, children }) => {
const [isHovered, setIsHovered] = useState(false);
const [position, setPosition] = useState({ top: 0, left: 0 });
const wrapperRef = useRef<HTMLDivElement | null>(null);

useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (wrapperRef.current) {
const { top, left } = wrapperRef.current.getBoundingClientRect();
const [popupPosition, setPopupPosition] = useState<Position>({ top: 0, left: 0 });

setPosition({
top: top + window.scrollY,
left: left + window.scrollX,
});
}
};
const handleMouseEvent = (e: React.MouseEvent) => {
const { type, clientX, clientY } = e;

if (isHovered) {
document.addEventListener('mousemove', handleMouseMove);
} else {
document.removeEventListener('mousemove', handleMouseMove);
}

return () => document.removeEventListener('mousemove', handleMouseMove);
}, [isHovered]);
setIsHovered(type !== 'mouseleave');
setPopupPosition({ top: clientY, left: clientX + 24 });
};

if (!text) return <>{children}</>;

const tooltipContent = (
<TooltipContent $top={position.top} $left={position.left}>
<Text size={14}>{text}</Text>
</TooltipContent>
);

return (
<TooltipWrapper ref={wrapperRef} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
<TooltipContainer onMouseEnter={handleMouseEvent} onMouseMove={handleMouseEvent} onMouseLeave={handleMouseEvent}>
{children}
{isHovered && ReactDOM.createPortal(tooltipContent, document.body)}
</TooltipWrapper>
{withIcon && <Image src='/icons/common/info.svg' alt='info' width={16} height={16} />}
{isHovered && <Popup {...popupPosition}>{text}</Popup>}
</TooltipContainer>
);
};

export { Tooltip };
const PopupContainer = styled.div<{ $top: number; $left: number }>`
position: absolute;
top: ${({ $top }) => $top}px;
left: ${({ $left }) => $left}px;
z-index: 9999;
max-width: 270px;
padding: 8px 12px;
border-radius: 16px;
border: 1px solid ${({ theme }) => theme.colors.white_opacity['008']};
background-color: ${({ theme }) => theme.colors.info};
color: ${({ theme }) => theme.text.primary};
pointer-events: none;
`;

const Popup: React.FC<PopupProps> = ({ top, left, children }) => {
return ReactDOM.createPortal(
<PopupContainer $top={top} $left={left}>
<Text size={12}>{children}</Text>
</PopupContainer>,
document.body,
);
};

0 comments on commit 6cda9b3

Please sign in to comment.