diff --git a/packages/libs/react-ui/src/components/Tabs/Tabs.css.ts b/packages/libs/react-ui/src/components/Tabs/Tabs.css.ts index ffc59ad3257..173ed832311 100644 --- a/packages/libs/react-ui/src/components/Tabs/Tabs.css.ts +++ b/packages/libs/react-ui/src/components/Tabs/Tabs.css.ts @@ -69,27 +69,13 @@ export const tabListClass = style([ }, ]); -export const selectorLine = style([ - atoms({ - position: 'absolute', - bottom: 0, - borderStyle: 'solid', - }), - { - width: 0, - height: 0, - zIndex: 4, - borderWidth: 0, - borderBottomWidth: token('border.width.normal'), - borderColor: token('color.border.tint.@focus'), - transition: 'transform .4s ease, width .4s ease', - transform: `translateX(0)`, - }, -]); +// Prevent button from increasing the tab size and having the outline conflict with label +globalStyle(`${tabListClass} button`, { + paddingBlock: 0, +}); -// To prevent overlapping with the focus ring, we hide the line when the tab is focused -globalStyle(`${tabListClass}.focusVisible ${selectorLine}`, { - opacity: 0, +globalStyle(`${tabListClass} span`, { + paddingInline: 0, }); export const tabItemClass = recipe({ @@ -167,6 +153,9 @@ export const tabItemClass = recipe({ }, bottom: { selectors: { + '&[data-selected="true"]': { + borderBottom: `2px solid ${token('color.border.tint.@focus')}`, + }, '&[data-hovered="true"]:not(&[data-selected="true"])': { borderBottom: `2px solid ${token('color.border.tint.outline')}`, }, diff --git a/packages/libs/react-ui/src/components/Tabs/Tabs.tsx b/packages/libs/react-ui/src/components/Tabs/Tabs.tsx index d8fd1677761..7bd41a0d2c3 100644 --- a/packages/libs/react-ui/src/components/Tabs/Tabs.tsx +++ b/packages/libs/react-ui/src/components/Tabs/Tabs.tsx @@ -1,24 +1,19 @@ 'use client'; import classNames from 'classnames'; -import type { ReactNode } from 'react'; -import React, { useEffect, useLayoutEffect, useRef } from 'react'; +import type { ComponentProps, ReactNode } from 'react'; +import React, { useEffect, useRef } from 'react'; import type { AriaTabListProps } from 'react-aria'; import { mergeProps, useFocusRing, useTabList } from 'react-aria'; import type { Node } from 'react-stately'; import { Item as TabItem, useTabListState } from 'react-stately'; import { Tab } from './Tab'; import { TabPanel } from './TabPanel'; -import { - scrollContainer, - selectorLine, - tabListClass, - tabsContainerClass, -} from './Tabs.css'; +import { scrollContainer, tabListClass, tabsContainerClass } from './Tabs.css'; import { TabsPagination } from './TabsPagination'; export { TabItem }; -export type ITabItemProps = React.ComponentProps; +export type ITabItemProps = ComponentProps; export interface ITabsProps extends Omit, 'orientation' | 'items'> { @@ -40,7 +35,6 @@ export const Tabs = ({ const state = useTabListState(props); const containerRef = useRef(null); const scrollRef = useRef(null); - const selectedUnderlineRef = useRef(null); const { focusProps, isFocusVisible } = useFocusRing({ within: true, @@ -52,22 +46,18 @@ export const Tabs = ({ containerRef, ); - const getSelectedTab = () => { + // set Selected as first tab if the tab isn't visible + useEffect(() => { let selected = containerRef.current?.querySelector( '[data-selected="true"]', - ); + ) as HTMLElement | undefined; if (selected === undefined || selected === null) { - selected = containerRef.current?.querySelectorAll('div[role="tab"]')[0]; + selected = containerRef.current?.querySelectorAll( + 'div[role="tab"]', + )[0] as HTMLElement; } - return selected as HTMLElement | undefined; - }; - - // set Selected as first tab if the tab isn't visible - useEffect(() => { - let selected = getSelectedTab(); - if ( selected && scrollRef.current && @@ -78,29 +68,6 @@ export const Tabs = ({ } }, []); - // handle underline animation - useLayoutEffect(() => { - if (!containerRef.current || !selectedUnderlineRef.current) { - return; - } - - const selected = getSelectedTab(); - - if (!selected) { - return; - } - - selectedUnderlineRef.current.style.setProperty( - 'transform', - `translateX(${selected.offsetLeft}px)`, - ); - - selectedUnderlineRef.current.style.setProperty( - 'width', - `${selected.getBoundingClientRect().width}px`, - ); - }, [state.selectedItem?.key]); - return (
))} - {borderPosition === 'bottom' && ( - - )}