Skip to content

Commit

Permalink
fix: scroll profiles issue and right arrow displaying (#1661)
Browse files Browse the repository at this point in the history
  • Loading branch information
AMIRKHANEF authored Nov 17, 2024
1 parent 37a614d commit bcf06ab
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface Props {
index: number;
}

export default function ProfileTabFullScreen ({ index, isHovered, orderedAccounts, selectedProfile, setSelectedProfile, text }: Props): React.ReactElement {
function ProfileTabFullScreen ({ index, isHovered, orderedAccounts, selectedProfile, setSelectedProfile, text }: Props): React.ReactElement {
const { t } = useTranslation();
const theme = useTheme();
const { alerts, notify } = useAlerts();
Expand Down Expand Up @@ -114,6 +114,7 @@ export default function ProfileTabFullScreen ({ index, isHovered, orderedAccount
cursor: 'pointer',
flexShrink: 0,
minWidth: '100px',
mr: '5px',
mt: '2px',
opacity: isDarkMode ? (visibleContent ? 1 : 0.3) : undefined,
position: 'relative',
Expand Down Expand Up @@ -151,3 +152,5 @@ export default function ProfileTabFullScreen ({ index, isHovered, orderedAccount
</Infotip2>
);
}

export default React.memo(ProfileTabFullScreen);
Original file line number Diff line number Diff line change
Expand Up @@ -19,69 +19,136 @@ interface Props {

export const HIDDEN_PERCENT = '50%';

export default function ProfileTabsFullScreen ({ orderedAccounts }: Props): React.ReactElement {
function ProfileTabsFullScreen ({ orderedAccounts }: Props): React.ReactElement {
const { defaultProfiles, userDefinedProfiles } = useProfiles();

const [selectedProfile, setSelectedProfile] = useState<string>();
const [isHovered, setIsHovered] = useState<boolean>();

const [showLeftMore, setShowLeftMore] = useState(false);
const [showRightMore, setShowRightMore] = useState(true);
const [showRightMore, setShowRightMore] = useState(false);
const [isContentReady, setIsContentReady] = useState(false);

const scrollContainerRef = useRef<HTMLDivElement>(null);
const checkTimeoutRef = useRef<ReturnType<typeof setTimeout>>();

const profilesToShow = useMemo(() => {
if (defaultProfiles.length === 0 && userDefinedProfiles.length === 0) {
return [];
}

return defaultProfiles.concat(userDefinedProfiles);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultProfiles.length, userDefinedProfiles.length]);
}, [defaultProfiles, userDefinedProfiles]);

const onMouseEnter = useCallback(() => setIsHovered(true), []);
const onMouseLeave = useCallback(() => setIsHovered(false), []);

const handleScroll = () => {
if (scrollContainerRef.current) {
const { clientWidth, scrollLeft, scrollWidth } = scrollContainerRef.current;
const handleScroll = useCallback(() => {
const container = scrollContainerRef.current;

if (container && isContentReady) {
let { clientWidth, scrollLeft, scrollWidth } = container;

scrollLeft = Math.round(scrollLeft);

// Check if content is actually scrollable
const isScrollable = scrollWidth > clientWidth;
const tolerance = 10;

setShowLeftMore(scrollLeft > 0);
setShowRightMore(scrollLeft + clientWidth < scrollWidth - tolerance && isScrollable);
// Show left arrow if we've scrolled at least 1px
setShowLeftMore(scrollLeft > 1);

// Show right arrow if there's more content to scroll to
// We add a small buffer (1px) to account for rounding errors
const remainingScroll = scrollWidth - (scrollLeft + clientWidth);

setShowRightMore(isScrollable && remainingScroll > 1);
}
};
}, [isContentReady]);

const handleWheel = useCallback((event: WheelEvent) => {
if (scrollContainerRef.current) {
event.preventDefault();
scrollContainerRef.current.scrollLeft += (event.deltaY || event.deltaX);

// Make the scroll amount more controlled
const scrollAmount = event.deltaY || event.deltaX;
const normalizedScroll = Math.sign(scrollAmount) * Math.min(Math.abs(scrollAmount), 50);

scrollContainerRef.current.scrollLeft += normalizedScroll;
handleScroll();
}
}, []);
}, [handleScroll]);

// Initial setup and content ready check
useEffect(() => {
handleScroll(); // Set initial shadow states on mount
const ref = scrollContainerRef.current;
const container = scrollContainerRef.current;

if (container) {
// Clear any existing timeout
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current);
}

// Function to check if content is stable
const checkContentStability = () => {
const { clientWidth, scrollWidth } = container;

if (scrollWidth && clientWidth) {
setIsContentReady(true);
handleScroll();
} else {
// If content isn't ready, check again in a moment
checkTimeoutRef.current = setTimeout(checkContentStability, 50);
}
};

if (ref) {
ref.addEventListener('scroll', handleScroll);
ref.addEventListener('wheel', handleWheel, { passive: false });
// Start checking content stability
checkContentStability();

return () => {
ref.removeEventListener('scroll', handleScroll);
ref.removeEventListener('wheel', handleWheel);
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current);
}
};
}

return undefined;
}, [handleWheel, profilesToShow.length]);
}, [handleScroll, profilesToShow]);

// Scroll and resize handlers
useEffect(() => {
const container = scrollContainerRef.current;

if (container && isContentReady) {
// Add scroll event listener
const scrollListener = () => {
requestAnimationFrame(handleScroll);
};

container.addEventListener('scroll', scrollListener);
container.addEventListener('wheel', handleWheel, { passive: false });

// Check on resize
const resizeObserver = new ResizeObserver(() => {
requestAnimationFrame(handleScroll);
});

resizeObserver.observe(container);

return () => {
container.removeEventListener('scroll', scrollListener);
container.removeEventListener('wheel', handleWheel);
resizeObserver.disconnect();
};
}

return undefined;
}, [handleScroll, handleWheel, isContentReady]);

return (
<Grid container sx={{ display: 'flex', height: '30px', mb: '10px', position: 'relative' }}>
{showLeftMore && <ArrowForwardIosRoundedIcon sx={{ color: 'text.disabled', fontSize: '20px', transform: 'rotate(-180deg)', width: 'fit-content', zIndex: 1 }} />}
<Grid columnGap='5px' container item
{isHovered && isContentReady && showLeftMore && <ArrowForwardIosRoundedIcon sx={{ color: 'text.disabled', fontSize: '20px', transform: 'rotate(-180deg)', width: 'fit-content', zIndex: 1 }} />}
<Grid container display='ruby'
item
justifyContent='left'
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
Expand Down Expand Up @@ -110,7 +177,9 @@ export default function ProfileTabsFullScreen ({ orderedAccounts }: Props): Reac
))
}
</Grid>
{showRightMore && <ArrowForwardIosRoundedIcon sx={{ color: 'text.disabled', fontSize: '20px', width: 'fit-content', zIndex: 1 }} />}
{isHovered && isContentReady && showRightMore && <ArrowForwardIosRoundedIcon sx={{ color: 'text.disabled', fontSize: '20px', width: 'fit-content', zIndex: 1 }} />}
</Grid>
);
}

export default React.memo(ProfileTabsFullScreen);

0 comments on commit bcf06ab

Please sign in to comment.