UNPKG

@grafana/ui

Version:
1 lines 8.7 kB
{"version":3,"file":"Tab.mjs","sources":["../../../../src/components/Tabs/Tab.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { HTMLProps } from 'react';\nimport * as React from 'react';\n\nimport { GrafanaTheme2, NavModelItem } from '@grafana/data';\nimport { selectors } from '@grafana/e2e-selectors';\n\nimport { useStyles2 } from '../../themes/ThemeContext';\nimport { getFocusStyles } from '../../themes/mixins';\nimport { IconName } from '../../types/icon';\nimport { clearButtonStyles } from '../Button/Button';\nimport { Icon } from '../Icon/Icon';\nimport { Tooltip } from '../Tooltip/Tooltip';\n\nimport { Counter } from './Counter';\n\nexport interface TabProps extends HTMLProps<HTMLElement> {\n label: string;\n active?: boolean;\n /** When provided, it is possible to use the tab as a hyperlink. Use in cases where the tabs update location. */\n href?: string;\n icon?: IconName;\n onChangeTab?: (event: React.MouseEvent<HTMLElement>) => void;\n /** A number rendered next to the text. Usually used to display the number of items in a tab's view. */\n counter?: number | null;\n /** Extra content, displayed after the tab label and counter */\n suffix?: NavModelItem['tabSuffix'];\n truncate?: boolean;\n tooltip?: string;\n}\n\nexport const Tab = React.forwardRef<HTMLElement, TabProps>(\n (\n { label, active, icon, onChangeTab, counter, suffix: Suffix, className, href, truncate, tooltip, ...otherProps },\n ref\n ) => {\n const tabsStyles = useStyles2(getStyles);\n const clearStyles = useStyles2(clearButtonStyles);\n\n const content = () => (\n <>\n {icon && <Icon name={icon} data-testid={`tab-icon-${icon}`} />}\n {label}\n {typeof counter === 'number' && <Counter value={counter} />}\n {Suffix && <Suffix className={tabsStyles.suffix} />}\n </>\n );\n\n const linkClass = cx(\n clearStyles,\n tabsStyles.link,\n active ? tabsStyles.activeStyle : tabsStyles.notActive,\n truncate && tabsStyles.linkTruncate\n );\n\n const commonProps = {\n className: linkClass,\n 'data-testid': selectors.components.Tab.title(label),\n ...otherProps,\n onClick: onChangeTab,\n role: 'tab',\n 'aria-selected': active,\n title: !!tooltip ? undefined : otherProps.title, // If tooltip is provided, don't set the title on the link or button, it looks weird\n };\n\n let tab = null;\n\n if (href) {\n tab = (\n <div className={cx(tabsStyles.item, truncate && tabsStyles.itemTruncate, className)}>\n <a\n {...commonProps}\n href={href}\n // don't think we can avoid the type assertion here :(\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n ref={ref as React.ForwardedRef<HTMLAnchorElement>}\n >\n {content()}\n </a>\n </div>\n );\n } else {\n tab = (\n <div className={cx(tabsStyles.item, truncate && tabsStyles.itemTruncate, className)}>\n <button\n {...commonProps}\n type=\"button\"\n // don't think we can avoid the type assertion here :(\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n ref={ref as React.ForwardedRef<HTMLButtonElement>}\n >\n {content()}\n </button>\n </div>\n );\n }\n\n if (tooltip) {\n return <Tooltip content={tooltip}>{tab}</Tooltip>;\n }\n\n return tab;\n }\n);\n\nTab.displayName = 'Tab';\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n item: css({\n listStyle: 'none',\n position: 'relative',\n display: 'flex',\n whiteSpace: 'nowrap',\n padding: theme.spacing(0, 0.5),\n }),\n itemTruncate: css({\n maxWidth: theme.spacing(40),\n }),\n link: css({\n color: theme.colors.text.secondary,\n padding: theme.spacing(1, 1.5, 1),\n borderRadius: theme.shape.radius.default,\n\n display: 'block',\n height: '100%',\n\n svg: {\n marginRight: theme.spacing(1),\n },\n\n '&:focus-visible': getFocusStyles(theme),\n\n '&::before': {\n display: 'block',\n content: '\" \"',\n position: 'absolute',\n left: 0,\n right: 0,\n height: '2px',\n borderRadius: theme.shape.radius.default,\n bottom: 0,\n },\n }),\n linkTruncate: css({\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n wordBreak: 'break-word',\n overflow: 'hidden',\n }),\n notActive: css({\n 'a:hover, &:hover, &:focus': {\n color: theme.colors.text.primary,\n\n '&::before': {\n backgroundColor: theme.colors.action.hover,\n },\n },\n }),\n activeStyle: css({\n label: 'activeTabStyle',\n color: theme.colors.text.primary,\n overflow: 'hidden',\n\n '&::before': {\n backgroundImage: theme.colors.gradients.brandHorizontal,\n },\n }),\n suffix: css({\n marginLeft: theme.spacing(1),\n }),\n };\n};\n"],"names":[],"mappings":"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"}