From c2c140407e3323ebdffef431d93e041de2665e9e Mon Sep 17 00:00:00 2001 From: devformatters2 <177856586+devformatters2@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:28:20 +0800 Subject: [PATCH] fix(tabs): add gradient visibility logic to handle tab overflow scenarios --- src/components/SquareTabs/index.tsx | 52 +++++++++++++++++++-- src/components/SquareTabs/styles.module.css | 42 +++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/components/SquareTabs/index.tsx b/src/components/SquareTabs/index.tsx index b47b2b9126..7e775d5ec0 100644 --- a/src/components/SquareTabs/index.tsx +++ b/src/components/SquareTabs/index.tsx @@ -1,4 +1,5 @@ import classNames from 'classnames' +import { useEffect, useRef, useState } from 'react' import styles from './styles.module.css' @@ -34,15 +35,60 @@ interface SquareTabsProps { export const SquareTabs: React.FC> & { Tab: typeof Tab } = ({ children, sticky }) => { + const navRef = useRef(null) + const containerRef = useRef(null) + const $nav = navRef.current + const $container = containerRef.current + const [showLeftGradient, setShowLeftGradient] = useState(false) + const [showRightGradient, setShowRightGradient] = useState(false) + + const isTabsOverflowing = () => { + if (!$nav || !$container) return false + return $nav.scrollWidth > $container.clientWidth + } + + const calculateGradient = () => { + if (!$nav || !$container) return + + const isAtLeftMost = $nav.scrollLeft <= 0 + const isAtRightMost = $nav.scrollLeft + $nav.clientWidth >= $nav.scrollWidth + + setShowLeftGradient(!isAtLeftMost) + setShowRightGradient(!isAtRightMost) + } + + useEffect(() => { + if (!isTabsOverflowing() || !$nav) return + + // initial gradient + calculateGradient() + + $nav.addEventListener('scroll', calculateGradient) + + return () => { + if (!$nav) return + + $nav.removeEventListener('scroll', calculateGradient) + } + }, [$nav]) + + const containerClasses = classNames({ + [styles.container]: true, + [styles.showLeftGradient]: showLeftGradient, + [styles.showRightGradient]: showRightGradient, + }) + const navClasses = classNames({ [styles.tabList]: true, [styles.sticky]: sticky, }) return ( -
    - {children} -
+
+
    + {children} +
+
) } diff --git a/src/components/SquareTabs/styles.module.css b/src/components/SquareTabs/styles.module.css index c98570d7b3..ec2c2a4078 100644 --- a/src/components/SquareTabs/styles.module.css +++ b/src/components/SquareTabs/styles.module.css @@ -1,3 +1,45 @@ +.container { + position: relative; + + &::before, + &::after { + position: absolute; + top: 0; + bottom: 0; + z-index: calc(var(--z-index-sticky-tabs) + 1); + width: 7.5rem; + pointer-events: none; + content: ''; + opacity: 0; /* Initially hidden */ + transition: opacity 0.3s; + } + + &.showLeftGradient::before, + &.showRightGradient::after { + opacity: 1; /* Show when scrollable */ + } + + &::before { + left: 0; + background: linear-gradient( + -90deg, + rgb(255 255 255 / 0%) 0%, + rgb(255 255 255 / 30%) 20%, + #fff 100% + ); + } + + &::after { + right: 0; + background: linear-gradient( + 90deg, + rgb(255 255 255 / 0%) 0%, + rgb(255 255 255 / 30%) 20%, + #fff 100% + ); + } +} + .tabList { @mixin hide-scrollbar;