@ -7,26 +7,29 @@ import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes' ;
import { getFocusStyles } from '../../themes/mixins' ;
import { IconName } from '../../types' ;
import { clearButtonStyles } from '../Button' ;
import { Icon } from '../Icon/Icon' ;
import { Counter } from './Counter' ;
export interface TabProps extends HTMLProps < HTMLAnchor Element > {
export interface TabProps extends HTMLProps < HTMLElement > {
label : string ;
active? : boolean ;
/** When provided, it is possible to use the tab as a hyperlink. Use in cases where the tabs update location. */
href? : string ;
icon? : IconName ;
onChangeTab ? : ( event? : React.MouseEvent < HTMLAnchor Element > ) = > void ;
onChangeTab ? : ( event : React.MouseEvent < HTMLElement > ) = > void ;
/** A number rendered next to the text. Usually used to display the number of items in a tab's view. */
counter? : number | null ;
/** Extra content, displayed after the tab label and counter */
suffix? : NavModelItem [ 'tabSuffix' ] ;
}
export const Tab = React . forwardRef < HTMLAnchor Element , TabProps > (
export const Tab = React . forwardRef < HTMLElement , TabProps > (
( { label , active , icon , onChangeTab , counter , suffix : Suffix , className , href , . . . otherProps } , ref ) = > {
const tabsStyles = useStyles2 ( getStyles ) ;
const clearStyles = useStyles2 ( clearButtonStyles ) ;
const content = ( ) = > (
< >
{ icon && < Icon name = { icon } / > }
@ -36,23 +39,44 @@ export const Tab = React.forwardRef<HTMLAnchorElement, TabProps>(
< / >
) ;
const linkClass = cx ( tabsStyles . link , active ? tabsStyles.activeStyle : tabsStyles.notActive ) ;
const linkClass = cx ( clearStyles , tabsStyles . link , active ? tabsStyles.activeStyle : tabsStyles.notActive ) ;
const commonProps = {
className : linkClass ,
. . . otherProps ,
onClick : onChangeTab ,
'aria-label' : otherProps [ 'aria-label' ] || selectors . components . Tab . title ( label ) ,
role : 'tab' ,
'aria-selected' : active ,
} ;
if ( href ) {
return (
< div className = { tabsStyles . item } >
< a
{ . . . commonProps }
href = { href }
// don't think we can avoid the type assertion here :(
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
ref = { ref as React . ForwardedRef < HTMLAnchorElement > }
>
{ content ( ) }
< / a >
< / div >
) ;
}
return (
< div className = { tabsStyles . item } >
< a
// in case there is no href '#' is set in order to maintain a11y
href = { href ? href : '#' }
className = { linkClass }
{ . . . otherProps }
onClick = { onChangeTab }
aria - label = { otherProps [ 'aria-label' ] || selectors . components . Tab . title ( label ) }
role = "tab"
aria - selected = { active }
ref = { ref }
< button
{ . . . commonProps }
type = "button"
// don't think we can avoid the type assertion here :(
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
ref = { ref as React . ForwardedRef < HTMLButtonElement > }
>
{ content ( ) }
< / a >
< / button >
< / div >
) ;
}
@ -108,10 +132,6 @@ const getStyles = (theme: GrafanaTheme2) => {
color : theme.colors.text.primary ,
overflow : 'hidden' ,
a : {
color : theme.colors.text.primary ,
} ,
'&::before' : {
backgroundImage : theme.colors.gradients.brandHorizontal ,
} ,