Skip to content

Commit

Permalink
Merge pull request #83 from KasperskyLab/fix/tabs-more-button-with-ex…
Browse files Browse the repository at this point in the history
…tra-content

fix: fix hiding tabs with extra content
  • Loading branch information
gitpoeble authored Aug 13, 2024
2 parents 90d7dc9 + 6876328 commit a71270f
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 31 deletions.
72 changes: 55 additions & 17 deletions packages/kaspersky-components/src/tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Tabs as AntdTabs } from 'antd'
import cn from 'classnames'
import React, {
ReactElement,
ReactNode,
FC,
Children,
isValidElement,
Expand All @@ -31,6 +32,7 @@ import {
tabPaneHeadCss,
StyledTabPaneIcon,
StyledTabPaneText,
StyledExtraContent,
StyledTabPaneIndicator
} from './tabsCss'
import { TabsDropdown } from './TabsDropdown'
Expand All @@ -43,11 +45,14 @@ import {
TabPaneHeaderProps,
GroupTabsProps,
TabsVariants,
ComplexTabBarExtraContent,
StyledTabPanedHeadProps
} from './types'
import { useThemedTabs } from './useThemedTabs'
import { createGroupTabPane, extractTabPanes } from './utils'

export const TABS_GAP = 4

const StyledTabs = styled(AntdTabs).withConfig<TabsViewProps & { hiddenTabsLength: number }>({
shouldForwardProp: (prop) => !['cssConfig', 'hiddenTabsLength', 'containerWidth'].includes(prop as string)
})`
Expand Down Expand Up @@ -121,21 +126,23 @@ export const GroupTabHeader: FC<TabPaneHeaderProps> = (props: TabPaneHeaderProps
GroupTabs.TabPaneHeader = GroupTabHeader

const TabViewComponent: FC<TabsViewProps> & Omit<TabsVariants, 'TabPaneHead'> = ({
cssConfig,
tabPosition = 'top',
type = 'line',
destroyInactiveTabPane = false,
children,
activeKey,
defaultActiveKey,
onChange,
testId,
testAttributes,
className,
rootHashClass,
...props
}: TabsViewProps) => {
cssConfig,
tabPosition = 'top',
type = 'line',
destroyInactiveTabPane = false,
children,
activeKey,
defaultActiveKey,
onChange,
testId,
testAttributes,
className,
tabBarExtraContent,
rootHashClass,
...props
}: TabsViewProps) => {
const tabsRef = useRef<HTMLDivElement>(null)
const extraContentRef = useRef<HTMLDivElement>(null)
const activeTab = activeKey ?? defaultActiveKey ?? (children as ReactElement[])[0]?.key ?? ''
const [activeTabKey, setActiveTabKey] = useState(activeTab)
const [buttonMoreSize, setButtonMoreSize] = useState(0)
Expand All @@ -155,17 +162,24 @@ const TabViewComponent: FC<TabsViewProps> & Omit<TabsVariants, 'TabPaneHead'> =
}, [children]
)

let extraContentWidthWithGap = 0
if (extraContentRef.current) {
extraContentWidthWithGap = extraContentRef.current.clientWidth + TABS_GAP
}

let lastFittingItemIndex = useIntersectionChildren(
tabsRef,
buttonMoreSize,
buttonMoreSize + extraContentWidthWithGap,
'.ant-tabs-nav-list',
recalculateIntersectionCounter
) ?? existingTabs.length

if (tabsRef.current) {
const tabs = tabsRef.current.querySelectorAll('.ant-tabs-tab')
const extraContentLeft = tabsRef.current.querySelector('.ant-tabs-extra-content')
const extraContentLeftWidth = extraContentLeft ? (extraContentLeft.clientWidth + TABS_GAP) : 0
const lastTab = tabs[tabs.length - 1]
if (lastTab && ((lastTab as HTMLElement).offsetLeft + lastTab.clientWidth < containerWidth)) {
if (lastTab && ((lastTab as HTMLElement).offsetLeft + lastTab.clientWidth + extraContentWidthWithGap + extraContentLeftWidth < containerWidth)) {
lastFittingItemIndex = existingTabs.length
}
}
Expand Down Expand Up @@ -218,13 +232,33 @@ const TabViewComponent: FC<TabsViewProps> & Omit<TabsVariants, 'TabPaneHead'> =
}
}, [])

const tabBarExtraContentLeft: ComplexTabBarExtraContent = { left: undefined }
let tabBarExtraContentRight: ReactNode
if (tabBarExtraContent) {
if (typeof tabBarExtraContent === 'object') {
if ('left' in tabBarExtraContent || 'right' in tabBarExtraContent) {
if ('left' in tabBarExtraContent) {
tabBarExtraContentLeft.left = tabBarExtraContent.left
}
if ('right' in tabBarExtraContent) {
tabBarExtraContentRight = tabBarExtraContent.right
}
} else {
tabBarExtraContentRight = tabBarExtraContent
}
} else {
tabBarExtraContentRight = tabBarExtraContent
}
}

return (
<TabsContext.Provider value={{ cssConfig, testAttributes }}>
<StyledTabsWrapper
ref={tabsRef}
className={cn(className, rootHashClass)}
cssConfig={cssConfig}
selectedMoreButton={isMoreButtonActive}
extraContentWidth={extraContentWidthWithGap}
shouldShowMoreButton={shouldShowMoreButton}
>
<StyledTabs
Expand All @@ -233,14 +267,18 @@ const TabViewComponent: FC<TabsViewProps> & Omit<TabsVariants, 'TabPaneHead'> =
tabPosition={tabPosition}
destroyInactiveTabPane={destroyInactiveTabPane}
{...props}
tabBarExtraContent={tabBarExtraContentLeft}
activeKey={activeTabKey as string}
onChange={onTabChange}
hiddenTabsLength={existingTabs.length - (lastFittingItemIndex || existingTabs.length)}
hiddenTabsLength={existingTabs.length - (lastFittingItemIndex)}
containerWidth={containerWidth}
{...testAttributes}
>
{extractTabPanes(existingTabs)}
</StyledTabs>
<StyledExtraContent ref={extraContentRef} className={'extraContent'}>
{tabBarExtraContentRight}
</StyledExtraContent>
<TabsDropdown
activeKey={activeTabKey}
className={rootHashClass}
Expand Down
24 changes: 17 additions & 7 deletions packages/kaspersky-components/src/tabs/tabsCss.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import styled, { css } from 'styled-components'
import { SPACES } from '@design-system/theme'
import { getTextSizes, textLevels } from '@design-system/tokens'
import { getFromProps } from '@helpers/getFromProps'
import { Button } from '@src/button'
import { Divider } from '@src/divider'
import { Text } from '@src/typography'
import styled, { css } from 'styled-components'

import { TabsCssConfig } from './types'
import { getFromProps } from '@helpers/getFromProps'
import { SPACES } from '@design-system/theme'
import { getTextSizes, textLevels } from '@design-system/tokens'

export const StyledTabPaneIcon = styled.div``
export const StyledTabPaneText = styled.div``
export const StyledTabPaneIndicator = styled.div``
export const StyledDivider = styled(Divider)``
export const StyledText = styled(Text)``
export const StyledMoreButton = styled(Button)``
export const StyledExtraContent = styled.div``

const fromProps = getFromProps<TabsCssConfig>()

Expand Down Expand Up @@ -358,10 +360,12 @@ export const tabPaneHeadCss = css<{ cssConfig: TabsCssConfig }>`

export const tabsWrapperCss = css<{
cssConfig: TabsCssConfig,
extraContentWidth: number,
selectedMoreButton: boolean,
shouldShowMoreButton: boolean
}>`
width: 100%;
position: relative;
display: flex;
justify-content: space-between;
overflow: hidden;
Expand All @@ -372,13 +376,18 @@ export const tabsWrapperCss = css<{
`}
}
.kl6-tabs-more-button{
.ant-tabs-extra-content {
padding-right: 4px;
}
& ${StyledExtraContent} {
position: absolute;
right: 0px;
}
&& ${StyledMoreButton} {
& ${StyledMoreButton} {
position: absolute;
right: 24px;
right: ${props => (props.extraContentWidth) + 'px'};
color: ${fromProps('unSelected.enabled.color')};
${props => props.selectedMoreButton && `
color: ${fromProps('selected.enabled.color')(props)};
Expand All @@ -396,6 +405,7 @@ export const tabsWrapperCss = css<{
border-radius: 4px;
min-width: fit-content;
&::before {
display: none;
position: absolute;
Expand Down
16 changes: 9 additions & 7 deletions packages/kaspersky-components/src/tabs/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { Focus } from '@design-system/tokens/focus'
import { Theme } from '@design-system/types/Theme'
import { TestingProps, ToViewProps } from '@helpers/typesHelpers'
import { IndicatorMode } from '@src/indicator'
import { SpaceProps } from '@src/space'
import { TabPaneProps } from 'antd'
import {
PropsWithChildren,
ReactNode,
Expand All @@ -6,12 +12,6 @@ import {
CSSProperties,
FC
} from 'react'
import { IndicatorMode } from '@src/indicator'
import { SpaceProps } from '@src/space'
import { Theme } from '@design-system/types/Theme'
import { TestingProps, ToViewProps } from '@helpers/typesHelpers'
import { TabPaneProps } from 'antd'
import { Focus } from '@design-system/tokens/focus'

type StateProps = {
color?: string,
Expand Down Expand Up @@ -44,11 +44,13 @@ export type TabsVariants = {
TabPaneHead: FC<TabPaneHeadProps>
}

export type ComplexTabBarExtraContent = { right?: ReactNode, left?: ReactNode }

export type TabsProps = TabsThemeProps & PropsWithChildren<{
/** @deprecated Tabs type - card tabs are not supported */
type?: 'line' | 'card',
/** Extra content at left and right side of tabs. Intends should be set manually (until design review) */
tabBarExtraContent?: ReactNode | { right?: ReactNode, left?: ReactNode },
tabBarExtraContent?: ReactNode | ComplexTabBarExtraContent,
/** TabPane's className */
className?: string,
/** Tabs position */
Expand Down

0 comments on commit a71270f

Please sign in to comment.